vfprintf.c revision 113723
1221828Sgrehan/*-
2221828Sgrehan * Copyright (c) 1990, 1993
3221828Sgrehan *	The Regents of the University of California.  All rights reserved.
4221828Sgrehan *
5221828Sgrehan * This code is derived from software contributed to Berkeley by
6221828Sgrehan * Chris Torek.
7221828Sgrehan *
8221828Sgrehan * Redistribution and use in source and binary forms, with or without
9221828Sgrehan * modification, are permitted provided that the following conditions
10221828Sgrehan * are met:
11221828Sgrehan * 1. Redistributions of source code must retain the above copyright
12221828Sgrehan *    notice, this list of conditions and the following disclaimer.
13221828Sgrehan * 2. Redistributions in binary form must reproduce the above copyright
14221828Sgrehan *    notice, this list of conditions and the following disclaimer in the
15221828Sgrehan *    documentation and/or other materials provided with the distribution.
16221828Sgrehan * 3. All advertising materials mentioning features or use of this software
17221828Sgrehan *    must display the following acknowledgement:
18221828Sgrehan *	This product includes software developed by the University of
19221828Sgrehan *	California, Berkeley and its contributors.
20221828Sgrehan * 4. Neither the name of the University nor the names of its contributors
21221828Sgrehan *    may be used to endorse or promote products derived from this software
22221828Sgrehan *    without specific prior written permission.
23221828Sgrehan *
24221828Sgrehan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25221828Sgrehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26221828Sgrehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27221828Sgrehan * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28221828Sgrehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29221828Sgrehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30221828Sgrehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31221828Sgrehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32221828Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33221828Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34221828Sgrehan * SUCH DAMAGE.
35221828Sgrehan */
36221828Sgrehan
37244013Sgrehan#if defined(LIBC_SCCS) && !defined(lint)
38221828Sgrehanstatic char sccsid[] = "@(#)vfprintf.c	8.1 (Berkeley) 6/4/93";
39221828Sgrehan#endif /* LIBC_SCCS and not lint */
40221828Sgrehan#include <sys/cdefs.h>
41221828Sgrehan__FBSDID("$FreeBSD: head/lib/libc/stdio/vfprintf.c 113723 2003-04-19 23:53:19Z das $");
42221828Sgrehan
43221828Sgrehan/*
44221828Sgrehan * Actual printf innards.
45221828Sgrehan *
46221828Sgrehan * This code is large and complicated...
47221828Sgrehan */
48221828Sgrehan
49256390Sgrehan#include "namespace.h"
50221828Sgrehan#include <sys/types.h>
51244167Sgrehan
52221828Sgrehan#include <ctype.h>
53221828Sgrehan#include <limits.h>
54280744Smav#include <locale.h>
55221828Sgrehan#include <stddef.h>
56221828Sgrehan#include <stdint.h>
57221828Sgrehan#include <stdio.h>
58221828Sgrehan#include <stdlib.h>
59221828Sgrehan#include <string.h>
60256390Sgrehan#include <wchar.h>
61221828Sgrehan
62256390Sgrehan#include <stdarg.h>
63256390Sgrehan#include "un-namespace.h"
64257128Sgrehan
65257128Sgrehan#include "libc_private.h"
66280243Smav#include "local.h"
67280243Smav#include "fvwrite.h"
68257128Sgrehan
69221828Sgrehan/* Define FLOATING_POINT to get floating point. */
70221828Sgrehan#define	FLOATING_POINT
71221828Sgrehan
72221828Sgrehanunion arg {
73257128Sgrehan	int	intarg;
74257128Sgrehan	u_int	uintarg;
75280243Smav	long	longarg;
76253440Sgrehan	u_long	ulongarg;
77221828Sgrehan	long long longlongarg;
78221828Sgrehan	unsigned long long ulonglongarg;
79253440Sgrehan	ptrdiff_t ptrdiffarg;
80221828Sgrehan	size_t	sizearg;
81221828Sgrehan	intmax_t intmaxarg;
82221828Sgrehan	uintmax_t uintmaxarg;
83221828Sgrehan	void	*pvoidarg;
84221828Sgrehan	char	*pchararg;
85280243Smav	signed char *pschararg;
86280243Smav	short	*pshortarg;
87280243Smav	int	*pintarg;
88280243Smav	long	*plongarg;
89280243Smav	long long *plonglongarg;
90221828Sgrehan	ptrdiff_t *pptrdiffarg;
91280243Smav	size_t	*psizearg;
92280243Smav	intmax_t *pintmaxarg;
93280243Smav#ifdef FLOATING_POINT
94280243Smav	double	doublearg;
95280243Smav	long double longdoublearg;
96280243Smav#endif
97280243Smav	wint_t	wintarg;
98221828Sgrehan	wchar_t	*pwchararg;
99221828Sgrehan};
100221828Sgrehan
101221828Sgrehan/*
102221828Sgrehan * Type ids for argument type table.
103221828Sgrehan */
104247342Sneelenum typeid {
105247342Sneel	T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT,
106276349Sneel	T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG,
107276349Sneel	T_PTRDIFFT, TP_PTRDIFFT, T_SIZET, TP_SIZET,
108256390Sgrehan	T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR,
109247342Sneel	T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR
110221828Sgrehan};
111221828Sgrehan
112221828Sgrehanstatic int	__sprint(FILE *, struct __suio *);
113221828Sgrehanstatic int	__sbprintf(FILE *, const char *, va_list) __printflike(2, 0);
114221828Sgrehanstatic char	*__ujtoa(uintmax_t, char *, int, int, const char *, int, char,
115221828Sgrehan		    const char *);
116221828Sgrehanstatic char	*__ultoa(u_long, char *, int, int, const char *, int, char,
117221828Sgrehan		    const char *);
118221828Sgrehanstatic char	*__wcsconv(wchar_t *, int);
119221828Sgrehanstatic void	__find_arguments(const char *, va_list, union arg **);
120221828Sgrehanstatic void	__grow_type_table(int, enum typeid **, int *);
121221828Sgrehan
122280744Smav/*
123280744Smav * Flush out all the vectors defined by the given uio,
124280744Smav * then reset it so that it can be reused.
125280744Smav */
126280744Smavstatic int
127280744Smav__sprint(FILE *fp, struct __suio *uio)
128280744Smav{
129221828Sgrehan	int err;
130221828Sgrehan
131221828Sgrehan	if (uio->uio_resid == 0) {
132221828Sgrehan		uio->uio_iovcnt = 0;
133253440Sgrehan		return (0);
134267393Sjhb	}
135253440Sgrehan	err = __sfvwrite(fp, uio);
136280744Smav	uio->uio_resid = 0;
137280744Smav	uio->uio_iovcnt = 0;
138256390Sgrehan	return (err);
139280744Smav}
140221828Sgrehan
141221828Sgrehan/*
142253440Sgrehan * Helper function for `fprintf to unbuffered unix file': creates a
143253440Sgrehan * temporary buffer.  We only work on write-only files; this avoids
144253440Sgrehan * worries about ungetc buffers and so forth.
145253440Sgrehan */
146246214Sneelstatic int
147253440Sgrehan__sbprintf(FILE *fp, const char *fmt, va_list ap)
148253440Sgrehan{
149253440Sgrehan	int ret;
150253440Sgrehan	FILE fake;
151253440Sgrehan	unsigned char buf[BUFSIZ];
152253440Sgrehan
153253440Sgrehan	/* copy the important variables */
154253440Sgrehan	fake._flags = fp->_flags & ~__SNBF;
155271685Sgrehan	fake._file = fp->_file;
156253440Sgrehan	fake._cookie = fp->_cookie;
157253440Sgrehan	fake._write = fp->_write;
158246214Sneel	fake._extra = fp->_extra;
159221828Sgrehan
160253440Sgrehan	/* set up the buffer */
161221828Sgrehan	fake._bf._base = fake._p = buf;
162253440Sgrehan	fake._bf._size = fake._w = sizeof(buf);
163221828Sgrehan	fake._lbfsize = 0;	/* not actually used, but Just In Case */
164253440Sgrehan
165253440Sgrehan	/* do the work, then copy any error status */
166221828Sgrehan	ret = __vfprintf(&fake, fmt, ap);
167221828Sgrehan	if (ret >= 0 && __fflush(&fake))
168221828Sgrehan		ret = EOF;
169280744Smav	if (fake._flags & __SERR)
170280744Smav		fp->_flags |= __SERR;
171280744Smav	return (ret);
172280744Smav}
173280744Smav
174280744Smav/*
175280744Smav * Macros for converting digits to letters and vice versa
176280744Smav */
177280744Smav#define	to_digit(c)	((c) - '0')
178280744Smav#define is_digit(c)	((unsigned)to_digit(c) <= 9)
179280744Smav#define	to_char(n)	((n) + '0')
180280744Smav
181280744Smav/*
182280744Smav * Convert an unsigned long to ASCII for printf purposes, returning
183280744Smav * a pointer to the first character of the string representation.
184280744Smav * Octal numbers can be forced to have a leading zero; hex numbers
185280744Smav * use the given digits.
186280744Smav */
187280744Smavstatic char *
188280744Smav__ultoa(u_long val, char *endp, int base, int octzero, const char *xdigs,
189280744Smav	int needgrp, char thousep, const char *grp)
190280744Smav{
191280744Smav	char *cp = endp;
192280744Smav	long sval;
193253440Sgrehan	int ndig;
194221828Sgrehan
195221828Sgrehan	/*
196280744Smav	 * Handle the three cases separately, in the hope of getting
197253440Sgrehan	 * better/faster code.
198221828Sgrehan	 */
199221828Sgrehan	switch (base) {
200253440Sgrehan	case 10:
201221828Sgrehan		if (val < 10) {	/* many numbers are 1 digit */
202280749Smav			*--cp = to_char(val);
203280749Smav			return (cp);
204221828Sgrehan		}
205280749Smav		ndig = 0;
206221828Sgrehan		/*
207253440Sgrehan		 * On many machines, unsigned arithmetic is harder than
208253440Sgrehan		 * signed arithmetic, so we do at most one unsigned mod and
209253440Sgrehan		 * divide; this is sufficient to reduce the range of
210253440Sgrehan		 * the incoming value to where signed arithmetic works.
211253440Sgrehan		 */
212253440Sgrehan		if (val > LONG_MAX) {
213253440Sgrehan			*--cp = to_char(val % 10);
214253440Sgrehan			ndig++;
215280749Smav			sval = val / 10;
216221828Sgrehan		} else
217280744Smav			sval = val;
218253440Sgrehan		do {
219253440Sgrehan			*--cp = to_char(sval % 10);
220253440Sgrehan			ndig++;
221280744Smav			/*
222280744Smav			 * If (*grp == CHAR_MAX) then no more grouping
223280744Smav			 * should be performed.
224280744Smav			 */
225253440Sgrehan			if (needgrp && ndig == *grp && *grp != CHAR_MAX
226253440Sgrehan					&& sval > 9) {
227221828Sgrehan				*--cp = thousep;
228221828Sgrehan				ndig = 0;
229247342Sneel				/*
230247342Sneel				 * If (*(grp+1) == '\0') then we have to
231247342Sneel				 * use *grp character (last grouping rule)
232247342Sneel				 * for all next cases
233247342Sneel				 */
234247342Sneel				if (*(grp+1) != '\0')
235221828Sgrehan					grp++;
236253440Sgrehan			}
237253440Sgrehan			sval /= 10;
238221828Sgrehan		} while (sval != 0);
239221828Sgrehan		break;
240256390Sgrehan
241221828Sgrehan	case 8:
242221828Sgrehan		do {
243221828Sgrehan			*--cp = to_char(val & 7);
244253440Sgrehan			val >>= 3;
245253440Sgrehan		} while (val);
246221828Sgrehan		if (octzero && *cp != '0')
247221828Sgrehan			*--cp = '0';
248221828Sgrehan		break;
249256390Sgrehan
250221828Sgrehan	case 16:
251256390Sgrehan		do {
252280744Smav			*--cp = xdigs[val & 15];
253280744Smav			val >>= 4;
254280744Smav		} while (val);
255256390Sgrehan		break;
256280744Smav
257256390Sgrehan	default:			/* oops */
258280744Smav		abort();
259280744Smav	}
260280744Smav	return (cp);
261256390Sgrehan}
262256390Sgrehan
263256390Sgrehan/* Identical to __ultoa, but for intmax_t. */
264280747Smavstatic char *
265280747Smav__ujtoa(uintmax_t val, char *endp, int base, int octzero, const char *xdigs,
266280747Smav	int needgrp, char thousep, const char *grp)
267268976Sjhb{
268280744Smav	char *cp = endp;
269280744Smav	intmax_t sval;
270256390Sgrehan	int ndig;
271280744Smav
272280744Smav	/* quick test for small values; __ultoa is typically much faster */
273256390Sgrehan	/* (perhaps instead we should run until small, then call __ultoa?) */
274280744Smav	if (val <= ULONG_MAX)
275221828Sgrehan		return (__ultoa((u_long)val, endp, base, octzero, xdigs,
276221828Sgrehan		    needgrp, thousep, grp));
277221828Sgrehan	switch (base) {
278253440Sgrehan	case 10:
279249813Sneel		if (val < 10) {
280253440Sgrehan			*--cp = to_char(val % 10);
281249813Sneel			return (cp);
282253440Sgrehan		}
283253440Sgrehan		ndig = 0;
284249813Sneel		if (val > INTMAX_MAX) {
285249813Sneel			*--cp = to_char(val % 10);
286221828Sgrehan			ndig++;
287221828Sgrehan			sval = val / 10;
288221828Sgrehan		} else
289280744Smav			sval = val;
290280744Smav		do {
291256390Sgrehan			*--cp = to_char(sval % 10);
292256390Sgrehan			ndig++;
293221828Sgrehan			/*
294280744Smav			 * If (*grp == CHAR_MAX) then no more grouping
295280744Smav			 * should be performed.
296221828Sgrehan			 */
297221828Sgrehan			if (needgrp && *grp != CHAR_MAX && ndig == *grp
298221828Sgrehan					&& sval > 9) {
299221828Sgrehan				*--cp = thousep;
300221828Sgrehan				ndig = 0;
301221828Sgrehan				/*
302221828Sgrehan				 * If (*(grp+1) == '\0') then we have to
303221828Sgrehan				 * use *grp character (last grouping rule)
304221828Sgrehan				 * for all next cases
305280744Smav				 */
306280744Smav				if (*(grp+1) != '\0')
307280744Smav					grp++;
308221828Sgrehan			}
309221828Sgrehan			sval /= 10;
310221828Sgrehan		} while (sval != 0);
311221828Sgrehan		break;
312280744Smav
313280744Smav	case 8:
314280744Smav		do {
315244013Sgrehan			*--cp = to_char(val & 7);
316268953Sjhb			val >>= 3;
317280744Smav		} while (val);
318280744Smav		if (octzero && *cp != '0')
319280744Smav			*--cp = '0';
320280744Smav		break;
321280744Smav
322280744Smav	case 16:
323280744Smav		do {
324280744Smav			*--cp = xdigs[val & 15];
325221828Sgrehan			val >>= 4;
326267393Sjhb		} while (val);
327267393Sjhb		break;
328253440Sgrehan
329253440Sgrehan	default:
330267393Sjhb		abort();
331267393Sjhb	}
332253440Sgrehan	return (cp);
333253440Sgrehan}
334253440Sgrehan
335256390Sgrehan/*
336256390Sgrehan * Convert a wide character string argument for the %ls format to a multibyte
337256390Sgrehan * string representation. ``prec'' specifies the maximum number of bytes
338256390Sgrehan * to output. If ``prec'' is greater than or equal to zero, we can't assume
339256390Sgrehan * that the wide char. string ends in a null character.
340256390Sgrehan */
341256390Sgrehanstatic char *
342256390Sgrehan__wcsconv(wchar_t *wcsarg, int prec)
343256390Sgrehan{
344256390Sgrehan	char buf[MB_LEN_MAX];
345221828Sgrehan	wchar_t *p;
346257128Sgrehan	char *convbuf, *mbp;
347280243Smav	size_t clen, nbytes;
348280749Smav	mbstate_t mbs;
349280243Smav
350280243Smav	/*
351280243Smav	 * Determine the number of bytes to output and allocate space for
352244013Sgrehan	 * the output.
353280243Smav	 */
354280243Smav	memset(&mbs, 0, sizeof(mbs));
355280243Smav	if (prec >= 0) {
356280243Smav		nbytes = 0;
357280243Smav		p = wcsarg;
358280243Smav		for (;;) {
359280243Smav			clen = wcrtomb(buf, *p++, &mbs);
360221828Sgrehan			if (clen == 0 || clen == (size_t)-1 ||
361253440Sgrehan			    nbytes + clen > prec)
362253440Sgrehan				break;
363253440Sgrehan			nbytes += clen;
364253440Sgrehan		}
365253440Sgrehan	} else {
366221828Sgrehan		p = wcsarg;
367221828Sgrehan		nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs);
368221828Sgrehan		if (nbytes == (size_t)-1)
369221828Sgrehan			return (NULL);
370246214Sneel	}
371267393Sjhb	if ((convbuf = malloc(nbytes + 1)) == NULL)
372267393Sjhb		return (NULL);
373280744Smav
374280744Smav	/*
375280744Smav	 * Fill the output buffer with the multibyte representations of as
376253440Sgrehan	 * many wide characters as will fit.
377280744Smav	 */
378253440Sgrehan	mbp = convbuf;
379221828Sgrehan	p = wcsarg;
380221828Sgrehan	memset(&mbs, 0, sizeof(mbs));
381221828Sgrehan	while (mbp - convbuf < nbytes) {
382253440Sgrehan		clen = wcrtomb(mbp, *p++, &mbs);
383253440Sgrehan		if (clen == 0 || clen == (size_t)-1)
384246214Sneel			break;
385246214Sneel		mbp += clen;
386253440Sgrehan	}
387253440Sgrehan	if (clen == (size_t)-1) {
388246214Sneel		free(convbuf);
389246214Sneel		return (NULL);
390253440Sgrehan	}
391253440Sgrehan	*mbp = '\0';
392221828Sgrehan
393253440Sgrehan	return (convbuf);
394222830Sgrehan}
395221828Sgrehan
396253440Sgrehan/*
397253440Sgrehan * MT-safe version
398253440Sgrehan */
399253440Sgrehanint
400221828Sgrehanvfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap)
401221828Sgrehan
402221828Sgrehan{
403241744Sgrehan	int ret;
404241744Sgrehan
405253440Sgrehan	FLOCKFILE(fp);
406253440Sgrehan	ret = __vfprintf(fp, fmt0, ap);
407221828Sgrehan	FUNLOCKFILE(fp);
408221828Sgrehan	return (ret);
409}
410
411#ifdef FLOATING_POINT
412
413#define	dtoa		__dtoa
414#define	freedtoa	__freedtoa
415
416#include <float.h>
417#include <math.h>
418#include "floatio.h"
419#include "gdtoa.h"
420
421#define	DEFPREC		6
422
423static int exponent(char *, int, int);
424
425#endif /* FLOATING_POINT */
426
427/*
428 * The size of the buffer we use as scratch space for integer
429 * conversions, among other things.  Technically, we would need the
430 * most space for base 10 conversions with thousands' grouping
431 * characters between each pair of digits.  100 bytes is a
432 * conservative overestimate even for a 128-bit uintmax_t.
433 */
434#define	BUF	100
435
436#define STATIC_ARG_TBL_SIZE 8           /* Size of static argument table. */
437
438/*
439 * Flags used during conversion.
440 */
441#define	ALT		0x001		/* alternate form */
442#define	LADJUST		0x004		/* left adjustment */
443#define	LONGDBL		0x008		/* long double */
444#define	LONGINT		0x010		/* long integer */
445#define	LLONGINT	0x020		/* long long integer */
446#define	SHORTINT	0x040		/* short integer */
447#define	ZEROPAD		0x080		/* zero (as opposed to blank) pad */
448#define	FPT		0x100		/* Floating point number */
449#define	GROUPING	0x200		/* use grouping ("'" flag) */
450					/* C99 additional size modifiers: */
451#define	SIZET		0x400		/* size_t */
452#define	PTRDIFFT	0x800		/* ptrdiff_t */
453#define	INTMAXT		0x1000		/* intmax_t */
454#define	CHARINT		0x2000		/* print char using int format */
455
456/*
457 * Non-MT-safe version
458 */
459int
460__vfprintf(FILE *fp, const char *fmt0, va_list ap)
461{
462	char *fmt;		/* format string */
463	int ch;			/* character from fmt */
464	int n, n2;		/* handy integer (short term usage) */
465	char *cp;		/* handy char pointer (short term usage) */
466	struct __siov *iovp;	/* for PRINT macro */
467	int flags;		/* flags as above */
468	int ret;		/* return value accumulator */
469	int width;		/* width from format (%8d), or 0 */
470	int prec;		/* precision from format; <0 for N/A */
471	char sign;		/* sign prefix (' ', '+', '-', or \0) */
472	char thousands_sep;	/* locale specific thousands separator */
473	const char *grouping;	/* locale specific numeric grouping rules */
474#ifdef FLOATING_POINT
475	/*
476	 * We can decompose the printed representation of floating
477	 * point numbers into several parts, some of which may be empty:
478	 *
479	 * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
480	 *    A       B     ---C---      D       E   F
481	 *
482	 * A:	'sign' holds this value if present; '\0' otherwise
483	 * B:	ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
484	 * C:	cp points to the string MMMNNN.  Leading and trailing
485	 *	zeros are not in the string and must be added.
486	 * D:	expchar holds this character; '\0' if no exponent, e.g. %f
487	 * F:	at least two digits for decimal, at least one digit for hex
488	 */
489	char *decimal_point;	/* locale specific decimal point */
490	int signflag;		/* true if float is negative */
491	union {			/* floating point arguments %[aAeEfFgG] */
492		double dbl;
493		long double ldbl;
494	} fparg;
495	int expt;		/* integer value of exponent */
496	char expchar;		/* exponent character: [eEpP\0] */
497	char *dtoaend;		/* pointer to end of converted digits */
498	int expsize;		/* character count for expstr */
499	int lead;		/* sig figs before decimal or group sep */
500	int ndig;		/* actual number of digits returned by dtoa */
501	char expstr[MAXEXPDIG+2];	/* buffer for exponent string: e+ZZZ */
502	char *dtoaresult;	/* buffer allocated by dtoa */
503	int nseps;		/* number of group separators with ' */
504	int nrepeats;		/* number of repeats of the last group */
505#endif
506	u_long	ulval;		/* integer arguments %[diouxX] */
507	uintmax_t ujval;	/* %j, %ll, %q, %t, %z integers */
508	int base;		/* base for [diouxX] conversion */
509	int dprec;		/* a copy of prec if [diouxX], 0 otherwise */
510	int realsz;		/* field size expanded by dprec, sign, etc */
511	int size;		/* size of converted field or string */
512	int prsize;             /* max size of printed field */
513	const char *xdigs;     	/* digits for %[xX] conversion */
514#define NIOV 8
515	struct __suio uio;	/* output information: summary */
516	struct __siov iov[NIOV];/* ... and individual io vectors */
517	char buf[BUF];		/* buffer with space for digits of uintmax_t */
518	char ox[2];		/* space for 0x; ox[1] is either x, X, or \0 */
519	union arg *argtable;    /* args, built due to positional arg */
520	union arg statargtable [STATIC_ARG_TBL_SIZE];
521	int nextarg;            /* 1-based argument index */
522	va_list orgap;          /* original argument pointer */
523	char *convbuf;		/* wide to multibyte conversion result */
524
525	/*
526	 * Choose PADSIZE to trade efficiency vs. size.  If larger printf
527	 * fields occur frequently, increase PADSIZE and make the initialisers
528	 * below longer.
529	 */
530#define	PADSIZE	16		/* pad chunk size */
531	static char blanks[PADSIZE] =
532	 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
533	static char zeroes[PADSIZE] =
534	 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
535
536	static const char xdigs_lower[16] = "0123456789abcdef";
537	static const char xdigs_upper[16] = "0123456789ABCDEF";
538
539	/*
540	 * BEWARE, these `goto error' on error, and PAD uses `n'.
541	 */
542#define	PRINT(ptr, len) { \
543	iovp->iov_base = (ptr); \
544	iovp->iov_len = (len); \
545	uio.uio_resid += (len); \
546	iovp++; \
547	if (++uio.uio_iovcnt >= NIOV) { \
548		if (__sprint(fp, &uio)) \
549			goto error; \
550		iovp = iov; \
551	} \
552}
553#define	PAD(howmany, with) { \
554	if ((n = (howmany)) > 0) { \
555		while (n > PADSIZE) { \
556			PRINT(with, PADSIZE); \
557			n -= PADSIZE; \
558		} \
559		PRINT(with, n); \
560	} \
561}
562#define	PRINTANDPAD(p, ep, len, with) do {	\
563	n2 = (ep) - (p);       			\
564	if (n2 > (len))				\
565		n2 = (len);			\
566	if (n2 > 0)				\
567		PRINT((p), n2);			\
568	PAD((len) - (n2 > 0 ? n2 : 0), (with));	\
569} while(0)
570#define	FLUSH() { \
571	if (uio.uio_resid && __sprint(fp, &uio)) \
572		goto error; \
573	uio.uio_iovcnt = 0; \
574	iovp = iov; \
575}
576
577	/*
578	 * Get the argument indexed by nextarg.   If the argument table is
579	 * built, use it to get the argument.  If its not, get the next
580	 * argument (and arguments must be gotten sequentially).
581	 */
582#define GETARG(type) \
583	((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
584	    (nextarg++, va_arg(ap, type)))
585
586	/*
587	 * To extend shorts properly, we need both signed and unsigned
588	 * argument extraction methods.
589	 */
590#define	SARG() \
591	(flags&LONGINT ? GETARG(long) : \
592	    flags&SHORTINT ? (long)(short)GETARG(int) : \
593	    flags&CHARINT ? (long)(signed char)GETARG(int) : \
594	    (long)GETARG(int))
595#define	UARG() \
596	(flags&LONGINT ? GETARG(u_long) : \
597	    flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
598	    flags&CHARINT ? (u_long)(u_char)GETARG(int) : \
599	    (u_long)GETARG(u_int))
600#define	INTMAX_SIZE	(INTMAXT|SIZET|PTRDIFFT|LLONGINT)
601#define SJARG() \
602	(flags&INTMAXT ? GETARG(intmax_t) : \
603	    flags&SIZET ? (intmax_t)GETARG(size_t) : \
604	    flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \
605	    (intmax_t)GETARG(long long))
606#define	UJARG() \
607	(flags&INTMAXT ? GETARG(uintmax_t) : \
608	    flags&SIZET ? (uintmax_t)GETARG(size_t) : \
609	    flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \
610	    (uintmax_t)GETARG(unsigned long long))
611
612	/*
613	 * Get * arguments, including the form *nn$.  Preserve the nextarg
614	 * that the argument can be gotten once the type is determined.
615	 */
616#define GETASTER(val) \
617	n2 = 0; \
618	cp = fmt; \
619	while (is_digit(*cp)) { \
620		n2 = 10 * n2 + to_digit(*cp); \
621		cp++; \
622	} \
623	if (*cp == '$') { \
624		int hold = nextarg; \
625		if (argtable == NULL) { \
626			argtable = statargtable; \
627			__find_arguments (fmt0, orgap, &argtable); \
628		} \
629		nextarg = n2; \
630		val = GETARG (int); \
631		nextarg = hold; \
632		fmt = ++cp; \
633	} else { \
634		val = GETARG (int); \
635	}
636
637
638	thousands_sep = '\0';
639	grouping = NULL;
640	convbuf = NULL;
641#ifdef FLOATING_POINT
642	dtoaresult = NULL;
643	decimal_point = localeconv()->decimal_point;
644#endif
645	/* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
646	if (cantwrite(fp))
647		return (EOF);
648
649	/* optimise fprintf(stderr) (and other unbuffered Unix files) */
650	if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
651	    fp->_file >= 0)
652		return (__sbprintf(fp, fmt0, ap));
653
654	fmt = (char *)fmt0;
655	argtable = NULL;
656	nextarg = 1;
657	va_copy(orgap, ap);
658	uio.uio_iov = iovp = iov;
659	uio.uio_resid = 0;
660	uio.uio_iovcnt = 0;
661	ret = 0;
662
663	/*
664	 * Scan the format for conversions (`%' character).
665	 */
666	for (;;) {
667		for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
668			/* void */;
669		if ((n = fmt - cp) != 0) {
670			if ((unsigned)ret + n > INT_MAX) {
671				ret = EOF;
672				goto error;
673			}
674			PRINT(cp, n);
675			ret += n;
676		}
677		if (ch == '\0')
678			goto done;
679		fmt++;		/* skip over '%' */
680
681		flags = 0;
682		dprec = 0;
683		width = 0;
684		prec = -1;
685		sign = '\0';
686		ox[1] = '\0';
687
688rflag:		ch = *fmt++;
689reswitch:	switch (ch) {
690		case ' ':
691			/*-
692			 * ``If the space and + flags both appear, the space
693			 * flag will be ignored.''
694			 *	-- ANSI X3J11
695			 */
696			if (!sign)
697				sign = ' ';
698			goto rflag;
699		case '#':
700			flags |= ALT;
701			goto rflag;
702		case '*':
703			/*-
704			 * ``A negative field width argument is taken as a
705			 * - flag followed by a positive field width.''
706			 *	-- ANSI X3J11
707			 * They don't exclude field widths read from args.
708			 */
709			GETASTER (width);
710			if (width >= 0)
711				goto rflag;
712			width = -width;
713			/* FALLTHROUGH */
714		case '-':
715			flags |= LADJUST;
716			goto rflag;
717		case '+':
718			sign = '+';
719			goto rflag;
720		case '\'':
721			flags |= GROUPING;
722			thousands_sep = *(localeconv()->thousands_sep);
723			grouping = localeconv()->grouping;
724			goto rflag;
725		case '.':
726			if ((ch = *fmt++) == '*') {
727				GETASTER (prec);
728				goto rflag;
729			}
730			prec = 0;
731			while (is_digit(ch)) {
732				prec = 10 * prec + to_digit(ch);
733				ch = *fmt++;
734			}
735			goto reswitch;
736		case '0':
737			/*-
738			 * ``Note that 0 is taken as a flag, not as the
739			 * beginning of a field width.''
740			 *	-- ANSI X3J11
741			 */
742			flags |= ZEROPAD;
743			goto rflag;
744		case '1': case '2': case '3': case '4':
745		case '5': case '6': case '7': case '8': case '9':
746			n = 0;
747			do {
748				n = 10 * n + to_digit(ch);
749				ch = *fmt++;
750			} while (is_digit(ch));
751			if (ch == '$') {
752				nextarg = n;
753				if (argtable == NULL) {
754					argtable = statargtable;
755					__find_arguments (fmt0, orgap,
756					    &argtable);
757				}
758				goto rflag;
759			}
760			width = n;
761			goto reswitch;
762#ifdef FLOATING_POINT
763		case 'L':
764			flags |= LONGDBL;
765			goto rflag;
766#endif
767		case 'h':
768			if (flags & SHORTINT) {
769				flags &= ~SHORTINT;
770				flags |= CHARINT;
771			} else
772				flags |= SHORTINT;
773			goto rflag;
774		case 'j':
775			flags |= INTMAXT;
776			goto rflag;
777		case 'l':
778			if (flags & LONGINT) {
779				flags &= ~LONGINT;
780				flags |= LLONGINT;
781			} else
782				flags |= LONGINT;
783			goto rflag;
784		case 'q':
785			flags |= LLONGINT;	/* not necessarily */
786			goto rflag;
787		case 't':
788			flags |= PTRDIFFT;
789			goto rflag;
790		case 'z':
791			flags |= SIZET;
792			goto rflag;
793		case 'C':
794			flags |= LONGINT;
795			/*FALLTHROUGH*/
796		case 'c':
797			if (flags & LONGINT) {
798				mbstate_t mbs;
799				size_t mbseqlen;
800
801				memset(&mbs, 0, sizeof(mbs));
802				mbseqlen = wcrtomb(cp = buf,
803				    (wchar_t)GETARG(wint_t), &mbs);
804				if (mbseqlen == (size_t)-1) {
805					fp->_flags |= __SERR;
806					goto error;
807				}
808				size = (int)mbseqlen;
809			} else {
810				*(cp = buf) = GETARG(int);
811				size = 1;
812			}
813			sign = '\0';
814			break;
815		case 'D':
816			flags |= LONGINT;
817			/*FALLTHROUGH*/
818		case 'd':
819		case 'i':
820			if (flags & INTMAX_SIZE) {
821				ujval = SJARG();
822				if ((intmax_t)ujval < 0) {
823					ujval = -ujval;
824					sign = '-';
825				}
826			} else {
827				ulval = SARG();
828				if ((long)ulval < 0) {
829					ulval = -ulval;
830					sign = '-';
831				}
832			}
833			base = 10;
834			goto number;
835#ifdef FLOATING_POINT
836#ifdef HEXFLOAT
837		case 'a':
838		case 'A':
839			if (ch == 'a') {
840				ox[1] = 'x';
841				xdigs = xdigs_lower;
842				expchar = 'p';
843			} else {
844				ox[1] = 'X';
845				xdigs = xdigs_upper;
846				expchar = 'P';
847			}
848			/*
849			 * XXX We don't actually have a conversion
850			 * XXX routine for this yet.
851			 */
852			if (flags & LONGDBL) {
853				fparg.ldbl = (double)GETARG(long double);
854				dtoaresult = cp =
855				    __hldtoa(fparg.ldbl, xdigs, prec,
856				    &expt, &signflag, &dtoaend);
857			} else {
858				fparg.dbl = GETARG(double);
859				dtoaresult = cp =
860				    __hdtoa(fparg.dbl, xdigs, prec,
861				    &expt, &signflag, &dtoaend);
862			}
863			goto fp_begin;
864#endif
865		case 'e':
866		case 'E':
867			expchar = ch;
868			if (prec < 0)	/* account for digit before decpt */
869				prec = DEFPREC + 1;
870			else
871				prec++;
872			goto fp_begin;
873		case 'f':
874		case 'F':
875			expchar = '\0';
876			goto fp_begin;
877		case 'g':
878		case 'G':
879			expchar = ch - ('g' - 'e');
880			if (prec == 0)
881				prec = 1;
882fp_begin:
883			if (prec < 0)
884				prec = DEFPREC;
885			if (dtoaresult != NULL)
886				freedtoa(dtoaresult);
887			if (flags & LONGDBL) {
888				fparg.ldbl = GETARG(long double);
889				dtoaresult = cp =
890				    __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec,
891				    &expt, &signflag, &dtoaend);
892			} else {
893				fparg.dbl = GETARG(double);
894				dtoaresult = cp =
895				    dtoa(fparg.dbl, expchar ? 2 : 3, prec,
896				    &expt, &signflag, &dtoaend);
897				if (expt == 9999)
898					expt = INT_MAX;
899			}
900			if (signflag)
901				sign = '-';
902			if (expt == INT_MAX) {	/* inf or nan */
903				if (*cp == 'N') {
904					cp = (ch >= 'a') ? "nan" : "NAN";
905					sign = '\0';
906				} else
907					cp = (ch >= 'a') ? "inf" : "INF";
908				size = 3;
909				break;
910			}
911			flags |= FPT;
912			ndig = dtoaend - cp;
913			if (ch == 'g' || ch == 'G') {
914				if (expt > -4 && expt <= prec) {
915					/* Make %[gG] smell like %[fF] */
916					expchar = '\0';
917					if (flags & ALT)
918						prec -= expt;
919					else
920						prec = ndig - expt;
921					if (prec < 0)
922						prec = 0;
923				} else {
924					/*
925					 * Make %[gG] smell like %[eE], but
926					 * trim trailing zeroes if no # flag.
927					 */
928					if (!(flags & ALT))
929						prec = ndig;
930				}
931			}
932			if (expchar) {
933				expsize = exponent(expstr, expt - 1, expchar);
934				size = expsize + prec;
935				if (prec > 1 || flags & ALT)
936					++size;
937			} else {
938				/* space for digits before decimal point */
939				if (expt > 0)
940					size = expt;
941				else	/* "0" */
942					size = 1;
943				/* space for decimal pt and following digits */
944				if (prec || flags & ALT)
945					size += prec + 1;
946				if (grouping && expt > 0) {
947					/* space for thousands' grouping */
948					nseps = nrepeats = 0;
949					lead = expt;
950					while (*grouping != CHAR_MAX) {
951						if (lead <= *grouping)
952							break;
953						lead -= *grouping;
954						if (*(grouping+1)) {
955							nseps++;
956							grouping++;
957						} else
958							nrepeats++;
959					}
960					size += nseps + nrepeats;
961				} else
962					lead = expt;
963			}
964			break;
965#endif /* FLOATING_POINT */
966		case 'n':
967			/*
968			 * Assignment-like behavior is specified if the
969			 * value overflows or is otherwise unrepresentable.
970			 * C99 says to use `signed char' for %hhn conversions.
971			 */
972			if (flags & LLONGINT)
973				*GETARG(long long *) = ret;
974			else if (flags & SIZET)
975				*GETARG(ssize_t *) = (ssize_t)ret;
976			else if (flags & PTRDIFFT)
977				*GETARG(ptrdiff_t *) = ret;
978			else if (flags & INTMAXT)
979				*GETARG(intmax_t *) = ret;
980			else if (flags & LONGINT)
981				*GETARG(long *) = ret;
982			else if (flags & SHORTINT)
983				*GETARG(short *) = ret;
984			else if (flags & CHARINT)
985				*GETARG(signed char *) = ret;
986			else
987				*GETARG(int *) = ret;
988			continue;	/* no output */
989		case 'O':
990			flags |= LONGINT;
991			/*FALLTHROUGH*/
992		case 'o':
993			if (flags & INTMAX_SIZE)
994				ujval = UJARG();
995			else
996				ulval = UARG();
997			base = 8;
998			goto nosign;
999		case 'p':
1000			/*-
1001			 * ``The argument shall be a pointer to void.  The
1002			 * value of the pointer is converted to a sequence
1003			 * of printable characters, in an implementation-
1004			 * defined manner.''
1005			 *	-- ANSI X3J11
1006			 */
1007			ujval = (uintmax_t)(uintptr_t)GETARG(void *);
1008			base = 16;
1009			xdigs = xdigs_lower;
1010			flags = flags | INTMAXT;
1011			ox[1] = 'x';
1012			goto nosign;
1013		case 'S':
1014			flags |= LONGINT;
1015			/*FALLTHROUGH*/
1016		case 's':
1017			if (flags & LONGINT) {
1018				wchar_t *wcp;
1019
1020				if (convbuf != NULL)
1021					free(convbuf);
1022				if ((wcp = GETARG(wchar_t *)) == NULL)
1023					cp = "(null)";
1024				else {
1025					convbuf = __wcsconv(wcp, prec);
1026					if (convbuf == NULL) {
1027						fp->_flags |= __SERR;
1028						goto error;
1029					}
1030					cp = convbuf;
1031				}
1032			} else if ((cp = GETARG(char *)) == NULL)
1033				cp = "(null)";
1034			if (prec >= 0) {
1035				/*
1036				 * can't use strlen; can only look for the
1037				 * NUL in the first `prec' characters, and
1038				 * strlen() will go further.
1039				 */
1040				char *p = memchr(cp, 0, (size_t)prec);
1041
1042				if (p != NULL) {
1043					size = p - cp;
1044					if (size > prec)
1045						size = prec;
1046				} else
1047					size = prec;
1048			} else
1049				size = strlen(cp);
1050			sign = '\0';
1051			break;
1052		case 'U':
1053			flags |= LONGINT;
1054			/*FALLTHROUGH*/
1055		case 'u':
1056			if (flags & INTMAX_SIZE)
1057				ujval = UJARG();
1058			else
1059				ulval = UARG();
1060			base = 10;
1061			goto nosign;
1062		case 'X':
1063			xdigs = xdigs_upper;
1064			goto hex;
1065		case 'x':
1066			xdigs = xdigs_lower;
1067hex:
1068			if (flags & INTMAX_SIZE)
1069				ujval = UJARG();
1070			else
1071				ulval = UARG();
1072			base = 16;
1073			/* leading 0x/X only if non-zero */
1074			if (flags & ALT &&
1075			    (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
1076				ox[1] = ch;
1077
1078			flags &= ~GROUPING;
1079			/* unsigned conversions */
1080nosign:			sign = '\0';
1081			/*-
1082			 * ``... diouXx conversions ... if a precision is
1083			 * specified, the 0 flag will be ignored.''
1084			 *	-- ANSI X3J11
1085			 */
1086number:			if ((dprec = prec) >= 0)
1087				flags &= ~ZEROPAD;
1088
1089			/*-
1090			 * ``The result of converting a zero value with an
1091			 * explicit precision of zero is no characters.''
1092			 *	-- ANSI X3J11
1093			 */
1094			cp = buf + BUF;
1095			if (flags & INTMAX_SIZE) {
1096				if (ujval != 0 || prec != 0)
1097					cp = __ujtoa(ujval, cp, base,
1098					    flags & ALT, xdigs,
1099					    flags & GROUPING, thousands_sep,
1100					    grouping);
1101			} else {
1102				if (ulval != 0 || prec != 0)
1103					cp = __ultoa(ulval, cp, base,
1104					    flags & ALT, xdigs,
1105					    flags & GROUPING, thousands_sep,
1106					    grouping);
1107			}
1108			size = buf + BUF - cp;
1109			if (size > BUF)	/* should never happen */
1110				abort();
1111			break;
1112		default:	/* "%?" prints ?, unless ? is NUL */
1113			if (ch == '\0')
1114				goto done;
1115			/* pretend it was %c with argument ch */
1116			cp = buf;
1117			*cp = ch;
1118			size = 1;
1119			sign = '\0';
1120			break;
1121		}
1122
1123		/*
1124		 * All reasonable formats wind up here.  At this point, `cp'
1125		 * points to a string which (if not flags&LADJUST) should be
1126		 * padded out to `width' places.  If flags&ZEROPAD, it should
1127		 * first be prefixed by any sign or other prefix; otherwise,
1128		 * it should be blank padded before the prefix is emitted.
1129		 * After any left-hand padding and prefixing, emit zeroes
1130		 * required by a decimal [diouxX] precision, then print the
1131		 * string proper, then emit zeroes required by any leftover
1132		 * floating precision; finally, if LADJUST, pad with blanks.
1133		 *
1134		 * Compute actual size, so we know how much to pad.
1135		 * size excludes decimal prec; realsz includes it.
1136		 */
1137		realsz = dprec > size ? dprec : size;
1138		if (sign)
1139			realsz++;
1140		else if (ox[1])
1141			realsz += 2;
1142
1143		prsize = width > realsz ? width : realsz;
1144		if ((unsigned)ret + prsize > INT_MAX) {
1145			ret = EOF;
1146			goto error;
1147		}
1148
1149		/* right-adjusting blank padding */
1150		if ((flags & (LADJUST|ZEROPAD)) == 0)
1151			PAD(width - realsz, blanks);
1152
1153		/* prefix */
1154		if (sign) {
1155			PRINT(&sign, 1);
1156		} else if (ox[1]) {	/* ox[1] is either x, X, or \0 */
1157			ox[0] = '0';
1158			PRINT(ox, 2);
1159		}
1160
1161		/* right-adjusting zero padding */
1162		if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
1163			PAD(width - realsz, zeroes);
1164
1165		/* leading zeroes from decimal precision */
1166		PAD(dprec - size, zeroes);
1167
1168		/* the string or number proper */
1169#ifdef FLOATING_POINT
1170		if ((flags & FPT) == 0) {
1171			PRINT(cp, size);
1172		} else {	/* glue together f_p fragments */
1173			if (!expchar) {	/* %[fF] or sufficiently short %[gG] */
1174				if (expt <= 0) {
1175					PRINT(zeroes, 1);
1176					if (prec || flags & ALT)
1177						PRINT(decimal_point, 1);
1178					PAD(-expt, zeroes);
1179					/* already handled initial 0's */
1180					prec += expt;
1181				} else {
1182					PRINTANDPAD(cp, dtoaend, lead, zeroes);
1183					cp += lead;
1184					if (grouping) {
1185						while (nseps>0 || nrepeats>0) {
1186							if (nrepeats > 0)
1187								nrepeats--;
1188							else {
1189								grouping--;
1190								nseps--;
1191							}
1192							PRINT(&thousands_sep,
1193							    1);
1194							PRINTANDPAD(cp,dtoaend,
1195							    *grouping, zeroes);
1196							cp += *grouping;
1197						}
1198						if (cp > dtoaend)
1199							cp = dtoaend;
1200					}
1201					if (prec || flags & ALT)
1202						PRINT(decimal_point,1);
1203				}
1204				PRINTANDPAD(cp, dtoaend, prec, zeroes);
1205			} else {	/* %[eE] or sufficiently long %[gG] */
1206				if (prec > 1 || flags & ALT) {
1207					buf[0] = *cp++;
1208					buf[1] = *decimal_point;
1209					PRINT(buf, 2);
1210					PRINT(cp, ndig-1);
1211					PAD(prec - ndig, zeroes);
1212				} else	/* XeYYY */
1213					PRINT(cp, 1);
1214				PRINT(expstr, expsize);
1215			}
1216		}
1217#else
1218		PRINT(cp, size);
1219#endif
1220		/* left-adjusting padding (always blank) */
1221		if (flags & LADJUST)
1222			PAD(width - realsz, blanks);
1223
1224		/* finally, adjust ret */
1225		ret += prsize;
1226
1227		FLUSH();	/* copy out the I/O vectors */
1228	}
1229done:
1230	FLUSH();
1231error:
1232#ifdef FLOATING_POINT
1233	if (dtoaresult != NULL)
1234		freedtoa(dtoaresult);
1235#endif
1236	if (convbuf != NULL)
1237		free(convbuf);
1238	if (__sferror(fp))
1239		ret = EOF;
1240	if ((argtable != NULL) && (argtable != statargtable))
1241		free (argtable);
1242	return (ret);
1243	/* NOTREACHED */
1244}
1245
1246/*
1247 * Find all arguments when a positional parameter is encountered.  Returns a
1248 * table, indexed by argument number, of pointers to each arguments.  The
1249 * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
1250 * It will be replaces with a malloc-ed one if it overflows.
1251 */
1252static void
1253__find_arguments (const char *fmt0, va_list ap, union arg **argtable)
1254{
1255	char *fmt;		/* format string */
1256	int ch;			/* character from fmt */
1257	int n, n2;		/* handy integer (short term usage) */
1258	char *cp;		/* handy char pointer (short term usage) */
1259	int flags;		/* flags as above */
1260	int width;		/* width from format (%8d), or 0 */
1261	enum typeid *typetable; /* table of types */
1262	enum typeid stattypetable [STATIC_ARG_TBL_SIZE];
1263	int tablesize;		/* current size of type table */
1264	int tablemax;		/* largest used index in table */
1265	int nextarg;		/* 1-based argument index */
1266
1267	/*
1268	 * Add an argument type to the table, expanding if necessary.
1269	 */
1270#define ADDTYPE(type) \
1271	((nextarg >= tablesize) ? \
1272		__grow_type_table(nextarg, &typetable, &tablesize) : 0, \
1273	(nextarg > tablemax) ? tablemax = nextarg : 0, \
1274	typetable[nextarg++] = type)
1275
1276#define	ADDSARG() \
1277	((flags&INTMAXT) ? ADDTYPE(T_INTMAXT) : \
1278		((flags&SIZET) ? ADDTYPE(T_SIZET) : \
1279		((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \
1280		((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \
1281		((flags&LONGINT) ? ADDTYPE(T_LONG) : ADDTYPE(T_INT))))))
1282
1283#define	ADDUARG() \
1284	((flags&INTMAXT) ? ADDTYPE(T_UINTMAXT) : \
1285		((flags&SIZET) ? ADDTYPE(T_SIZET) : \
1286		((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \
1287		((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \
1288		((flags&LONGINT) ? ADDTYPE(T_U_LONG) : ADDTYPE(T_U_INT))))))
1289
1290	/*
1291	 * Add * arguments to the type array.
1292	 */
1293#define ADDASTER() \
1294	n2 = 0; \
1295	cp = fmt; \
1296	while (is_digit(*cp)) { \
1297		n2 = 10 * n2 + to_digit(*cp); \
1298		cp++; \
1299	} \
1300	if (*cp == '$') { \
1301		int hold = nextarg; \
1302		nextarg = n2; \
1303		ADDTYPE (T_INT); \
1304		nextarg = hold; \
1305		fmt = ++cp; \
1306	} else { \
1307		ADDTYPE (T_INT); \
1308	}
1309	fmt = (char *)fmt0;
1310	typetable = stattypetable;
1311	tablesize = STATIC_ARG_TBL_SIZE;
1312	tablemax = 0;
1313	nextarg = 1;
1314	memset (typetable, T_UNUSED, STATIC_ARG_TBL_SIZE);
1315
1316	/*
1317	 * Scan the format for conversions (`%' character).
1318	 */
1319	for (;;) {
1320		for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
1321			/* void */;
1322		if (ch == '\0')
1323			goto done;
1324		fmt++;		/* skip over '%' */
1325
1326		flags = 0;
1327		width = 0;
1328
1329rflag:		ch = *fmt++;
1330reswitch:	switch (ch) {
1331		case ' ':
1332		case '#':
1333			goto rflag;
1334		case '*':
1335			ADDASTER ();
1336			goto rflag;
1337		case '-':
1338		case '+':
1339		case '\'':
1340			goto rflag;
1341		case '.':
1342			if ((ch = *fmt++) == '*') {
1343				ADDASTER ();
1344				goto rflag;
1345			}
1346			while (is_digit(ch)) {
1347				ch = *fmt++;
1348			}
1349			goto reswitch;
1350		case '0':
1351			goto rflag;
1352		case '1': case '2': case '3': case '4':
1353		case '5': case '6': case '7': case '8': case '9':
1354			n = 0;
1355			do {
1356				n = 10 * n + to_digit(ch);
1357				ch = *fmt++;
1358			} while (is_digit(ch));
1359			if (ch == '$') {
1360				nextarg = n;
1361				goto rflag;
1362			}
1363			width = n;
1364			goto reswitch;
1365#ifdef FLOATING_POINT
1366		case 'L':
1367			flags |= LONGDBL;
1368			goto rflag;
1369#endif
1370		case 'h':
1371			if (flags & SHORTINT) {
1372				flags &= ~SHORTINT;
1373				flags |= CHARINT;
1374			} else
1375				flags |= SHORTINT;
1376			goto rflag;
1377		case 'j':
1378			flags |= INTMAXT;
1379			goto rflag;
1380		case 'l':
1381			if (flags & LONGINT) {
1382				flags &= ~LONGINT;
1383				flags |= LLONGINT;
1384			} else
1385				flags |= LONGINT;
1386			goto rflag;
1387		case 'q':
1388			flags |= LLONGINT;	/* not necessarily */
1389			goto rflag;
1390		case 't':
1391			flags |= PTRDIFFT;
1392			goto rflag;
1393		case 'z':
1394			flags |= SIZET;
1395			goto rflag;
1396		case 'C':
1397			flags |= LONGINT;
1398			/*FALLTHROUGH*/
1399		case 'c':
1400			if (flags & LONGINT)
1401				ADDTYPE(T_WINT);
1402			else
1403				ADDTYPE(T_INT);
1404			break;
1405		case 'D':
1406			flags |= LONGINT;
1407			/*FALLTHROUGH*/
1408		case 'd':
1409		case 'i':
1410			ADDSARG();
1411			break;
1412#ifdef FLOATING_POINT
1413#ifdef HEXFLOAT
1414		case 'a':
1415		case 'A':
1416#endif
1417		case 'e':
1418		case 'E':
1419		case 'f':
1420		case 'g':
1421		case 'G':
1422			if (flags & LONGDBL)
1423				ADDTYPE(T_LONG_DOUBLE);
1424			else
1425				ADDTYPE(T_DOUBLE);
1426			break;
1427#endif /* FLOATING_POINT */
1428		case 'n':
1429			if (flags & INTMAXT)
1430				ADDTYPE(TP_INTMAXT);
1431			else if (flags & PTRDIFFT)
1432				ADDTYPE(TP_PTRDIFFT);
1433			else if (flags & SIZET)
1434				ADDTYPE(TP_SIZET);
1435			else if (flags & LLONGINT)
1436				ADDTYPE(TP_LLONG);
1437			else if (flags & LONGINT)
1438				ADDTYPE(TP_LONG);
1439			else if (flags & SHORTINT)
1440				ADDTYPE(TP_SHORT);
1441			else if (flags & CHARINT)
1442				ADDTYPE(TP_SCHAR);
1443			else
1444				ADDTYPE(TP_INT);
1445			continue;	/* no output */
1446		case 'O':
1447			flags |= LONGINT;
1448			/*FALLTHROUGH*/
1449		case 'o':
1450			ADDUARG();
1451			break;
1452		case 'p':
1453			ADDTYPE(TP_VOID);
1454			break;
1455		case 'S':
1456			flags |= LONGINT;
1457			/*FALLTHROUGH*/
1458		case 's':
1459			if (flags & LONGINT)
1460				ADDTYPE(TP_WCHAR);
1461			else
1462				ADDTYPE(TP_CHAR);
1463			break;
1464		case 'U':
1465			flags |= LONGINT;
1466			/*FALLTHROUGH*/
1467		case 'u':
1468		case 'X':
1469		case 'x':
1470			ADDUARG();
1471			break;
1472		default:	/* "%?" prints ?, unless ? is NUL */
1473			if (ch == '\0')
1474				goto done;
1475			break;
1476		}
1477	}
1478done:
1479	/*
1480	 * Build the argument table.
1481	 */
1482	if (tablemax >= STATIC_ARG_TBL_SIZE) {
1483		*argtable = (union arg *)
1484		    malloc (sizeof (union arg) * (tablemax + 1));
1485	}
1486
1487	(*argtable) [0].intarg = 0;
1488	for (n = 1; n <= tablemax; n++) {
1489		switch (typetable [n]) {
1490		    case T_UNUSED: /* whoops! */
1491			(*argtable) [n].intarg = va_arg (ap, int);
1492			break;
1493		    case TP_SCHAR:
1494			(*argtable) [n].pschararg = va_arg (ap, signed char *);
1495			break;
1496		    case TP_SHORT:
1497			(*argtable) [n].pshortarg = va_arg (ap, short *);
1498			break;
1499		    case T_INT:
1500			(*argtable) [n].intarg = va_arg (ap, int);
1501			break;
1502		    case T_U_INT:
1503			(*argtable) [n].uintarg = va_arg (ap, unsigned int);
1504			break;
1505		    case TP_INT:
1506			(*argtable) [n].pintarg = va_arg (ap, int *);
1507			break;
1508		    case T_LONG:
1509			(*argtable) [n].longarg = va_arg (ap, long);
1510			break;
1511		    case T_U_LONG:
1512			(*argtable) [n].ulongarg = va_arg (ap, unsigned long);
1513			break;
1514		    case TP_LONG:
1515			(*argtable) [n].plongarg = va_arg (ap, long *);
1516			break;
1517		    case T_LLONG:
1518			(*argtable) [n].longlongarg = va_arg (ap, long long);
1519			break;
1520		    case T_U_LLONG:
1521			(*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long);
1522			break;
1523		    case TP_LLONG:
1524			(*argtable) [n].plonglongarg = va_arg (ap, long long *);
1525			break;
1526		    case T_PTRDIFFT:
1527			(*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t);
1528			break;
1529		    case TP_PTRDIFFT:
1530			(*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *);
1531			break;
1532		    case T_SIZET:
1533			(*argtable) [n].sizearg = va_arg (ap, size_t);
1534			break;
1535		    case TP_SIZET:
1536			(*argtable) [n].psizearg = va_arg (ap, ssize_t *);
1537			break;
1538		    case T_INTMAXT:
1539			(*argtable) [n].intmaxarg = va_arg (ap, intmax_t);
1540			break;
1541		    case T_UINTMAXT:
1542			(*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t);
1543			break;
1544		    case TP_INTMAXT:
1545			(*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *);
1546			break;
1547#ifdef FLOATING_POINT
1548		    case T_DOUBLE:
1549			(*argtable) [n].doublearg = va_arg (ap, double);
1550			break;
1551		    case T_LONG_DOUBLE:
1552			(*argtable) [n].longdoublearg = va_arg (ap, long double);
1553			break;
1554#endif
1555		    case TP_CHAR:
1556			(*argtable) [n].pchararg = va_arg (ap, char *);
1557			break;
1558		    case TP_VOID:
1559			(*argtable) [n].pvoidarg = va_arg (ap, void *);
1560			break;
1561		    case T_WINT:
1562			(*argtable) [n].wintarg = va_arg (ap, wint_t);
1563			break;
1564		    case TP_WCHAR:
1565			(*argtable) [n].pwchararg = va_arg (ap, wchar_t *);
1566			break;
1567		}
1568	}
1569
1570	if ((typetable != NULL) && (typetable != stattypetable))
1571		free (typetable);
1572}
1573
1574/*
1575 * Increase the size of the type table.
1576 */
1577static void
1578__grow_type_table (int nextarg, enum typeid **typetable, int *tablesize)
1579{
1580	enum typeid *const oldtable = *typetable;
1581	const int oldsize = *tablesize;
1582	enum typeid *newtable;
1583	int newsize = oldsize * 2;
1584
1585	if (newsize < nextarg + 1)
1586		newsize = nextarg + 1;
1587	if (oldsize == STATIC_ARG_TBL_SIZE) {
1588		if ((newtable = malloc(newsize)) == NULL)
1589			abort();			/* XXX handle better */
1590		bcopy(oldtable, newtable, oldsize);
1591	} else {
1592		if ((newtable = reallocf(oldtable, newsize)) == NULL)
1593			abort();			/* XXX handle better */
1594	}
1595	memset(&newtable[oldsize], T_UNUSED, newsize - oldsize);
1596
1597	*typetable = newtable;
1598	*tablesize = newsize;
1599}
1600
1601
1602#ifdef FLOATING_POINT
1603
1604static int
1605exponent(char *p0, int exp, int fmtch)
1606{
1607	char *p, *t;
1608	char expbuf[MAXEXPDIG];
1609
1610	p = p0;
1611	*p++ = fmtch;
1612	if (exp < 0) {
1613		exp = -exp;
1614		*p++ = '-';
1615	}
1616	else
1617		*p++ = '+';
1618	t = expbuf + MAXEXPDIG;
1619	if (exp > 9) {
1620		do {
1621			*--t = to_char(exp % 10);
1622		} while ((exp /= 10) > 9);
1623		*--t = to_char(exp);
1624		for (; t < expbuf + MAXEXPDIG; *p++ = *t++);
1625	}
1626	else {
1627		/*
1628		 * Exponents for decimal floating point conversions
1629		 * (%[eEgG]) must be at least two characters long,
1630		 * whereas exponents for hexadecimal conversions can
1631		 * be only one character long.
1632		 */
1633		if (fmtch == 'e' || fmtch == 'E')
1634			*p++ = '0';
1635		*p++ = to_char(exp);
1636	}
1637	return (p - p0);
1638}
1639#endif /* FLOATING_POINT */
1640