/************************************************************************
 *									*
 *	Copyright (c) 1988 Enhanced Software Technologies, Inc.		*
 *			   All Rights Reserved				*
 *									*
 *	This software and/or documentation is protected by U.S.		*
 *	Copyright Law (Title 17 United States Code).  Unauthorized	*
 *	reproduction and/or sales may result in imprisonment of up	*
 *	to 1 year and fines of up to $10,000 (17 USC 506).		*
 *	Copyright infringers may also be subject to civil liability.	*
 *									*
 ************************************************************************
 */


/*
 *  FILE
 *
 *	vargs.h    include file for environments without varargs.h
 *
 *  SCCS
 *
 *	@(#)vargs.h	12.8	11 Feb 1991
 *
 *  SYNOPSIS
 *
 *	#include "vargs.h"
 *
 *  DESCRIPTION
 *
 *	This file implements a varargs macro set for use in those
 *	environments where there is no system supplied varargs.  This
 *	generally works because systems which don't supply a varargs
 *	package are precisely those which don't strictly need a varargs
 *	package.  Using this one then allows us to minimize source
 *	code changes.  So in some sense, this is a "portable" varargs
 *	since it is only used for convenience, when it is not strictly
 *	needed.
 *
 */

/*
 *	These macros allow us to rebuild an argument list on the stack
 *	given only a va_list.  We can use these to fake a function like
 *	vfprintf, which gets a fixed number of arguments, the last of
 *	which is a va_list, by rebuilding a stack and calling the variable
 *	argument form fprintf.  Of course this only works when vfprintf
 *	is not available in the host environment, and thus is not available
 *	for fprintf to call (which would give us an infinite loop).
 *
 *	Note that ARGS_TYPE is a long, which lets us get several bytes
 *	at a time while also preventing lots of "possible pointer alignment
 *	problem" messages from lint.  The messages are valid, because this
 *	IS nonportable, but then we should only be using it in very
 *	nonrestrictive environments, and using the real varargs where it
 *	really counts.
 *
 */

#define ARG0 a0
#define ARG1 a1
#define ARG2 a2
#define ARG3 a3
#define ARG4 a4
#define ARG5 a5
#define ARG6 a6
#define ARG7 a7
#define ARG8 a8
#define ARG9 a9

#define ARGS_TYPE long
#define ARGS_LIST ARG0,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6,ARG7,ARG8,ARG9
#define ARGS_DCL auto ARGS_TYPE ARGS_LIST

/*
 *	A pointer of type "va_list" points to a section of memory
 *	containing an array of variable sized arguments of unknown
 *	number.  This pointer is initialized by the va_start
 *	macro to point to the first byte of the first argument.
 *	We can then use it to walk through the argument list by 
 *	incrementing it by the size of the argument being referenced.
 */

typedef char *va_list;

/*
 *	The first variable argument overlays va_alist, which is
 *	nothing more than a "handle" which allows us to get the
 *	address of the first argument on the stack.  Note that
 *	by definition, the va_dcl macro includes the terminating
 *	semicolon, which makes use of va_dcl in the source code
 *	appear to be missing a semicolon.
 */

#define va_dcl ARGS_TYPE va_alist;

/*
 *	The va_start macro takes a variable of type "va_list" and
 *	initializes it.  In our case, it initializes a local variable
 *	of type "pointer to char" to point to the first argument on
 *	the stack.
 */

#define va_start(list) list = (char *) &va_alist

/*
 *	The va_end macro is a null operation for our use.
 */

#define va_end(list)

/*
 *	The va_arg macro is the tricky one.  This one takes
 *	a va_list as the first argument, and a type as the second
 *	argument, and returns a value of the appropriate type
 *	while advancing the va_list to the following argument.
 *	For our case, we first increment the va_list arg by the
 *	size of the type being recovered, cast the result to 
 *	a pointer of the appropriate type, and then dereference
 *	that pointer as an array to get the previous arg (which
 *	is the one we wanted.
 */

#define va_arg(list,type) ((type *) (list += sizeof (type)))[-1]

