blob: b1011456a5ea9d576ede4dc119b07fc75e5cda54 [file] [log] [blame]
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001/* $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
54static void __find_arguments(const char *fmt0, va_list ap, va_list **argtable,
55 size_t *argtablesiz);
56static 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 */
62static 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 */
82static 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 */
Kenny Rootf5823402011-02-12 07:13:44 -0800103 ret = __vfprintf(&fake, fmt, ap);
104 if (ret >= 0 && __sflush(&fake))
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800105 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
120static char *cvt(double, int, int, char *, int *, int, int *);
121static 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
130static int _my_isinf(double);
131static 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
158int
159vfprintf(FILE *fp, const char *fmt0, __va_list ap)
160{
Kenny Rootf5823402011-02-12 07:13:44 -0800161 int ret;
162
163 FLOCKFILE(fp);
164 ret = __vfprintf(fp, fmt0, ap);
165 FUNLOCKFILE(fp);
166 return (ret);
167}
168
169int
170__vfprintf(FILE *fp, const char *fmt0, __va_list ap)
171{
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800172 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 */
Glenn Kasten0946b1f2011-01-09 11:28:22 -0800217 static const char blanks[PADSIZE] =
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800218 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
Glenn Kasten0946b1f2011-01-09 11:28:22 -0800219 static const char zeroes[PADSIZE] =
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800220 {'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
368rflag: ch = *fmt++;
369reswitch: 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':
Elliott Hughes1d13c642013-09-23 16:02:39 -0700454 if (*fmt == 'h') {
455 fmt++;
456 flags |= CHARINT;
457 } else {
458 flags |= SHORTINT;
459 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800460 goto rflag;
461 case 'j':
462 flags |= MAXINT;
463 goto rflag;
464 case 'l':
465 if (*fmt == 'l') {
466 fmt++;
467 flags |= LLONGINT;
468 } else {
469 flags |= LONGINT;
470 }
471 goto rflag;
472 case 'q':
473 flags |= LLONGINT;
474 goto rflag;
475 case 't':
476 flags |= PTRINT;
477 goto rflag;
478 case 'z':
479 flags |= SIZEINT;
480 goto rflag;
481 case 'c':
482 *(cp = buf) = GETARG(int);
483 size = 1;
484 sign = '\0';
485 break;
486 case 'D':
487 flags |= LONGINT;
488 /*FALLTHROUGH*/
489 case 'd':
490 case 'i':
491 _umax = SARG();
492 if ((intmax_t)_umax < 0) {
493 _umax = -_umax;
494 sign = '-';
495 }
496 base = DEC;
497 goto number;
498#ifdef FLOATING_POINT
499 case 'e':
500 case 'E':
501 case 'f':
502 case 'g':
503 case 'G':
504 if (prec == -1) {
505 prec = DEFPREC;
506 } else if ((ch == 'g' || ch == 'G') && prec == 0) {
507 prec = 1;
508 }
509
510 if (flags & LONGDBL) {
511 _double = (double) GETARG(long double);
512 } else {
513 _double = GETARG(double);
514 }
515
516 /* do this before tricky precision changes */
517 if (_my_isinf(_double)) {
518 if (_double < 0)
519 sign = '-';
520 cp = "Inf";
521 size = 3;
522 break;
523 }
524 if (_my_isnan(_double)) {
525 cp = "NaN";
526 size = 3;
527 break;
528 }
529
530 flags |= FPT;
531 cp = cvt(_double, prec, flags, &softsign,
532 &expt, ch, &ndig);
533 cp_free = cp;
534 if (ch == 'g' || ch == 'G') {
535 if (expt <= -4 || expt > prec)
536 ch = (ch == 'g') ? 'e' : 'E';
537 else
538 ch = 'g';
539 }
540 if (ch <= 'e') { /* 'e' or 'E' fmt */
541 --expt;
542 expsize = exponent(expstr, expt, ch);
543 size = expsize + ndig;
544 if (ndig > 1 || flags & ALT)
545 ++size;
546 } else if (ch == 'f') { /* f fmt */
547 if (expt > 0) {
548 size = expt;
549 if (prec || flags & ALT)
550 size += prec + 1;
551 } else /* "0.X" */
552 size = prec + 2;
553 } else if (expt >= ndig) { /* fixed g fmt */
554 size = expt;
555 if (flags & ALT)
556 ++size;
557 } else
558 size = ndig + (expt > 0 ?
559 1 : 2 - expt);
560
561 if (softsign)
562 sign = '-';
563 break;
564#endif /* FLOATING_POINT */
565/* the Android security team suggests removing support for %n
566 * since it has no real practical value, and could lead to
Nick Kralevich9145ad32012-07-25 16:01:38 -0700567 * running malicious code (for really buggy programs that
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800568 * send to printf() user-generated formatting strings).
569 */
570#if 0
571 case 'n':
572 if (flags & LLONGINT)
573 *GETARG(long long *) = ret;
574 else if (flags & LONGINT)
575 *GETARG(long *) = ret;
576 else if (flags & SHORTINT)
577 *GETARG(short *) = ret;
578 else if (flags & CHARINT)
579 *GETARG(__signed char *) = ret;
580 else if (flags & PTRINT)
581 *GETARG(ptrdiff_t *) = ret;
582 else if (flags & SIZEINT)
583 *GETARG(ssize_t *) = ret;
584 else if (flags & MAXINT)
585 *GETARG(intmax_t *) = ret;
586 else
587 *GETARG(int *) = ret;
588 continue; /* no output */
589#endif
590 case 'O':
591 flags |= LONGINT;
592 /*FALLTHROUGH*/
593 case 'o':
594 _umax = UARG();
595 base = OCT;
596 goto nosign;
597 case 'p':
598 /*
599 * ``The argument shall be a pointer to void. The
600 * value of the pointer is converted to a sequence
601 * of printable characters, in an implementation-
602 * defined manner.''
603 * -- ANSI X3J11
604 */
605 /* NOSTRICT */
606 _umax = (u_long)GETARG(void *);
607 base = HEX;
608 xdigs = "0123456789abcdef";
609 flags |= HEXPREFIX;
610 ch = 'x';
611 goto nosign;
612 case 's':
613 if ((cp = GETARG(char *)) == NULL)
614 cp = "(null)";
615 if (prec >= 0) {
616 /*
617 * can't use strlen; can only look for the
618 * NUL in the first `prec' characters, and
619 * strlen() will go further.
620 */
621 char *p = memchr(cp, 0, prec);
622
623 if (p != NULL) {
624 size = p - cp;
625 if (size > prec)
626 size = prec;
627 } else
628 size = prec;
629 } else
630 size = strlen(cp);
631 sign = '\0';
632 break;
633 case 'U':
634 flags |= LONGINT;
635 /*FALLTHROUGH*/
636 case 'u':
637 _umax = UARG();
638 base = DEC;
639 goto nosign;
640 case 'X':
641 xdigs = "0123456789ABCDEF";
642 goto hex;
643 case 'x':
644 xdigs = "0123456789abcdef";
645hex: _umax = UARG();
646 base = HEX;
647 /* leading 0x/X only if non-zero */
648 if (flags & ALT && _umax != 0)
649 flags |= HEXPREFIX;
650
651 /* unsigned conversions */
652nosign: sign = '\0';
653 /*
654 * ``... diouXx conversions ... if a precision is
655 * specified, the 0 flag will be ignored.''
656 * -- ANSI X3J11
657 */
658number: if ((dprec = prec) >= 0)
659 flags &= ~ZEROPAD;
660
661 /*
662 * ``The result of converting a zero value with an
663 * explicit precision of zero is no characters.''
664 * -- ANSI X3J11
665 */
666 cp = buf + BUF;
667 if (_umax != 0 || prec != 0) {
668 /*
669 * Unsigned mod is hard, and unsigned mod
670 * by a constant is easier than that by
671 * a variable; hence this switch.
672 */
673 switch (base) {
674 case OCT:
675 do {
676 *--cp = to_char(_umax & 7);
677 _umax >>= 3;
678 } while (_umax);
679 /* handle octal leading 0 */
680 if (flags & ALT && *cp != '0')
681 *--cp = '0';
682 break;
683
684 case DEC:
685 /* many numbers are 1 digit */
686 while (_umax >= 10) {
687 *--cp = to_char(_umax % 10);
688 _umax /= 10;
689 }
690 *--cp = to_char(_umax);
691 break;
692
693 case HEX:
694 do {
695 *--cp = xdigs[_umax & 15];
696 _umax >>= 4;
697 } while (_umax);
698 break;
699
700 default:
701 cp = "bug in vfprintf: bad base";
702 size = strlen(cp);
703 goto skipsize;
704 }
705 }
706 size = buf + BUF - cp;
707 skipsize:
708 break;
709 default: /* "%?" prints ?, unless ? is NUL */
710 if (ch == '\0')
711 goto done;
712 /* pretend it was %c with argument ch */
713 cp = buf;
714 *cp = ch;
715 size = 1;
716 sign = '\0';
717 break;
718 }
719
720 /*
721 * All reasonable formats wind up here. At this point, `cp'
722 * points to a string which (if not flags&LADJUST) should be
723 * padded out to `width' places. If flags&ZEROPAD, it should
724 * first be prefixed by any sign or other prefix; otherwise,
725 * it should be blank padded before the prefix is emitted.
726 * After any left-hand padding and prefixing, emit zeroes
727 * required by a decimal [diouxX] precision, then print the
728 * string proper, then emit zeroes required by any leftover
729 * floating precision; finally, if LADJUST, pad with blanks.
730 *
731 * Compute actual size, so we know how much to pad.
732 * size excludes decimal prec; realsz includes it.
733 */
734 realsz = dprec > size ? dprec : size;
735 if (sign)
736 realsz++;
737 else if (flags & HEXPREFIX)
738 realsz+= 2;
739
740 /* right-adjusting blank padding */
741 if ((flags & (LADJUST|ZEROPAD)) == 0)
742 PAD(width - realsz, blanks);
743
744 /* prefix */
745 if (sign) {
746 PRINT(&sign, 1);
747 } else if (flags & HEXPREFIX) {
748 ox[0] = '0';
749 ox[1] = ch;
750 PRINT(ox, 2);
751 }
752
753 /* right-adjusting zero padding */
754 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
755 PAD(width - realsz, zeroes);
756
757 /* leading zeroes from decimal precision */
758 PAD(dprec - size, zeroes);
759
760 /* the string or number proper */
761#ifdef FLOATING_POINT
762 if ((flags & FPT) == 0) {
763 PRINT(cp, size);
764 } else { /* glue together f_p fragments */
765 if (ch >= 'f') { /* 'f' or 'g' */
766 if (_double == 0) {
767 /* kludge for __dtoa irregularity */
768 PRINT("0", 1);
769 if (expt < ndig || (flags & ALT) != 0) {
770 PRINT(decimal_point, 1);
771 PAD(ndig - 1, zeroes);
772 }
773 } else if (expt <= 0) {
774 PRINT("0", 1);
775 PRINT(decimal_point, 1);
776 PAD(-expt, zeroes);
777 PRINT(cp, ndig);
778 } else if (expt >= ndig) {
779 PRINT(cp, ndig);
780 PAD(expt - ndig, zeroes);
781 if (flags & ALT)
782 PRINT(".", 1);
783 } else {
784 PRINT(cp, expt);
785 cp += expt;
786 PRINT(".", 1);
787 PRINT(cp, ndig-expt);
788 }
789 } else { /* 'e' or 'E' */
790 if (ndig > 1 || flags & ALT) {
791 ox[0] = *cp++;
792 ox[1] = '.';
793 PRINT(ox, 2);
794 if (_double) {
795 PRINT(cp, ndig-1);
796 } else /* 0.[0..] */
797 /* __dtoa irregularity */
798 PAD(ndig - 1, zeroes);
799 } else /* XeYYY */
800 PRINT(cp, 1);
801 PRINT(expstr, expsize);
802 }
803 }
804#else
805 PRINT(cp, size);
806#endif
807 /* left-adjusting padding (always blank) */
808 if (flags & LADJUST)
809 PAD(width - realsz, blanks);
810
811 /* finally, adjust ret */
812 ret += width > realsz ? width : realsz;
813
814 FLUSH(); /* copy out the I/O vectors */
815#if 1 /* BIONIC: remove memory leak when printing doubles */
816 if (cp_free) {
817 free(cp_free);
818 cp_free = NULL;
819 }
820#endif
821 }
822done:
823 FLUSH();
824error:
825#if 1 /* BIONIC: remove memory leak when printing doubles */
826 if (cp_free) {
827 free(cp_free);
828 cp_free = NULL;
829 }
830#endif
831 if (argtable != NULL && argtable != statargtable) {
832 munmap(argtable, argtablesiz);
833 argtable = NULL;
834 }
Yaroslav Miroshnychenkoc7dcd672012-06-14 12:41:54 +0200835 va_end(orgap);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800836 return (__sferror(fp) ? EOF : ret);
837 /* NOTREACHED */
838}
839
840/*
841 * Type ids for argument type table.
842 */
843#define T_UNUSED 0
844#define T_SHORT 1
845#define T_U_SHORT 2
846#define TP_SHORT 3
847#define T_INT 4
848#define T_U_INT 5
849#define TP_INT 6
850#define T_LONG 7
851#define T_U_LONG 8
852#define TP_LONG 9
853#define T_LLONG 10
854#define T_U_LLONG 11
855#define TP_LLONG 12
856#define T_DOUBLE 13
857#define T_LONG_DOUBLE 14
858#define TP_CHAR 15
859#define TP_VOID 16
860#define T_PTRINT 17
861#define TP_PTRINT 18
862#define T_SIZEINT 19
863#define T_SSIZEINT 20
864#define TP_SSIZEINT 21
865#define T_MAXINT 22
866#define T_MAXUINT 23
867#define TP_MAXINT 24
868
869/*
870 * Find all arguments when a positional parameter is encountered. Returns a
871 * table, indexed by argument number, of pointers to each arguments. The
872 * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
873 * It will be replaced with a mmap-ed one if it overflows (malloc cannot be
874 * used since we are attempting to make snprintf thread safe, and alloca is
875 * problematic since we have nested functions..)
876 */
877static void
878__find_arguments(const char *fmt0, va_list ap, va_list **argtable,
879 size_t *argtablesiz)
880{
881 char *fmt; /* format string */
882 int ch; /* character from fmt */
883 int n, n2; /* handy integer (short term usage) */
884 char *cp; /* handy char pointer (short term usage) */
885 int flags; /* flags as above */
886 unsigned char *typetable; /* table of types */
887 unsigned char stattypetable[STATIC_ARG_TBL_SIZE];
888 int tablesize; /* current size of type table */
889 int tablemax; /* largest used index in table */
890 int nextarg; /* 1-based argument index */
891 wchar_t wc;
892 void* ps;
893
894 /*
895 * Add an argument type to the table, expanding if necessary.
896 */
897#define ADDTYPE(type) \
898 ((nextarg >= tablesize) ? \
899 __grow_type_table(&typetable, &tablesize) : 0, \
900 (nextarg > tablemax) ? tablemax = nextarg : 0, \
901 typetable[nextarg++] = type)
902
903#define ADDSARG() \
904 ((flags&MAXINT) ? ADDTYPE(T_MAXINT) : \
905 ((flags&PTRINT) ? ADDTYPE(T_PTRINT) : \
906 ((flags&SIZEINT) ? ADDTYPE(T_SSIZEINT) : \
907 ((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \
908 ((flags&LONGINT) ? ADDTYPE(T_LONG) : \
909 ((flags&SHORTINT) ? ADDTYPE(T_SHORT) : ADDTYPE(T_INT)))))))
910
911#define ADDUARG() \
912 ((flags&MAXINT) ? ADDTYPE(T_MAXUINT) : \
913 ((flags&PTRINT) ? ADDTYPE(T_PTRINT) : \
914 ((flags&SIZEINT) ? ADDTYPE(T_SIZEINT) : \
915 ((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \
916 ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : \
917 ((flags&SHORTINT) ? ADDTYPE(T_U_SHORT) : ADDTYPE(T_U_INT)))))))
918
919 /*
920 * Add * arguments to the type array.
921 */
922#define ADDASTER() \
923 n2 = 0; \
924 cp = fmt; \
925 while (is_digit(*cp)) { \
926 n2 = 10 * n2 + to_digit(*cp); \
927 cp++; \
928 } \
929 if (*cp == '$') { \
930 int hold = nextarg; \
931 nextarg = n2; \
932 ADDTYPE(T_INT); \
933 nextarg = hold; \
934 fmt = ++cp; \
935 } else { \
936 ADDTYPE(T_INT); \
937 }
938 fmt = (char *)fmt0;
939 typetable = stattypetable;
940 tablesize = STATIC_ARG_TBL_SIZE;
941 tablemax = 0;
942 nextarg = 1;
943 memset(typetable, T_UNUSED, STATIC_ARG_TBL_SIZE);
944 memset(&ps, 0, sizeof(ps));
945
946 /*
947 * Scan the format for conversions (`%' character).
948 */
949 for (;;) {
950 cp = fmt;
951#if 1 /* BIONIC */
952 n = -1;
953 while ((wc = *fmt) != 0) {
954 if (wc == '%') {
955 n = 1;
956 break;
957 }
958 fmt++;
959 }
960#else
961 while ((n = mbrtowc(&wc, fmt, MB_CUR_MAX, &ps)) > 0) {
962 fmt += n;
963 if (wc == '%') {
964 fmt--;
965 break;
966 }
967 }
968#endif
969 if (n <= 0)
970 goto done;
971 fmt++; /* skip over '%' */
972
973 flags = 0;
974
975rflag: ch = *fmt++;
976reswitch: switch (ch) {
977 case ' ':
978 case '#':
979 goto rflag;
980 case '*':
981 ADDASTER();
982 goto rflag;
983 case '-':
984 case '+':
985 goto rflag;
986 case '.':
987 if ((ch = *fmt++) == '*') {
988 ADDASTER();
989 goto rflag;
990 }
991 while (is_digit(ch)) {
992 ch = *fmt++;
993 }
994 goto reswitch;
995 case '0':
996 goto rflag;
997 case '1': case '2': case '3': case '4':
998 case '5': case '6': case '7': case '8': case '9':
999 n = 0;
1000 do {
1001 n = 10 * n + to_digit(ch);
1002 ch = *fmt++;
1003 } while (is_digit(ch));
1004 if (ch == '$') {
1005 nextarg = n;
1006 goto rflag;
1007 }
1008 goto reswitch;
1009#ifdef FLOATING_POINT
1010 case 'L':
1011 flags |= LONGDBL;
1012 goto rflag;
1013#endif
1014 case 'h':
1015 if (*fmt == 'h') {
1016 fmt++;
1017 flags |= CHARINT;
1018 } else {
1019 flags |= SHORTINT;
1020 }
1021 goto rflag;
1022 case 'l':
1023 if (*fmt == 'l') {
1024 fmt++;
1025 flags |= LLONGINT;
1026 } else {
1027 flags |= LONGINT;
1028 }
1029 goto rflag;
1030 case 'q':
1031 flags |= LLONGINT;
1032 goto rflag;
1033 case 't':
1034 flags |= PTRINT;
1035 goto rflag;
1036 case 'z':
1037 flags |= SIZEINT;
1038 goto rflag;
1039 case 'c':
1040 ADDTYPE(T_INT);
1041 break;
1042 case 'D':
1043 flags |= LONGINT;
1044 /*FALLTHROUGH*/
1045 case 'd':
1046 case 'i':
1047 ADDSARG();
1048 break;
1049#ifdef FLOATING_POINT
1050 case 'e':
1051 case 'E':
1052 case 'f':
1053 case 'g':
1054 case 'G':
1055 if (flags & LONGDBL)
1056 ADDTYPE(T_LONG_DOUBLE);
1057 else
1058 ADDTYPE(T_DOUBLE);
1059 break;
1060#endif /* FLOATING_POINT */
1061 case 'n':
1062 if (flags & LLONGINT)
1063 ADDTYPE(TP_LLONG);
1064 else if (flags & LONGINT)
1065 ADDTYPE(TP_LONG);
1066 else if (flags & SHORTINT)
1067 ADDTYPE(TP_SHORT);
1068 else if (flags & PTRINT)
1069 ADDTYPE(TP_PTRINT);
1070 else if (flags & SIZEINT)
1071 ADDTYPE(TP_SSIZEINT);
1072 else if (flags & MAXINT)
1073 ADDTYPE(TP_MAXINT);
1074 else
1075 ADDTYPE(TP_INT);
1076 continue; /* no output */
1077 case 'O':
1078 flags |= LONGINT;
1079 /*FALLTHROUGH*/
1080 case 'o':
1081 ADDUARG();
1082 break;
1083 case 'p':
1084 ADDTYPE(TP_VOID);
1085 break;
1086 case 's':
1087 ADDTYPE(TP_CHAR);
1088 break;
1089 case 'U':
1090 flags |= LONGINT;
1091 /*FALLTHROUGH*/
1092 case 'u':
1093 case 'X':
1094 case 'x':
1095 ADDUARG();
1096 break;
1097 default: /* "%?" prints ?, unless ? is NUL */
1098 if (ch == '\0')
1099 goto done;
1100 break;
1101 }
1102 }
1103done:
1104 /*
1105 * Build the argument table.
1106 */
1107 if (tablemax >= STATIC_ARG_TBL_SIZE) {
1108 *argtablesiz = sizeof (va_list) * (tablemax + 1);
1109 *argtable = (va_list *)mmap(NULL, *argtablesiz,
1110 PROT_WRITE|PROT_READ, MAP_ANON|MAP_PRIVATE, -1, 0);
1111 }
1112
1113#if 0
1114 /* XXX is this required? */
1115 (*argtable) [0] = NULL;
1116#endif
1117 for (n = 1; n <= tablemax; n++) {
1118 va_copy((*argtable)[n], ap);
1119 switch (typetable[n]) {
1120 case T_UNUSED:
1121 (void) va_arg(ap, int);
1122 break;
1123 case T_SHORT:
1124 (void) va_arg(ap, int);
1125 break;
1126 case T_U_SHORT:
1127 (void) va_arg(ap, int);
1128 break;
1129 case TP_SHORT:
1130 (void) va_arg(ap, short *);
1131 break;
1132 case T_INT:
1133 (void) va_arg(ap, int);
1134 break;
1135 case T_U_INT:
1136 (void) va_arg(ap, unsigned int);
1137 break;
1138 case TP_INT:
1139 (void) va_arg(ap, int *);
1140 break;
1141 case T_LONG:
1142 (void) va_arg(ap, long);
1143 break;
1144 case T_U_LONG:
1145 (void) va_arg(ap, unsigned long);
1146 break;
1147 case TP_LONG:
1148 (void) va_arg(ap, long *);
1149 break;
1150 case T_LLONG:
1151 (void) va_arg(ap, long long);
1152 break;
1153 case T_U_LLONG:
1154 (void) va_arg(ap, unsigned long long);
1155 break;
1156 case TP_LLONG:
1157 (void) va_arg(ap, long long *);
1158 break;
1159 case T_DOUBLE:
1160 (void) va_arg(ap, double);
1161 break;
1162 case T_LONG_DOUBLE:
1163 (void) va_arg(ap, long double);
1164 break;
1165 case TP_CHAR:
1166 (void) va_arg(ap, char *);
1167 break;
1168 case TP_VOID:
1169 (void) va_arg(ap, void *);
1170 break;
1171 case T_PTRINT:
1172 (void) va_arg(ap, ptrdiff_t);
1173 break;
1174 case TP_PTRINT:
1175 (void) va_arg(ap, ptrdiff_t *);
1176 break;
1177 case T_SIZEINT:
1178 (void) va_arg(ap, size_t);
1179 break;
1180 case T_SSIZEINT:
1181 (void) va_arg(ap, ssize_t);
1182 break;
1183 case TP_SSIZEINT:
1184 (void) va_arg(ap, ssize_t *);
1185 break;
1186 case TP_MAXINT:
1187 (void) va_arg(ap, intmax_t *);
1188 break;
1189 }
1190 }
1191
1192 if (typetable != NULL && typetable != stattypetable) {
1193 munmap(typetable, *argtablesiz);
1194 typetable = NULL;
1195 }
1196}
1197
1198/*
1199 * Increase the size of the type table.
1200 */
1201static int
1202__grow_type_table(unsigned char **typetable, int *tablesize)
1203{
1204 unsigned char *oldtable = *typetable;
1205 int newsize = *tablesize * 2;
1206
1207 if (*tablesize == STATIC_ARG_TBL_SIZE) {
1208 *typetable = (unsigned char *)mmap(NULL,
1209 sizeof (unsigned char) * newsize, PROT_WRITE|PROT_READ,
1210 MAP_ANON|MAP_PRIVATE, -1, 0);
1211 /* XXX unchecked */
1212 memcpy( *typetable, oldtable, *tablesize);
1213 } else {
1214 unsigned char *new = (unsigned char *)mmap(NULL,
1215 sizeof (unsigned char) * newsize, PROT_WRITE|PROT_READ,
1216 MAP_ANON|MAP_PRIVATE, -1, 0);
1217 memmove(new, *typetable, *tablesize);
1218 munmap(*typetable, *tablesize);
1219 *typetable = new;
1220 /* XXX unchecked */
1221 }
1222 memset(*typetable + *tablesize, T_UNUSED, (newsize - *tablesize));
1223
1224 *tablesize = newsize;
1225 return(0);
1226}
1227
1228
1229#ifdef FLOATING_POINT
1230
1231extern char *__dtoa(double, int, int, int *, int *, char **);
1232
1233static char *
1234cvt(double value, int ndigits, int flags, char *sign, int *decpt, int ch,
1235 int *length)
1236{
1237 int mode, dsgn;
1238 char *digits, *bp, *rve;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001239
1240 if (ch == 'f') {
1241 mode = 3; /* ndigits after the decimal point */
1242 } else {
1243 /* To obtain ndigits after the decimal point for the 'e'
1244 * and 'E' formats, round to ndigits + 1 significant
1245 * figures.
1246 */
1247 if (ch == 'e' || ch == 'E') {
1248 ndigits++;
1249 }
1250 mode = 2; /* ndigits significant digits */
1251 }
1252
1253 if (value < 0) {
1254 value = -value;
1255 *sign = '-';
1256 } else
1257 *sign = '\000';
1258 digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
1259 if ((ch != 'g' && ch != 'G') || flags & ALT) { /* Print trailing zeros */
1260 bp = digits + ndigits;
1261 if (ch == 'f') {
1262 if (*digits == '0' && value)
1263 *decpt = -ndigits + 1;
1264 bp += *decpt;
1265 }
1266 if (value == 0) /* kludge for __dtoa irregularity */
1267 rve = bp;
1268 while (rve < bp)
1269 *rve++ = '0';
1270 }
1271 *length = rve - digits;
1272 return (digits);
1273}
1274
1275static int
1276exponent(char *p0, int exp, int fmtch)
1277{
1278 char *p, *t;
1279 char expbuf[MAXEXP];
1280
1281 p = p0;
1282 *p++ = fmtch;
1283 if (exp < 0) {
1284 exp = -exp;
1285 *p++ = '-';
1286 }
1287 else
1288 *p++ = '+';
1289 t = expbuf + MAXEXP;
1290 if (exp > 9) {
1291 do {
1292 *--t = to_char(exp % 10);
1293 } while ((exp /= 10) > 9);
1294 *--t = to_char(exp);
1295 for (; t < expbuf + MAXEXP; *p++ = *t++);
1296 }
1297 else {
1298 *p++ = '0';
1299 *p++ = to_char(exp);
1300 }
1301 return (p - p0);
1302}
1303
1304
1305/* BIONIC */
1306#include <machine/ieee.h>
1307typedef union {
1308 double d;
1309 struct ieee_double i;
1310} ieee_u;
1311
1312static int
1313_my_isinf (double value)
1314{
1315 ieee_u u;
1316
1317 u.d = value;
1318 return (u.i.dbl_exp == 2047 && u.i.dbl_frach == 0 && u.i.dbl_fracl == 0);
1319}
1320
1321static int
1322_my_isnan (double value)
1323{
1324 ieee_u u;
1325
1326 u.d = value;
1327 return (u.i.dbl_exp == 2047 && (u.i.dbl_frach != 0 || u.i.dbl_fracl != 0));
1328}
1329#endif /* FLOATING_POINT */