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