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