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