Xref: utzoo comp.unix.questions:6951 comp.unix.wizards:8371
Path: utzoo!mnetor!uunet!lll-winken!lll-tis!ames!ncar!oddjob!mimsy!chris
From: chris@mimsy.UUCP (Chris Torek)
Newsgroups: comp.unix.questions,comp.unix.wizards
Subject: Re: Guessing buffer size needed for sprintf beforehand
Message-ID: <11439@mimsy.UUCP>
Date: 11 May 88 05:17:14 GMT
References: <136@insyte.uucp> <11331@mimsy.UUCP> <13597@comp.vuw.ac.nz>
Organization: U of Maryland, Dept. of Computer Science, Coll. Pk., MD 20742
Lines: 67
Keywords: sprintf

>In article <11331@mimsy.UUCP> I wrote:
>>By the time you reach a routine that takes a `va_list' argument,
>>it is too late to scan the argument list twice....

In article <13597@comp.vuw.ac.nz> andrew@comp.vuw.ac.nz (Andrew Vignaux) writes:
>The `varargs' manual page says "Multiple traversals, each bracketed by
>va_start ...  va_end, are possible." so it is possible to rescan the
>argument list.  (or have I misinterpreted what you said?)

You have.  Watch:

	int prf(const char *fmt, ...) {
		va_list ap;
		int rv;
		va_start(ap, fmt);
		rv = __printf(stdout, fmt, ap);
		va_end(ap);
		return (rv);
	}

	int __printf(FILE *fp, const char *fmt, va_list ap) {
		...

Which function takes a va_list argument?  Which one has the
va_start/va_end pair?  You *could* do this:

	int prf(const char *fmt, ...) {
		...
		va_start(ap, fmt);
		_first_fn(fmt, ap);
		va_end(ap);
		va_start(ap, fmt);
		_second_fn(fmt, ap);
		va_end(ap);
		...
	}

except that the original problem requires that the solution be
contained within the __printf function.

>BTW, I think there should be a stropen()-like function so mere-mortals
>can open string based stdio streams.  Is this in the standard?

It is not in the standard, but I have one; mine is called fmemopen().
There is a more general interface called funopen():

	/* declaration (prototype version) */
	FILE *funopen(const void *cookie,
		int (*readfn)(void *cookie, char *buf, int n),
		int (*writefn)(void *cookie, const char *buf, int n),
		long (*seekfn)(void *cookie, long off, int whence),
		int (*closefn)(void *cookie));
	#define	fropen(cookie, fn) funopen(cookie, fn, 0, 0, 0)
	#define fwopen(cookie, fn) funopen(cookie, 0, fn, 0, 0)

Unix stdio needs only these four operations.  By restructuring the
stdio internals slightly, `normal' file I/O is done with read, write,
seek, and close functions that just call read, write, seek, and close,
and anyone can easily write `special' I/O routines.  fmemopen() is just
a special instance of this same general case---in principle, it uses
read and write functions that transfer to user memory, although in
practise just aims the internal stdio buffers directly at that memory;
its read and write functions return an error, and get called only when
the declared region is full (write) or empty (read).  (Being an
internal stdio function, it is allowed to cheat like this.)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris