xref: /openbsd-src/lib/libc/stdio/vfprintf.c (revision 1fc27e414118cd8922c6b93fbaeb7a5246bfd593)
1 /*-
2  * Copyright (c) 1990 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Chris Torek.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #if defined(LIBC_SCCS) && !defined(lint)
38 static char *rcsid = "$OpenBSD: vfprintf.c,v 1.9 1999/08/22 17:06:35 millert Exp $";
39 #endif /* LIBC_SCCS and not lint */
40 
41 /*
42  * Actual printf innards.
43  *
44  * This code is large and complicated...
45  */
46 
47 #include <sys/types.h>
48 
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <errno.h>
53 
54 #ifdef __STDC__
55 #include <stdarg.h>
56 #else
57 #include <varargs.h>
58 #endif
59 
60 #include "local.h"
61 #include "fvwrite.h"
62 
63 static void __find_arguments __P((const char *fmt0, va_list ap,
64 	va_list **argtable));
65 static int __grow_type_table __P((unsigned char **typetable,
66 	int *tablesize));
67 
68 /*
69  * Flush out all the vectors defined by the given uio,
70  * then reset it so that it can be reused.
71  */
72 static int
73 __sprint(fp, uio)
74 	FILE *fp;
75 	register struct __suio *uio;
76 {
77 	register int err;
78 
79 	if (uio->uio_resid == 0) {
80 		uio->uio_iovcnt = 0;
81 		return (0);
82 	}
83 	err = __sfvwrite(fp, uio);
84 	uio->uio_resid = 0;
85 	uio->uio_iovcnt = 0;
86 	return (err);
87 }
88 
89 /*
90  * Helper function for `fprintf to unbuffered unix file': creates a
91  * temporary buffer.  We only work on write-only files; this avoids
92  * worries about ungetc buffers and so forth.
93  */
94 static int
95 __sbprintf(fp, fmt, ap)
96 	register FILE *fp;
97 	const char *fmt;
98 	va_list ap;
99 {
100 	int ret;
101 	FILE fake;
102 	unsigned char buf[BUFSIZ];
103 
104 	/* copy the important variables */
105 	fake._flags = fp->_flags & ~__SNBF;
106 	fake._file = fp->_file;
107 	fake._cookie = fp->_cookie;
108 	fake._write = fp->_write;
109 
110 	/* set up the buffer */
111 	fake._bf._base = fake._p = buf;
112 	fake._bf._size = fake._w = sizeof(buf);
113 	fake._lbfsize = 0;	/* not actually used, but Just In Case */
114 
115 	/* do the work, then copy any error status */
116 	ret = vfprintf(&fake, fmt, ap);
117 	if (ret >= 0 && fflush(&fake))
118 		ret = EOF;
119 	if (fake._flags & __SERR)
120 		fp->_flags |= __SERR;
121 	return (ret);
122 }
123 
124 
125 #ifdef FLOATING_POINT
126 #include <locale.h>
127 #include <math.h>
128 #include "floatio.h"
129 
130 #define	BUF		(MAXEXP+MAXFRACT+1)	/* + decimal point */
131 #define	DEFPREC		6
132 
133 static char *cvt __P((double, int, int, char *, int *, int, int *));
134 static int exponent __P((char *, int, int));
135 
136 #else /* no FLOATING_POINT */
137 #define	BUF		40
138 #endif /* FLOATING_POINT */
139 
140 #define STATIC_ARG_TBL_SIZE 8	/* Size of static argument table. */
141 
142 
143 /*
144  * Macros for converting digits to letters and vice versa
145  */
146 #define	to_digit(c)	((c) - '0')
147 #define is_digit(c)	((unsigned)to_digit(c) <= 9)
148 #define	to_char(n)	((n) + '0')
149 
150 /*
151  * Flags used during conversion.
152  */
153 #define	ALT		0x001		/* alternate form */
154 #define	HEXPREFIX	0x002		/* add 0x or 0X prefix */
155 #define	LADJUST		0x004		/* left adjustment */
156 #define	LONGDBL		0x008		/* long double; unimplemented */
157 #define	LONGINT		0x010		/* long integer */
158 #define	QUADINT		0x020		/* quad integer */
159 #define	SHORTINT	0x040		/* short integer */
160 #define	ZEROPAD		0x080		/* zero (as opposed to blank) pad */
161 #define FPT		0x100		/* Floating point number */
162 int
163 vfprintf(fp, fmt0, ap)
164 	FILE *fp;
165 	const char *fmt0;
166 	_BSD_VA_LIST_ ap;
167 {
168 	register char *fmt;	/* format string */
169 	register int ch;	/* character from fmt */
170 	register int n, m, n2;	/* handy integers (short term usage) */
171 	register char *cp;	/* handy char pointer (short term usage) */
172 	register struct __siov *iovp;/* for PRINT macro */
173 	register int flags;	/* flags as above */
174 	int ret;		/* return value accumulator */
175 	int width;		/* width from format (%8d), or 0 */
176 	int prec;		/* precision from format (%.3d), or -1 */
177 	char sign;		/* sign prefix (' ', '+', '-', or \0) */
178 	wchar_t wc;
179 #ifdef FLOATING_POINT
180 	char *decimal_point = localeconv()->decimal_point;
181 	char softsign;		/* temporary negative sign for floats */
182 	double _double;		/* double precision arguments %[eEfgG] */
183 	int expt;		/* integer value of exponent */
184 	int expsize;		/* character count for expstr */
185 	int ndig;		/* actual number of digits returned by cvt */
186 	char expstr[7];		/* buffer for exponent string */
187 #endif
188 
189 #ifdef __GNUC__			/* gcc has builtin quad type (long long) SOS */
190 #define	quad_t	  long long
191 #define	u_quad_t  unsigned long long
192 #endif
193 
194 	u_quad_t _uquad;	/* integer arguments %[diouxX] */
195 	enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
196 	int dprec;		/* a copy of prec if [diouxX], 0 otherwise */
197 	int realsz;		/* field size expanded by dprec */
198 	int size;		/* size of converted field or string */
199 	char *xdigs;		/* digits for [xX] conversion */
200 #define NIOV 8
201 	struct __suio uio;	/* output information: summary */
202 	struct __siov iov[NIOV];/* ... and individual io vectors */
203 	char buf[BUF];		/* space for %c, %[diouxX], %[eEfgG] */
204 	char ox[2];		/* space for 0x hex-prefix */
205 	va_list *argtable;        /* args, built due to positional arg */
206 	va_list statargtable[STATIC_ARG_TBL_SIZE];
207 	int nextarg;            /* 1-based argument index */
208 	va_list orgap;          /* original argument pointer */
209 
210 	/*
211 	 * Choose PADSIZE to trade efficiency vs. size.  If larger printf
212 	 * fields occur frequently, increase PADSIZE and make the initialisers
213 	 * below longer.
214 	 */
215 #define	PADSIZE	16		/* pad chunk size */
216 	static char blanks[PADSIZE] =
217 	 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
218 	static char zeroes[PADSIZE] =
219 	 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
220 
221 	/*
222 	 * BEWARE, these `goto error' on error, and PAD uses `n'.
223 	 */
224 #define	PRINT(ptr, len) do { \
225 	iovp->iov_base = (ptr); \
226 	iovp->iov_len = (len); \
227 	uio.uio_resid += (len); \
228 	iovp++; \
229 	if (++uio.uio_iovcnt >= NIOV) { \
230 		if (__sprint(fp, &uio)) \
231 			goto error; \
232 		iovp = iov; \
233 	} \
234 } while (0)
235 #define	PAD(howmany, with) do { \
236 	if ((n = (howmany)) > 0) { \
237 		while (n > PADSIZE) { \
238 			PRINT(with, PADSIZE); \
239 			n -= PADSIZE; \
240 		} \
241 		PRINT(with, n); \
242 	} \
243 } while (0)
244 #define	FLUSH() do { \
245 	if (uio.uio_resid && __sprint(fp, &uio)) \
246 		goto error; \
247 	uio.uio_iovcnt = 0; \
248 	iovp = iov; \
249 } while (0)
250 
251 	/*
252 	 * To extend shorts properly, we need both signed and unsigned
253 	 * argument extraction methods.
254 	 */
255 #define	SARG() \
256 	(flags&QUADINT ? va_arg(ap, quad_t) : \
257 	    flags&LONGINT ? GETARG(long) : \
258 	    flags&SHORTINT ? (long)(short)GETARG(int) : \
259 	    (long)GETARG(int))
260 #define	UARG() \
261 	(flags&QUADINT ? va_arg(ap, u_quad_t) : \
262 	    flags&LONGINT ? GETARG(u_long) : \
263 	    flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
264 	    (u_long)GETARG(u_int))
265 
266          /*
267           * Get * arguments, including the form *nn$.  Preserve the nextarg
268           * that the argument can be gotten once the type is determined.
269           */
270 #define GETASTER(val) \
271 	 n2 = 0; \
272 	 cp = fmt; \
273 	 while (is_digit(*cp)) { \
274 		 n2 = 10 * n2 + to_digit(*cp); \
275 		 cp++; \
276 	 } \
277 	 if (*cp == '$') { \
278 	       int hold = nextarg; \
279 		 if (argtable == NULL) { \
280 			 argtable = statargtable; \
281 			 __find_arguments (fmt0, orgap, &argtable); \
282 		 } \
283 		 nextarg = n2; \
284 		 val = GETARG(int); \
285 		 nextarg = hold; \
286 		 fmt = ++cp; \
287 	} \
288 	else { \
289 	       val = GETARG(int); \
290 	 }
291 
292 /*
293 * Get the argument indexed by nextarg.   If the argument table is
294 * built, use it to get the argument.  If its not, get the next
295 * argument (and arguments must be gotten sequentially).
296 */
297 #define GETARG(type) \
298 	(((argtable != NULL) ? (void)(ap = argtable[nextarg]) : (void)0), \
299 	 nextarg++, va_arg(ap, type))
300 
301 	/* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
302 	if (cantwrite(fp)) {
303 		errno = EBADF;
304 		return (EOF);
305 	}
306 
307 	/* optimise fprintf(stderr) (and other unbuffered Unix files) */
308 	if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
309 	    fp->_file >= 0)
310 		return (__sbprintf(fp, fmt0, ap));
311 
312 	fmt = (char *)fmt0;
313 	argtable = NULL;
314 	nextarg = 1;
315 	orgap = ap;
316 	uio.uio_iov = iovp = iov;
317 	uio.uio_resid = 0;
318 	uio.uio_iovcnt = 0;
319 	ret = 0;
320 
321 	/*
322 	 * Scan the format for conversions (`%' character).
323 	 */
324 	for (;;) {
325 		cp = fmt;
326 		while ((n = mbtowc(&wc, fmt, MB_CUR_MAX)) > 0) {
327 			fmt += n;
328 			if (wc == '%') {
329 				fmt--;
330 				break;
331 			}
332 		}
333 		if ((m = fmt - cp) != 0) {
334 			PRINT(cp, m);
335 			ret += m;
336 		}
337 		if (n <= 0)
338 			goto done;
339 		fmt++;		/* skip over '%' */
340 
341 		flags = 0;
342 		dprec = 0;
343 		width = 0;
344 		prec = -1;
345 		sign = '\0';
346 
347 rflag:		ch = *fmt++;
348 reswitch:	switch (ch) {
349 		case ' ':
350 			/*
351 			 * ``If the space and + flags both appear, the space
352 			 * flag will be ignored.''
353 			 *	-- ANSI X3J11
354 			 */
355 			if (!sign)
356 				sign = ' ';
357 			goto rflag;
358 		case '#':
359 			flags |= ALT;
360 			goto rflag;
361 		case '*':
362 			/*
363 			 * ``A negative field width argument is taken as a
364 			 * - flag followed by a positive field width.''
365 			 *	-- ANSI X3J11
366 			 * They don't exclude field widths read from args.
367 			 */
368 			GETASTER(width);
369 			if (width >= 0)
370 				goto rflag;
371 			width = -width;
372 			/* FALLTHROUGH */
373 		case '-':
374 			flags |= LADJUST;
375 			goto rflag;
376 		case '+':
377 			sign = '+';
378 			goto rflag;
379 		case '.':
380 			if ((ch = *fmt++) == '*') {
381 				GETASTER(n);
382 				prec = n < 0 ? -1 : n;
383 				goto rflag;
384 			}
385 			n = 0;
386 			while (is_digit(ch)) {
387 				n = 10 * n + to_digit(ch);
388 				ch = *fmt++;
389 			}
390 			if (ch == '$') {
391 				nextarg = n;
392 				if (argtable == NULL) {
393 					argtable = statargtable;
394 					__find_arguments(fmt0, orgap,
395 					    &argtable);
396 				}
397 				goto rflag;
398 			}
399 			prec = n < 0 ? -1 : n;
400 			goto reswitch;
401 		case '0':
402 			/*
403 			 * ``Note that 0 is taken as a flag, not as the
404 			 * beginning of a field width.''
405 			 *	-- ANSI X3J11
406 			 */
407 			flags |= ZEROPAD;
408 			goto rflag;
409 		case '1': case '2': case '3': case '4':
410 		case '5': case '6': case '7': case '8': case '9':
411 			n = 0;
412 			do {
413 				n = 10 * n + to_digit(ch);
414 				ch = *fmt++;
415 			} while (is_digit(ch));
416                        	if (ch == '$') {
417 				nextarg = n;
418 			   	if (argtable == NULL) {
419 			   		argtable = statargtable;
420 			   		__find_arguments (fmt0, orgap,
421 					    &argtable);
422 			  	}
423 				goto rflag;
424 			}
425 			width = n;
426 			goto reswitch;
427 #ifdef FLOATING_POINT
428 		case 'L':
429 			flags |= LONGDBL;
430 			goto rflag;
431 #endif
432 		case 'h':
433 			flags |= SHORTINT;
434 			goto rflag;
435 		case 'l':
436 			if (*fmt == 'l') {
437 				fmt++;
438 				flags |= QUADINT;
439 			} else {
440 				flags |= LONGINT;
441 			}
442 			goto rflag;
443 		case 'q':
444 			flags |= QUADINT;
445 			goto rflag;
446 		case 'c':
447 			*(cp = buf) = GETARG(int);
448 			size = 1;
449 			sign = '\0';
450 			break;
451 		case 'D':
452 			flags |= LONGINT;
453 			/*FALLTHROUGH*/
454 		case 'd':
455 		case 'i':
456 			_uquad = SARG();
457 			if ((quad_t)_uquad < 0) {
458 				_uquad = -_uquad;
459 				sign = '-';
460 			}
461 			base = DEC;
462 			goto number;
463 #ifdef FLOATING_POINT
464 		case 'e':
465 		case 'E':
466 		case 'f':
467 		case 'g':
468 		case 'G':
469 			if (prec == -1) {
470 				prec = DEFPREC;
471 			} else if ((ch == 'g' || ch == 'G') && prec == 0) {
472 				prec = 1;
473 			}
474 
475 			if (flags & LONGDBL) {
476 				_double = (double) GETARG(long double);
477 			} else {
478 				_double = GETARG(double);
479 			}
480 
481 			/* do this before tricky precision changes */
482 			if (isinf(_double)) {
483 				if (_double < 0)
484 					sign = '-';
485 				cp = "Inf";
486 				size = 3;
487 				break;
488 			}
489 			if (isnan(_double)) {
490 				cp = "NaN";
491 				size = 3;
492 				break;
493 			}
494 
495 			flags |= FPT;
496 			cp = cvt(_double, prec, flags, &softsign,
497 				&expt, ch, &ndig);
498 			if (ch == 'g' || ch == 'G') {
499 				if (expt <= -4 || expt > prec)
500 					ch = (ch == 'g') ? 'e' : 'E';
501 				else
502 					ch = 'g';
503 			}
504 			if (ch <= 'e') {	/* 'e' or 'E' fmt */
505 				--expt;
506 				expsize = exponent(expstr, expt, ch);
507 				size = expsize + ndig;
508 				if (ndig > 1 || flags & ALT)
509 					++size;
510 			} else if (ch == 'f') {		/* f fmt */
511 				if (expt > 0) {
512 					size = expt;
513 					if (prec || flags & ALT)
514 						size += prec + 1;
515 				} else	/* "0.X" */
516 					size = prec + 2;
517 			} else if (expt >= ndig) {	/* fixed g fmt */
518 				size = expt;
519 				if (flags & ALT)
520 					++size;
521 			} else
522 				size = ndig + (expt > 0 ?
523 					1 : 2 - expt);
524 
525 			if (softsign)
526 				sign = '-';
527 			break;
528 #endif /* FLOATING_POINT */
529 		case 'n':
530 			if (flags & QUADINT)
531 				*GETARG(quad_t *) = ret;
532 			else if (flags & LONGINT)
533 				*GETARG(long *) = ret;
534 			else if (flags & SHORTINT)
535 				*GETARG(short *) = ret;
536 			else
537 				*GETARG(int *) = ret;
538 			continue;	/* no output */
539 		case 'O':
540 			flags |= LONGINT;
541 			/*FALLTHROUGH*/
542 		case 'o':
543 			_uquad = UARG();
544 			base = OCT;
545 			goto nosign;
546 		case 'p':
547 			/*
548 			 * ``The argument shall be a pointer to void.  The
549 			 * value of the pointer is converted to a sequence
550 			 * of printable characters, in an implementation-
551 			 * defined manner.''
552 			 *	-- ANSI X3J11
553 			 */
554 			/* NOSTRICT */
555 			_uquad = (u_long)GETARG(void *);
556 			base = HEX;
557 			xdigs = "0123456789abcdef";
558 			flags |= HEXPREFIX;
559 			ch = 'x';
560 			goto nosign;
561 		case 's':
562 			if ((cp = GETARG(char *)) == NULL)
563 				cp = "(null)";
564 			if (prec >= 0) {
565 				/*
566 				 * can't use strlen; can only look for the
567 				 * NUL in the first `prec' characters, and
568 				 * strlen() will go further.
569 				 */
570 				char *p = memchr(cp, 0, prec);
571 
572 				if (p != NULL) {
573 					size = p - cp;
574 					if (size > prec)
575 						size = prec;
576 				} else
577 					size = prec;
578 			} else
579 				size = strlen(cp);
580 			sign = '\0';
581 			break;
582 		case 'U':
583 			flags |= LONGINT;
584 			/*FALLTHROUGH*/
585 		case 'u':
586 			_uquad = UARG();
587 			base = DEC;
588 			goto nosign;
589 		case 'X':
590 			xdigs = "0123456789ABCDEF";
591 			goto hex;
592 		case 'x':
593 			xdigs = "0123456789abcdef";
594 hex:			_uquad = UARG();
595 			base = HEX;
596 			/* leading 0x/X only if non-zero */
597 			if (flags & ALT && _uquad != 0)
598 				flags |= HEXPREFIX;
599 
600 			/* unsigned conversions */
601 nosign:			sign = '\0';
602 			/*
603 			 * ``... diouXx conversions ... if a precision is
604 			 * specified, the 0 flag will be ignored.''
605 			 *	-- ANSI X3J11
606 			 */
607 number:			if ((dprec = prec) >= 0)
608 				flags &= ~ZEROPAD;
609 
610 			/*
611 			 * ``The result of converting a zero value with an
612 			 * explicit precision of zero is no characters.''
613 			 *	-- ANSI X3J11
614 			 */
615 			cp = buf + BUF;
616 			if (_uquad != 0 || prec != 0) {
617 				/*
618 				 * Unsigned mod is hard, and unsigned mod
619 				 * by a constant is easier than that by
620 				 * a variable; hence this switch.
621 				 */
622 				switch (base) {
623 				case OCT:
624 					do {
625 						*--cp = to_char(_uquad & 7);
626 						_uquad >>= 3;
627 					} while (_uquad);
628 					/* handle octal leading 0 */
629 					if (flags & ALT && *cp != '0')
630 						*--cp = '0';
631 					break;
632 
633 				case DEC:
634 					/* many numbers are 1 digit */
635 					while (_uquad >= 10) {
636 						*--cp = to_char(_uquad % 10);
637 						_uquad /= 10;
638 					}
639 					*--cp = to_char(_uquad);
640 					break;
641 
642 				case HEX:
643 					do {
644 						*--cp = xdigs[_uquad & 15];
645 						_uquad >>= 4;
646 					} while (_uquad);
647 					break;
648 
649 				default:
650 					cp = "bug in vfprintf: bad base";
651 					size = strlen(cp);
652 					goto skipsize;
653 				}
654 			}
655 			size = buf + BUF - cp;
656 		skipsize:
657 			break;
658 		default:	/* "%?" prints ?, unless ? is NUL */
659 			if (ch == '\0')
660 				goto done;
661 			/* pretend it was %c with argument ch */
662 			cp = buf;
663 			*cp = ch;
664 			size = 1;
665 			sign = '\0';
666 			break;
667 		}
668 
669 		/*
670 		 * All reasonable formats wind up here.  At this point, `cp'
671 		 * points to a string which (if not flags&LADJUST) should be
672 		 * padded out to `width' places.  If flags&ZEROPAD, it should
673 		 * first be prefixed by any sign or other prefix; otherwise,
674 		 * it should be blank padded before the prefix is emitted.
675 		 * After any left-hand padding and prefixing, emit zeroes
676 		 * required by a decimal [diouxX] precision, then print the
677 		 * string proper, then emit zeroes required by any leftover
678 		 * floating precision; finally, if LADJUST, pad with blanks.
679 		 *
680 		 * Compute actual size, so we know how much to pad.
681 		 * size excludes decimal prec; realsz includes it.
682 		 */
683 		realsz = dprec > size ? dprec : size;
684 		if (sign)
685 			realsz++;
686 		else if (flags & HEXPREFIX)
687 			realsz+= 2;
688 
689 		/* right-adjusting blank padding */
690 		if ((flags & (LADJUST|ZEROPAD)) == 0)
691 			PAD(width - realsz, blanks);
692 
693 		/* prefix */
694 		if (sign) {
695 			PRINT(&sign, 1);
696 		} else if (flags & HEXPREFIX) {
697 			ox[0] = '0';
698 			ox[1] = ch;
699 			PRINT(ox, 2);
700 		}
701 
702 		/* right-adjusting zero padding */
703 		if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
704 			PAD(width - realsz, zeroes);
705 
706 		/* leading zeroes from decimal precision */
707 		PAD(dprec - size, zeroes);
708 
709 		/* the string or number proper */
710 #ifdef FLOATING_POINT
711 		if ((flags & FPT) == 0) {
712 			PRINT(cp, size);
713 		} else {	/* glue together f_p fragments */
714 			if (ch >= 'f') {	/* 'f' or 'g' */
715 				if (_double == 0) {
716 					/* kludge for __dtoa irregularity */
717 					PRINT("0", 1);
718 					if (expt < ndig || (flags & ALT) != 0) {
719 						PRINT(decimal_point, 1);
720 						PAD(ndig - 1, zeroes);
721 					}
722 				} else if (expt <= 0) {
723 					PRINT("0", 1);
724 					PRINT(decimal_point, 1);
725 					PAD(-expt, zeroes);
726 					PRINT(cp, ndig);
727 				} else if (expt >= ndig) {
728 					PRINT(cp, ndig);
729 					PAD(expt - ndig, zeroes);
730 					if (flags & ALT)
731 						PRINT(".", 1);
732 				} else {
733 					PRINT(cp, expt);
734 					cp += expt;
735 					PRINT(".", 1);
736 					PRINT(cp, ndig-expt);
737 				}
738 			} else {	/* 'e' or 'E' */
739 				if (ndig > 1 || flags & ALT) {
740 					ox[0] = *cp++;
741 					ox[1] = '.';
742 					PRINT(ox, 2);
743 					if (_double || flags & ALT == 0) {
744 						PRINT(cp, ndig-1);
745 					} else	/* 0.[0..] */
746 						/* __dtoa irregularity */
747 						PAD(ndig - 1, zeroes);
748 				} else	/* XeYYY */
749 					PRINT(cp, 1);
750 				PRINT(expstr, expsize);
751 			}
752 		}
753 #else
754 		PRINT(cp, size);
755 #endif
756 		/* left-adjusting padding (always blank) */
757 		if (flags & LADJUST)
758 			PAD(width - realsz, blanks);
759 
760 		/* finally, adjust ret */
761 		ret += width > realsz ? width : realsz;
762 
763 		FLUSH();	/* copy out the I/O vectors */
764 	}
765 done:
766 	FLUSH();
767 error:
768 	if ((argtable != NULL) && (argtable != statargtable))
769 		free (argtable);
770 	return (__sferror(fp) ? EOF : ret);
771 	/* NOTREACHED */
772 }
773 
774 /*
775  * Type ids for argument type table.
776  */
777 #define T_UNUSED	0
778 #define T_SHORT		1
779 #define T_U_SHORT	2
780 #define TP_SHORT	3
781 #define T_INT		4
782 #define T_U_INT		5
783 #define TP_INT		6
784 #define T_LONG		7
785 #define T_U_LONG	8
786 #define TP_LONG		9
787 #define T_QUAD		10
788 #define T_U_QUAD      	11
789 #define TP_QUAD         12
790 #define T_DOUBLE      	13
791 #define T_LONG_DOUBLE 	14
792 #define TP_CHAR		15
793 #define TP_VOID		16
794 
795 /*
796  * Find all arguments when a positional parameter is encountered.  Returns a
797  * table, indexed by argument number, of pointers to each arguments.  The
798  * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
799  * It will be replaces with a malloc-ed on if it overflows.
800  */
801 static void
802 __find_arguments (fmt0, ap, argtable)
803 	const char *fmt0;
804 	va_list ap;
805 	va_list **argtable;
806 {
807 	register char *fmt;	/* format string */
808 	register int ch;	/* character from fmt */
809 	register int n, n2;	/* handy integer (short term usage) */
810 	register char *cp;	/* handy char pointer (short term usage) */
811 	register int flags;	/* flags as above */
812 	unsigned char *typetable; /* table of types */
813 	unsigned char stattypetable[STATIC_ARG_TBL_SIZE];
814 	int tablesize;		/* current size of type table */
815 	int tablemax;		/* largest used index in table */
816 	int nextarg;		/* 1-based argument index */
817 
818 	/*
819 	 * Add an argument type to the table, expanding if necessary.
820 	 */
821 #define ADDTYPE(type) \
822 	((nextarg >= tablesize) ? \
823 		__grow_type_table(&typetable, &tablesize) : 0, \
824 	typetable[nextarg++] = type, \
825 	(nextarg > tablemax) ? tablemax = nextarg : 0)
826 
827 #define	ADDSARG() \
828 	((flags&LONGINT) ? ADDTYPE(T_LONG) : \
829 		((flags&SHORTINT) ? ADDTYPE(T_SHORT) : ADDTYPE(T_INT)))
830 
831 #define	ADDUARG() \
832 	((flags&LONGINT) ? ADDTYPE(T_U_LONG) : \
833 		((flags&SHORTINT) ? ADDTYPE(T_U_SHORT) : ADDTYPE(T_U_INT)))
834 
835 	/*
836 	 * Add * arguments to the type array.
837 	 */
838 #define ADDASTER() \
839 	n2 = 0; \
840 	cp = fmt; \
841 	while (is_digit(*cp)) { \
842 		n2 = 10 * n2 + to_digit(*cp); \
843 		cp++; \
844 	} \
845 	if (*cp == '$') { \
846 		int hold = nextarg; \
847 		nextarg = n2; \
848 		ADDTYPE (T_INT); \
849 		nextarg = hold; \
850 		fmt = ++cp; \
851 	} else { \
852 		ADDTYPE (T_INT); \
853 	}
854 	fmt = (char *)fmt0;
855 	typetable = stattypetable;
856 	tablesize = STATIC_ARG_TBL_SIZE;
857 	tablemax = 0;
858 	nextarg = 1;
859 	memset (typetable, T_UNUSED, STATIC_ARG_TBL_SIZE);
860 
861 	/*
862 	 * Scan the format for conversions (`%' character).
863 	 */
864 	for (;;) {
865 		for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
866 			/* void */;
867 		if (ch == '\0')
868 			goto done;
869 		fmt++;		/* skip over '%' */
870 
871 		flags = 0;
872 
873 rflag:		ch = *fmt++;
874 reswitch:	switch (ch) {
875 		case ' ':
876 		case '#':
877 			goto rflag;
878 		case '*':
879 			ADDASTER ();
880 			goto rflag;
881 		case '-':
882 		case '+':
883 			goto rflag;
884 		case '.':
885 			if ((ch = *fmt++) == '*') {
886 				ADDASTER ();
887 				goto rflag;
888 			}
889 			while (is_digit(ch)) {
890 				ch = *fmt++;
891 			}
892 			goto reswitch;
893 		case '0':
894 			goto rflag;
895 		case '1': case '2': case '3': case '4':
896 		case '5': case '6': case '7': case '8': case '9':
897 			n = 0;
898 			do {
899 				n = 10 * n + to_digit(ch);
900 				ch = *fmt++;
901 			} while (is_digit(ch));
902 			if (ch == '$') {
903 				nextarg = n;
904 				goto rflag;
905 			}
906 			goto reswitch;
907 #ifdef FLOATING_POINT
908 		case 'L':
909 			flags |= LONGDBL;
910 			goto rflag;
911 #endif
912 		case 'h':
913 			flags |= SHORTINT;
914 			goto rflag;
915 		case 'l':
916 			flags |= LONGINT;
917 			goto rflag;
918 		case 'q':
919 			flags |= QUADINT;
920 			goto rflag;
921 		case 'c':
922 			ADDTYPE(T_INT);
923 			break;
924 		case 'D':
925 			flags |= LONGINT;
926 			/*FALLTHROUGH*/
927 		case 'd':
928 		case 'i':
929 			if (flags & QUADINT) {
930 				ADDTYPE(T_QUAD);
931 			} else {
932 				ADDSARG();
933 			}
934 			break;
935 #ifdef FLOATING_POINT
936 		case 'e':
937 		case 'E':
938 		case 'f':
939 		case 'g':
940 		case 'G':
941 			if (flags & LONGDBL)
942 				ADDTYPE(T_LONG_DOUBLE);
943 			else
944 				ADDTYPE(T_DOUBLE);
945 			break;
946 #endif /* FLOATING_POINT */
947 		case 'n':
948 			if (flags & QUADINT)
949 				ADDTYPE(TP_QUAD);
950 			else if (flags & LONGINT)
951 				ADDTYPE(TP_LONG);
952 			else if (flags & SHORTINT)
953 				ADDTYPE(TP_SHORT);
954 			else
955 				ADDTYPE(TP_INT);
956 			continue;	/* no output */
957 		case 'O':
958 			flags |= LONGINT;
959 			/*FALLTHROUGH*/
960 		case 'o':
961 			if (flags & QUADINT)
962 				ADDTYPE(T_U_QUAD);
963 			else
964 				ADDUARG();
965 			break;
966 		case 'p':
967 			ADDTYPE(TP_VOID);
968 			break;
969 		case 's':
970 			ADDTYPE(TP_CHAR);
971 			break;
972 		case 'U':
973 			flags |= LONGINT;
974 			/*FALLTHROUGH*/
975 		case 'u':
976 			if (flags & QUADINT)
977 				ADDTYPE(T_U_QUAD);
978 			else
979 				ADDUARG();
980 			break;
981 		case 'X':
982 		case 'x':
983 			if (flags & QUADINT)
984 				ADDTYPE(T_U_QUAD);
985 			else
986 				ADDUARG();
987 			break;
988 		default:	/* "%?" prints ?, unless ? is NUL */
989 			if (ch == '\0')
990 				goto done;
991 			break;
992 		}
993 	}
994 done:
995 	/*
996 	 * Build the argument table.
997 	 */
998 	if (tablemax >= STATIC_ARG_TBL_SIZE) {
999 		*argtable = (va_list *)
1000 		    malloc (sizeof (va_list) * (tablemax + 1));
1001 	}
1002 
1003 #if 0
1004 	/* XXX is this required? */
1005 	(*argtable) [0] = NULL;
1006 #endif
1007 	for (n = 1; n <= tablemax; n++) {
1008 		(*argtable) [n] = ap;
1009 		switch (typetable [n]) {
1010 		    case T_UNUSED:
1011 			(void) va_arg (ap, int);
1012 			break;
1013 		    case T_SHORT:
1014 			(void) va_arg (ap, int);
1015 			break;
1016 		    case T_U_SHORT:
1017 			(void) va_arg (ap, int);
1018 			break;
1019 		    case TP_SHORT:
1020 			(void) va_arg (ap, short *);
1021 			break;
1022 		    case T_INT:
1023 			(void) va_arg (ap, int);
1024 			break;
1025 		    case T_U_INT:
1026 			(void) va_arg (ap, unsigned int);
1027 			break;
1028 		    case TP_INT:
1029 			(void) va_arg (ap, int *);
1030 			break;
1031 		    case T_LONG:
1032 			(void) va_arg (ap, long);
1033 			break;
1034 		    case T_U_LONG:
1035 			(void) va_arg (ap, unsigned long);
1036 			break;
1037 		    case TP_LONG:
1038 			(void) va_arg (ap, long *);
1039 			break;
1040 		    case T_QUAD:
1041 			(void) va_arg (ap, quad_t);
1042 			break;
1043 		    case T_U_QUAD:
1044 			(void) va_arg (ap, u_quad_t);
1045 			break;
1046 		    case TP_QUAD:
1047 			(void) va_arg (ap, quad_t *);
1048 			break;
1049 		    case T_DOUBLE:
1050 			(void) va_arg (ap, double);
1051 			break;
1052 		    case T_LONG_DOUBLE:
1053 			(void) va_arg (ap, long double);
1054 			break;
1055 		    case TP_CHAR:
1056 			(void) va_arg (ap, char *);
1057 			break;
1058 		    case TP_VOID:
1059 			(void) va_arg (ap, void *);
1060 			break;
1061 		}
1062 	}
1063 
1064 	if ((typetable != NULL) && (typetable != stattypetable))
1065 		free (typetable);
1066 }
1067 
1068 /*
1069  * Increase the size of the type table.
1070  */
1071 static int
1072 __grow_type_table(typetable, tablesize)
1073 	unsigned char **typetable;
1074 	int *tablesize;
1075 {
1076 	unsigned char *oldtable = *typetable;
1077 	int newsize = *tablesize * 2;
1078 
1079 	if (*tablesize == STATIC_ARG_TBL_SIZE) {
1080 		*typetable = (unsigned char *)
1081 		    malloc (sizeof (unsigned char) * newsize);
1082 		bcopy (oldtable, *typetable, *tablesize);
1083 	} else {
1084 		*typetable = (unsigned char *)
1085 		    realloc (typetable, sizeof (unsigned char) * newsize);
1086 		/* XXX unchecked */
1087 	}
1088 	memset (&typetable [*tablesize], T_UNUSED, (newsize - *tablesize));
1089 
1090 	*tablesize = newsize;
1091 	return(0);
1092 }
1093 
1094 
1095 #ifdef FLOATING_POINT
1096 
1097 extern char *__dtoa __P((double, int, int, int *, int *, char **));
1098 
1099 static char *
1100 cvt(value, ndigits, flags, sign, decpt, ch, length)
1101 	double value;
1102 	int ndigits, flags, *decpt, ch, *length;
1103 	char *sign;
1104 {
1105 	int mode, dsgn;
1106 	char *digits, *bp, *rve;
1107 
1108 	if (ch == 'f') {
1109 		mode = 3;		/* ndigits after the decimal point */
1110 	} else {
1111 		/* To obtain ndigits after the decimal point for the 'e'
1112 		 * and 'E' formats, round to ndigits + 1 significant
1113 		 * figures.
1114 		 */
1115 		if (ch == 'e' || ch == 'E') {
1116 			ndigits++;
1117 		}
1118 		mode = 2;		/* ndigits significant digits */
1119 	}
1120 
1121 	if (value < 0) {
1122 		value = -value;
1123 		*sign = '-';
1124 	} else
1125 		*sign = '\000';
1126 	digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
1127 	if ((ch != 'g' && ch != 'G') || flags & ALT) {	/* Print trailing zeros */
1128 		bp = digits + ndigits;
1129 		if (ch == 'f') {
1130 			if (*digits == '0' && value)
1131 				*decpt = -ndigits + 1;
1132 			bp += *decpt;
1133 		}
1134 		if (value == 0)	/* kludge for __dtoa irregularity */
1135 			rve = bp;
1136 		while (rve < bp)
1137 			*rve++ = '0';
1138 	}
1139 	*length = rve - digits;
1140 	return (digits);
1141 }
1142 
1143 static int
1144 exponent(p0, exp, fmtch)
1145 	char *p0;
1146 	int exp, fmtch;
1147 {
1148 	register char *p, *t;
1149 	char expbuf[MAXEXP];
1150 
1151 	p = p0;
1152 	*p++ = fmtch;
1153 	if (exp < 0) {
1154 		exp = -exp;
1155 		*p++ = '-';
1156 	}
1157 	else
1158 		*p++ = '+';
1159 	t = expbuf + MAXEXP;
1160 	if (exp > 9) {
1161 		do {
1162 			*--t = to_char(exp % 10);
1163 		} while ((exp /= 10) > 9);
1164 		*--t = to_char(exp);
1165 		for (; t < expbuf + MAXEXP; *p++ = *t++);
1166 	}
1167 	else {
1168 		*p++ = '0';
1169 		*p++ = to_char(exp);
1170 	}
1171 	return (p - p0);
1172 }
1173 #endif /* FLOATING_POINT */
1174