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