[net.lang.c] variable # of args portability?

faustus@ucbcad.BERKELEY.EDU (Wayne A. Christopher) (07/08/86)

I want to be able to write a function that will take an unknown number
of arguments and then call another such function with these arguments,
namely something like printf() that calls _doprnt() without processing
its arguments at all.  I know there is no way to write this code portably,
but is it reasonable to assume that I will be able to do it at all in
most common implementations of C?  Also, how safe is it to assume that there
will be something like _doprnt() available?  I know it's not good to depend on
things like this, but I don't want to have to write my own printf()...

	Wayne

gwyn@BRL.ARPA (VLD/VMB) (07/08/86)

Most UNIX and some other C implementations have a <varargs.h>
header file that defines macros for getting at variably-sized
argument lists; unfortunately this is not sufficient for an
interface to a printf-like routine, where you need to pass
the remaining argument list along.  Many UNIX and some other C
implementations provide v*printf functions that are useful
in such situations.  There is normally some function like
_doprnt in the C library, but it may go by another name and
have slightly different arguments.

For the time being, people usually either invoke *printf using
functions with fixed arguments (perhaps several of them to
cover all necessary cases) or provide an interface that must
be adapted by each site.  Other commonly-used approaches tend
to be non-portable.

hansen@mips.UUCP (07/09/86)

> I want to be able to write a function that will take an unknown number
> of arguments and then call another such function with these arguments,
> namely something like printf() that calls _doprnt() without processing
> its arguments at all.  I know there is no way to write this code portably,
> but is it reasonable to assume that I will be able to do it at all in
> most common implementations of C?  Also, how safe is it to assume that there
> will be something like _doprnt() available?  I know it's not good to depend on
> things like this, but I don't want to have to write my own printf()...
> 
> 	Wayne

System V defines functions named vprintf, vfprintf, and vsprintf,
that combined with the macros defined in varargs.h, provide a
reasonably portable interface to _doprnt.  The first two
functions are trivial to implement on a machine that has _doprnt,
the third is a little tricker, since you must trick the stdio package
into outputting into a string, and the necessary flag setting
is rather unportable (which is why the v...printf functions should
be defined in the system-provided library).

Using varargs.h goes a long way toward making such functions portable.

-- 

Craig Hansen			|	 "Evahthun' tastes
MIPS Computer Systems		|	 bettah when it
...decwrl!mips!hansen		|	 sits on a RISC"

meissner@dg_rtp.UUCP (Michael Meissner) (07/09/86)

In article <809@ucbcad.BERKELEY.EDU> faustus@ucbcad.UUCP writes:
>
> I want to be able to write a function that will take an unknown number
> of arguments and then call another such function with these arguments,
> namely something like printf() that calls _doprnt() without processing
> its arguments at all.  I know there is no way to write this code portably,
> but is it reasonable to assume that I will be able to do it at all in
> most common implementations of C?  Also, how safe is it to assume that there
> will be something like _doprnt() available?  I know it's not good to depend on
> things like this, but I don't want to have to write my own printf()...
> 
> 	Wayne

    In the forthcoming ANSI X3J11 standard, as well as System V, are the
functions vprintf, vfprintf, and vsprintf.  Instead of taking the argument
list directly, the take the varargs pointer.  Thus the calling sequence looks
like (in the ANSI declarative style):

	int vprintf( const char *fmt, va_list varargs_ptr );
	int vfprintf( FILE *stream, const char *fmt, va_list varargs_ptr );
	int vsprintf( char *buffer, const char *fmt, va_list varargs_ptr );

    For systems that do not have vprintf and friends yet, you could write
the vprintf, et. al, in a few lines of code calling _doprnt.  This would
have to be tailored for each system.

	Michael Meissner, Data General
	...{ decvax, ucbvax, ihnp4 }!mcnc!rti-sel!dg_rtp!meissner

chris@umcp-cs.UUCP (Chris Torek) (07/10/86)

In article <434@dg_rtp.UUCP> meissner@dg_rtp.UUCP (Michael Meissner) writes:
> In the forthcoming ANSI X3J11 standard, as well as System V, are the
>functions vprintf, vfprintf, and vsprintf.  Instead of taking the argument
>list directly, the take the varargs pointer.  Thus the calling sequence looks
>like (in the ANSI declarative style):
>
>	int vprintf( const char *fmt, va_list varargs_ptr );
>	int vfprintf( FILE *stream, const char *fmt, va_list varargs_ptr );
>	int vsprintf( char *buffer, const char *fmt, va_list varargs_ptr );

Since none of 4.[123]BSD Vax Unix have these, but they are trivial,
here is an (untested) implementation.  (Unfortunately, implementing
the proper return value is not so trivial, except for vsprintf.)

I believe this code will work on a Pyramid as well.

#include <stdio.h>

int
vprintf(fmt, args)
	char *fmt;
	va_list args;
{

	_doprnt(fmt, args, stdout);
	return (ferror(stdout) ? EOF : 0);
}

int
vfprintf(f, fmt, args)
	FILE *f;
	char *fmt;
	va_list args;
{

	_doprnt(fmt, args, f);
	return (ferror(f) ? EOF : 0);
}

int
vsprintf(s, fmt, args)
	char *s, *fmt;
	va_list args;
{
	FILE fakebuf;

	fakebuf._flag = _IOSTRG;	/* no _IOWRT: avoid stdio bug */
	fakebuf._ptr = s;
	fakebuf._cnt = 32767;
	_doprnt(fmt, args, &fakebuf);
	return (strlen(s));
}
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@mimsy.umd.edu