blob: e33c105049a02d47fec12eab9dcc7e829421a58c [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
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +040054union arg {
55 int intarg;
56 unsigned int uintarg;
57 long longarg;
58 unsigned long ulongarg;
59 long long longlongarg;
60 unsigned long long ulonglongarg;
61 ptrdiff_t ptrdiffarg;
62 size_t sizearg;
63 size_t ssizearg;
64 intmax_t intmaxarg;
65 uintmax_t uintmaxarg;
66 void *pvoidarg;
67 char *pchararg;
68 signed char *pschararg;
69 short *pshortarg;
70 int *pintarg;
71 long *plongarg;
72 long long *plonglongarg;
73 ptrdiff_t *pptrdiffarg;
74 size_t *pssizearg;
75 intmax_t *pintmaxarg;
76#ifdef FLOATING_POINT
77 double doublearg;
78 long double longdoublearg;
79#endif
80};
81
82static int __find_arguments(const char *fmt0, va_list ap, union arg **argtable,
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080083 size_t *argtablesiz);
84static int __grow_type_table(unsigned char **typetable, int *tablesize);
85
86/*
87 * Flush out all the vectors defined by the given uio,
88 * then reset it so that it can be reused.
89 */
90static int
91__sprint(FILE *fp, struct __suio *uio)
92{
93 int err;
94
95 if (uio->uio_resid == 0) {
96 uio->uio_iovcnt = 0;
97 return (0);
98 }
99 err = __sfvwrite(fp, uio);
100 uio->uio_resid = 0;
101 uio->uio_iovcnt = 0;
102 return (err);
103}
104
105/*
106 * Helper function for `fprintf to unbuffered unix file': creates a
107 * temporary buffer. We only work on write-only files; this avoids
108 * worries about ungetc buffers and so forth.
109 */
110static int
111__sbprintf(FILE *fp, const char *fmt, va_list ap)
112{
113 int ret;
114 FILE fake;
115 struct __sfileext fakeext;
116 unsigned char buf[BUFSIZ];
117
118 _FILEEXT_SETUP(&fake, &fakeext);
119 /* copy the important variables */
120 fake._flags = fp->_flags & ~__SNBF;
121 fake._file = fp->_file;
122 fake._cookie = fp->_cookie;
123 fake._write = fp->_write;
124
125 /* set up the buffer */
126 fake._bf._base = fake._p = buf;
127 fake._bf._size = fake._w = sizeof(buf);
128 fake._lbfsize = 0; /* not actually used, but Just In Case */
129
130 /* do the work, then copy any error status */
Kenny Rootf5823402011-02-12 07:13:44 -0800131 ret = __vfprintf(&fake, fmt, ap);
132 if (ret >= 0 && __sflush(&fake))
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800133 ret = EOF;
134 if (fake._flags & __SERR)
135 fp->_flags |= __SERR;
136 return (ret);
137}
138
139
140#ifdef FLOATING_POINT
141#include <locale.h>
142#include <math.h>
143#include "floatio.h"
144
145#define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
146#define DEFPREC 6
147
148static char *cvt(double, int, int, char *, int *, int, int *);
Elliott Hughes5eb67042014-04-11 18:00:37 -0700149extern void freedtoa(char *);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800150static int exponent(char *, int, int);
151#else /* no FLOATING_POINT */
152#define BUF 40
153#endif /* FLOATING_POINT */
154
155#define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */
156
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800157/*
158 * Macros for converting digits to letters and vice versa
159 */
160#define to_digit(c) ((c) - '0')
161#define is_digit(c) ((unsigned)to_digit(c) <= 9)
162#define to_char(n) ((n) + '0')
163
164/*
165 * Flags used during conversion.
166 */
167#define ALT 0x0001 /* alternate form */
168#define HEXPREFIX 0x0002 /* add 0x or 0X prefix */
169#define LADJUST 0x0004 /* left adjustment */
170#define LONGDBL 0x0008 /* long double; unimplemented */
171#define LONGINT 0x0010 /* long integer */
172#define LLONGINT 0x0020 /* long long integer */
173#define SHORTINT 0x0040 /* short integer */
174#define ZEROPAD 0x0080 /* zero (as opposed to blank) pad */
175#define FPT 0x0100 /* Floating point number */
176#define PTRINT 0x0200 /* (unsigned) ptrdiff_t */
177#define SIZEINT 0x0400 /* (signed) size_t */
178#define CHARINT 0x0800 /* 8 bit integer */
179#define MAXINT 0x1000 /* largest integer size (intmax_t) */
180
181int
182vfprintf(FILE *fp, const char *fmt0, __va_list ap)
183{
Kenny Rootf5823402011-02-12 07:13:44 -0800184 int ret;
185
186 FLOCKFILE(fp);
187 ret = __vfprintf(fp, fmt0, ap);
188 FUNLOCKFILE(fp);
189 return (ret);
190}
191
192int
193__vfprintf(FILE *fp, const char *fmt0, __va_list ap)
194{
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +0400195 char *fmt; /* format string */
196 int ch; /* character from fmt */
197 int n, m, n2; /* handy integers (short term usage) */
198 char *cp; /* handy char pointer (short term usage) */
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +0400199 struct __siov *iovp; /* for PRINT macro */
200 int flags; /* flags as above */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800201 int ret; /* return value accumulator */
202 int width; /* width from format (%8d), or 0 */
203 int prec; /* precision from format (%.3d), or -1 */
204 char sign; /* sign prefix (' ', '+', '-', or \0) */
205 wchar_t wc;
206 void* ps;
207#ifdef FLOATING_POINT
208 char *decimal_point = ".";
209 char softsign; /* temporary negative sign for floats */
210 double _double = 0.; /* double precision arguments %[eEfgG] */
211 int expt; /* integer value of exponent */
212 int expsize = 0; /* character count for expstr */
213 int ndig; /* actual number of digits returned by cvt */
214 char expstr[7]; /* buffer for exponent string */
Elliott Hughes5eb67042014-04-11 18:00:37 -0700215 char *dtoaresult = NULL;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800216#endif
217
218 uintmax_t _umax; /* integer arguments %[diouxX] */
219 enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
220 int dprec; /* a copy of prec if [diouxX], 0 otherwise */
221 int realsz; /* field size expanded by dprec */
222 int size; /* size of converted field or string */
223 char* xdigs = NULL; /* digits for [xX] conversion */
224#define NIOV 8
225 struct __suio uio; /* output information: summary */
226 struct __siov iov[NIOV];/* ... and individual io vectors */
227 char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
228 char ox[2]; /* space for 0x hex-prefix */
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +0400229 union arg *argtable; /* args, built due to positional arg */
230 union arg statargtable[STATIC_ARG_TBL_SIZE];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800231 size_t argtablesiz;
232 int nextarg; /* 1-based argument index */
233 va_list orgap; /* original argument pointer */
234 /*
235 * Choose PADSIZE to trade efficiency vs. size. If larger printf
236 * fields occur frequently, increase PADSIZE and make the initialisers
237 * below longer.
238 */
239#define PADSIZE 16 /* pad chunk size */
Glenn Kasten0946b1f2011-01-09 11:28:22 -0800240 static const char blanks[PADSIZE] =
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800241 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
Glenn Kasten0946b1f2011-01-09 11:28:22 -0800242 static const char zeroes[PADSIZE] =
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800243 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
244
245 /*
246 * BEWARE, these `goto error' on error, and PAD uses `n'.
247 */
248#define PRINT(ptr, len) do { \
249 iovp->iov_base = (ptr); \
250 iovp->iov_len = (len); \
251 uio.uio_resid += (len); \
252 iovp++; \
253 if (++uio.uio_iovcnt >= NIOV) { \
254 if (__sprint(fp, &uio)) \
255 goto error; \
256 iovp = iov; \
257 } \
258} while (0)
259#define PAD(howmany, with) do { \
260 if ((n = (howmany)) > 0) { \
261 while (n > PADSIZE) { \
262 PRINT(with, PADSIZE); \
263 n -= PADSIZE; \
264 } \
265 PRINT(with, n); \
266 } \
267} while (0)
268#define FLUSH() do { \
269 if (uio.uio_resid && __sprint(fp, &uio)) \
270 goto error; \
271 uio.uio_iovcnt = 0; \
272 iovp = iov; \
273} while (0)
274
275 /*
276 * To extend shorts properly, we need both signed and unsigned
277 * argument extraction methods.
278 */
279#define SARG() \
280 ((intmax_t)(flags&MAXINT ? GETARG(intmax_t) : \
281 flags&LLONGINT ? GETARG(long long) : \
282 flags&LONGINT ? GETARG(long) : \
283 flags&PTRINT ? GETARG(ptrdiff_t) : \
284 flags&SIZEINT ? GETARG(ssize_t) : \
285 flags&SHORTINT ? (short)GETARG(int) : \
286 flags&CHARINT ? (__signed char)GETARG(int) : \
287 GETARG(int)))
288#define UARG() \
289 ((uintmax_t)(flags&MAXINT ? GETARG(uintmax_t) : \
290 flags&LLONGINT ? GETARG(unsigned long long) : \
291 flags&LONGINT ? GETARG(unsigned long) : \
292 flags&PTRINT ? (uintptr_t)GETARG(ptrdiff_t) : /* XXX */ \
293 flags&SIZEINT ? GETARG(size_t) : \
294 flags&SHORTINT ? (unsigned short)GETARG(int) : \
295 flags&CHARINT ? (unsigned char)GETARG(int) : \
296 GETARG(unsigned int)))
297
298 /*
299 * Get * arguments, including the form *nn$. Preserve the nextarg
300 * that the argument can be gotten once the type is determined.
301 */
302#define GETASTER(val) \
303 n2 = 0; \
304 cp = fmt; \
305 while (is_digit(*cp)) { \
306 n2 = 10 * n2 + to_digit(*cp); \
307 cp++; \
308 } \
309 if (*cp == '$') { \
310 int hold = nextarg; \
311 if (argtable == NULL) { \
312 argtable = statargtable; \
313 __find_arguments(fmt0, orgap, &argtable, &argtablesiz); \
314 } \
315 nextarg = n2; \
316 val = GETARG(int); \
317 nextarg = hold; \
318 fmt = ++cp; \
319 } else { \
320 val = GETARG(int); \
321 }
322
323/*
324* Get the argument indexed by nextarg. If the argument table is
325* built, use it to get the argument. If its not, get the next
326* argument (and arguments must be gotten sequentially).
327*/
328#define GETARG(type) \
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +0400329 ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
330 (nextarg++, va_arg(ap, type)))
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800331
332 _SET_ORIENTATION(fp, -1);
333 /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
334 if (cantwrite(fp)) {
335 errno = EBADF;
336 return (EOF);
337 }
338
339 /* optimise fprintf(stderr) (and other unbuffered Unix files) */
340 if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
341 fp->_file >= 0)
342 return (__sbprintf(fp, fmt0, ap));
343
344 fmt = (char *)fmt0;
345 argtable = NULL;
346 nextarg = 1;
347 va_copy(orgap, ap);
348 uio.uio_iov = iovp = iov;
349 uio.uio_resid = 0;
350 uio.uio_iovcnt = 0;
351 ret = 0;
352
353 memset(&ps, 0, sizeof(ps));
354 /*
355 * Scan the format for conversions (`%' character).
356 */
357 for (;;) {
358 cp = fmt;
359#if 1 /* BIONIC */
360 n = -1;
361 while ( (wc = *fmt) != 0 ) {
362 if (wc == '%') {
363 n = 1;
364 break;
365 }
366 fmt++;
367 }
368#else
369 while ((n = mbrtowc(&wc, fmt, MB_CUR_MAX, &ps)) > 0) {
370 fmt += n;
371 if (wc == '%') {
372 fmt--;
373 break;
374 }
375 }
376#endif
377 if ((m = fmt - cp) != 0) {
378 PRINT(cp, m);
379 ret += m;
380 }
381 if (n <= 0)
382 goto done;
383 fmt++; /* skip over '%' */
384
385 flags = 0;
386 dprec = 0;
387 width = 0;
388 prec = -1;
389 sign = '\0';
390
391rflag: ch = *fmt++;
392reswitch: switch (ch) {
393 case ' ':
394 /*
395 * ``If the space and + flags both appear, the space
396 * flag will be ignored.''
397 * -- ANSI X3J11
398 */
399 if (!sign)
400 sign = ' ';
401 goto rflag;
402 case '#':
403 flags |= ALT;
404 goto rflag;
405 case '*':
406 /*
407 * ``A negative field width argument is taken as a
408 * - flag followed by a positive field width.''
409 * -- ANSI X3J11
410 * They don't exclude field widths read from args.
411 */
412 GETASTER(width);
413 if (width >= 0)
414 goto rflag;
415 width = -width;
416 /* FALLTHROUGH */
417 case '-':
418 flags |= LADJUST;
419 goto rflag;
420 case '+':
421 sign = '+';
422 goto rflag;
423 case '.':
424 if ((ch = *fmt++) == '*') {
425 GETASTER(n);
426 prec = n < 0 ? -1 : n;
427 goto rflag;
428 }
429 n = 0;
430 while (is_digit(ch)) {
431 n = 10 * n + to_digit(ch);
432 ch = *fmt++;
433 }
434 if (ch == '$') {
435 nextarg = n;
436 if (argtable == NULL) {
437 argtable = statargtable;
438 __find_arguments(fmt0, orgap,
439 &argtable, &argtablesiz);
440 }
441 goto rflag;
442 }
443 prec = n < 0 ? -1 : n;
444 goto reswitch;
445 case '0':
446 /*
447 * ``Note that 0 is taken as a flag, not as the
448 * beginning of a field width.''
449 * -- ANSI X3J11
450 */
451 flags |= ZEROPAD;
452 goto rflag;
453 case '1': case '2': case '3': case '4':
454 case '5': case '6': case '7': case '8': case '9':
455 n = 0;
456 do {
457 n = 10 * n + to_digit(ch);
458 ch = *fmt++;
459 } while (is_digit(ch));
460 if (ch == '$') {
461 nextarg = n;
462 if (argtable == NULL) {
463 argtable = statargtable;
464 __find_arguments(fmt0, orgap,
465 &argtable, &argtablesiz);
466 }
467 goto rflag;
468 }
469 width = n;
470 goto reswitch;
471#ifdef FLOATING_POINT
472 case 'L':
473 flags |= LONGDBL;
474 goto rflag;
475#endif
476 case 'h':
Elliott Hughes1d13c642013-09-23 16:02:39 -0700477 if (*fmt == 'h') {
478 fmt++;
479 flags |= CHARINT;
480 } else {
481 flags |= SHORTINT;
482 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800483 goto rflag;
484 case 'j':
485 flags |= MAXINT;
486 goto rflag;
487 case 'l':
488 if (*fmt == 'l') {
489 fmt++;
490 flags |= LLONGINT;
491 } else {
492 flags |= LONGINT;
493 }
494 goto rflag;
495 case 'q':
496 flags |= LLONGINT;
497 goto rflag;
498 case 't':
499 flags |= PTRINT;
500 goto rflag;
501 case 'z':
502 flags |= SIZEINT;
503 goto rflag;
504 case 'c':
505 *(cp = buf) = GETARG(int);
506 size = 1;
507 sign = '\0';
508 break;
509 case 'D':
510 flags |= LONGINT;
511 /*FALLTHROUGH*/
512 case 'd':
513 case 'i':
514 _umax = SARG();
515 if ((intmax_t)_umax < 0) {
516 _umax = -_umax;
517 sign = '-';
518 }
519 base = DEC;
520 goto number;
521#ifdef FLOATING_POINT
522 case 'e':
523 case 'E':
524 case 'f':
525 case 'g':
526 case 'G':
527 if (prec == -1) {
528 prec = DEFPREC;
529 } else if ((ch == 'g' || ch == 'G') && prec == 0) {
530 prec = 1;
531 }
532
533 if (flags & LONGDBL) {
534 _double = (double) GETARG(long double);
535 } else {
536 _double = GETARG(double);
537 }
538
539 /* do this before tricky precision changes */
Elliott Hughes02c78a32014-04-11 17:02:20 -0700540 if (isinf(_double)) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800541 if (_double < 0)
542 sign = '-';
543 cp = "Inf";
544 size = 3;
545 break;
546 }
Elliott Hughes02c78a32014-04-11 17:02:20 -0700547 if (isnan(_double)) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800548 cp = "NaN";
549 size = 3;
550 break;
551 }
552
Elliott Hughes5eb67042014-04-11 18:00:37 -0700553 if (dtoaresult != NULL) freedtoa(dtoaresult);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800554 flags |= FPT;
Elliott Hughes5eb67042014-04-11 18:00:37 -0700555 dtoaresult = cp = cvt(_double, prec, flags, &softsign,
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800556 &expt, ch, &ndig);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800557 if (ch == 'g' || ch == 'G') {
558 if (expt <= -4 || expt > prec)
559 ch = (ch == 'g') ? 'e' : 'E';
560 else
561 ch = 'g';
562 }
563 if (ch <= 'e') { /* 'e' or 'E' fmt */
564 --expt;
565 expsize = exponent(expstr, expt, ch);
566 size = expsize + ndig;
567 if (ndig > 1 || flags & ALT)
568 ++size;
569 } else if (ch == 'f') { /* f fmt */
570 if (expt > 0) {
571 size = expt;
572 if (prec || flags & ALT)
573 size += prec + 1;
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +0400574 } else { /* "0.X" */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800575 size = prec + 2;
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +0400576 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800577 } else if (expt >= ndig) { /* fixed g fmt */
578 size = expt;
579 if (flags & ALT)
580 ++size;
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +0400581 } else {
582 size = ndig + (expt > 0 ? 1 : 2 - expt);
583 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800584
585 if (softsign)
586 sign = '-';
587 break;
588#endif /* FLOATING_POINT */
589/* the Android security team suggests removing support for %n
590 * since it has no real practical value, and could lead to
Nick Kralevich9145ad32012-07-25 16:01:38 -0700591 * running malicious code (for really buggy programs that
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800592 * send to printf() user-generated formatting strings).
593 */
594#if 0
595 case 'n':
596 if (flags & LLONGINT)
597 *GETARG(long long *) = ret;
598 else if (flags & LONGINT)
599 *GETARG(long *) = ret;
600 else if (flags & SHORTINT)
601 *GETARG(short *) = ret;
602 else if (flags & CHARINT)
603 *GETARG(__signed char *) = ret;
604 else if (flags & PTRINT)
605 *GETARG(ptrdiff_t *) = ret;
606 else if (flags & SIZEINT)
607 *GETARG(ssize_t *) = ret;
608 else if (flags & MAXINT)
609 *GETARG(intmax_t *) = ret;
610 else
611 *GETARG(int *) = ret;
612 continue; /* no output */
613#endif
614 case 'O':
615 flags |= LONGINT;
616 /*FALLTHROUGH*/
617 case 'o':
618 _umax = UARG();
619 base = OCT;
620 goto nosign;
621 case 'p':
622 /*
623 * ``The argument shall be a pointer to void. The
624 * value of the pointer is converted to a sequence
625 * of printable characters, in an implementation-
626 * defined manner.''
627 * -- ANSI X3J11
628 */
629 /* NOSTRICT */
630 _umax = (u_long)GETARG(void *);
631 base = HEX;
632 xdigs = "0123456789abcdef";
633 flags |= HEXPREFIX;
634 ch = 'x';
635 goto nosign;
636 case 's':
637 if ((cp = GETARG(char *)) == NULL)
638 cp = "(null)";
639 if (prec >= 0) {
640 /*
641 * can't use strlen; can only look for the
642 * NUL in the first `prec' characters, and
643 * strlen() will go further.
644 */
645 char *p = memchr(cp, 0, prec);
646
647 if (p != NULL) {
648 size = p - cp;
649 if (size > prec)
650 size = prec;
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +0400651 } else {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800652 size = prec;
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +0400653 }
654 } else {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800655 size = strlen(cp);
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +0400656 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800657 sign = '\0';
658 break;
659 case 'U':
660 flags |= LONGINT;
661 /*FALLTHROUGH*/
662 case 'u':
663 _umax = UARG();
664 base = DEC;
665 goto nosign;
666 case 'X':
667 xdigs = "0123456789ABCDEF";
668 goto hex;
669 case 'x':
670 xdigs = "0123456789abcdef";
671hex: _umax = UARG();
672 base = HEX;
673 /* leading 0x/X only if non-zero */
674 if (flags & ALT && _umax != 0)
675 flags |= HEXPREFIX;
676
677 /* unsigned conversions */
678nosign: sign = '\0';
679 /*
680 * ``... diouXx conversions ... if a precision is
681 * specified, the 0 flag will be ignored.''
682 * -- ANSI X3J11
683 */
684number: if ((dprec = prec) >= 0)
685 flags &= ~ZEROPAD;
686
687 /*
688 * ``The result of converting a zero value with an
689 * explicit precision of zero is no characters.''
690 * -- ANSI X3J11
691 */
692 cp = buf + BUF;
693 if (_umax != 0 || prec != 0) {
694 /*
695 * Unsigned mod is hard, and unsigned mod
696 * by a constant is easier than that by
697 * a variable; hence this switch.
698 */
699 switch (base) {
700 case OCT:
701 do {
702 *--cp = to_char(_umax & 7);
703 _umax >>= 3;
704 } while (_umax);
705 /* handle octal leading 0 */
706 if (flags & ALT && *cp != '0')
707 *--cp = '0';
708 break;
709
710 case DEC:
711 /* many numbers are 1 digit */
712 while (_umax >= 10) {
713 *--cp = to_char(_umax % 10);
714 _umax /= 10;
715 }
716 *--cp = to_char(_umax);
717 break;
718
719 case HEX:
720 do {
721 *--cp = xdigs[_umax & 15];
722 _umax >>= 4;
723 } while (_umax);
724 break;
725
726 default:
727 cp = "bug in vfprintf: bad base";
728 size = strlen(cp);
729 goto skipsize;
730 }
731 }
732 size = buf + BUF - cp;
733 skipsize:
734 break;
735 default: /* "%?" prints ?, unless ? is NUL */
736 if (ch == '\0')
737 goto done;
738 /* pretend it was %c with argument ch */
739 cp = buf;
740 *cp = ch;
741 size = 1;
742 sign = '\0';
743 break;
744 }
745
746 /*
747 * All reasonable formats wind up here. At this point, `cp'
748 * points to a string which (if not flags&LADJUST) should be
749 * padded out to `width' places. If flags&ZEROPAD, it should
750 * first be prefixed by any sign or other prefix; otherwise,
751 * it should be blank padded before the prefix is emitted.
752 * After any left-hand padding and prefixing, emit zeroes
753 * required by a decimal [diouxX] precision, then print the
754 * string proper, then emit zeroes required by any leftover
755 * floating precision; finally, if LADJUST, pad with blanks.
756 *
757 * Compute actual size, so we know how much to pad.
758 * size excludes decimal prec; realsz includes it.
759 */
760 realsz = dprec > size ? dprec : size;
761 if (sign)
762 realsz++;
763 else if (flags & HEXPREFIX)
764 realsz+= 2;
765
766 /* right-adjusting blank padding */
767 if ((flags & (LADJUST|ZEROPAD)) == 0)
768 PAD(width - realsz, blanks);
769
770 /* prefix */
771 if (sign) {
772 PRINT(&sign, 1);
773 } else if (flags & HEXPREFIX) {
774 ox[0] = '0';
775 ox[1] = ch;
776 PRINT(ox, 2);
777 }
778
779 /* right-adjusting zero padding */
780 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
781 PAD(width - realsz, zeroes);
782
783 /* leading zeroes from decimal precision */
784 PAD(dprec - size, zeroes);
785
786 /* the string or number proper */
787#ifdef FLOATING_POINT
788 if ((flags & FPT) == 0) {
789 PRINT(cp, size);
790 } else { /* glue together f_p fragments */
791 if (ch >= 'f') { /* 'f' or 'g' */
792 if (_double == 0) {
793 /* kludge for __dtoa irregularity */
794 PRINT("0", 1);
795 if (expt < ndig || (flags & ALT) != 0) {
796 PRINT(decimal_point, 1);
797 PAD(ndig - 1, zeroes);
798 }
799 } else if (expt <= 0) {
800 PRINT("0", 1);
801 PRINT(decimal_point, 1);
802 PAD(-expt, zeroes);
803 PRINT(cp, ndig);
804 } else if (expt >= ndig) {
805 PRINT(cp, ndig);
806 PAD(expt - ndig, zeroes);
807 if (flags & ALT)
808 PRINT(".", 1);
809 } else {
810 PRINT(cp, expt);
811 cp += expt;
812 PRINT(".", 1);
813 PRINT(cp, ndig-expt);
814 }
815 } else { /* 'e' or 'E' */
816 if (ndig > 1 || flags & ALT) {
817 ox[0] = *cp++;
818 ox[1] = '.';
819 PRINT(ox, 2);
820 if (_double) {
821 PRINT(cp, ndig-1);
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +0400822 } else {/* 0.[0..] */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800823 /* __dtoa irregularity */
824 PAD(ndig - 1, zeroes);
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +0400825 }
826 } else { /* XeYYY */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800827 PRINT(cp, 1);
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +0400828 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800829 PRINT(expstr, expsize);
830 }
831 }
832#else
833 PRINT(cp, size);
834#endif
835 /* left-adjusting padding (always blank) */
836 if (flags & LADJUST)
837 PAD(width - realsz, blanks);
838
839 /* finally, adjust ret */
840 ret += width > realsz ? width : realsz;
841
842 FLUSH(); /* copy out the I/O vectors */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800843 }
844done:
845 FLUSH();
846error:
Elliott Hughes5eb67042014-04-11 18:00:37 -0700847#ifdef FLOATING_POINT
848 if (dtoaresult != NULL) {
849 freedtoa(dtoaresult);
850 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800851#endif
852 if (argtable != NULL && argtable != statargtable) {
853 munmap(argtable, argtablesiz);
854 argtable = NULL;
855 }
Yaroslav Miroshnychenkoc7dcd672012-06-14 12:41:54 +0200856 va_end(orgap);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800857 return (__sferror(fp) ? EOF : ret);
858 /* NOTREACHED */
859}
860
861/*
862 * Type ids for argument type table.
863 */
864#define T_UNUSED 0
865#define T_SHORT 1
866#define T_U_SHORT 2
867#define TP_SHORT 3
868#define T_INT 4
869#define T_U_INT 5
870#define TP_INT 6
871#define T_LONG 7
872#define T_U_LONG 8
873#define TP_LONG 9
874#define T_LLONG 10
875#define T_U_LLONG 11
876#define TP_LLONG 12
877#define T_DOUBLE 13
878#define T_LONG_DOUBLE 14
879#define TP_CHAR 15
880#define TP_VOID 16
881#define T_PTRINT 17
882#define TP_PTRINT 18
883#define T_SIZEINT 19
884#define T_SSIZEINT 20
885#define TP_SSIZEINT 21
886#define T_MAXINT 22
887#define T_MAXUINT 23
888#define TP_MAXINT 24
889
890/*
891 * Find all arguments when a positional parameter is encountered. Returns a
892 * table, indexed by argument number, of pointers to each arguments. The
893 * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
894 * It will be replaced with a mmap-ed one if it overflows (malloc cannot be
895 * used since we are attempting to make snprintf thread safe, and alloca is
896 * problematic since we have nested functions..)
897 */
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +0400898static int
899__find_arguments(const char *fmt0, va_list ap, union arg **argtable,
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800900 size_t *argtablesiz)
901{
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +0400902 char *fmt; /* format string */
903 int ch; /* character from fmt */
904 int n, n2; /* handy integer (short term usage) */
905 char *cp; /* handy char pointer (short term usage) */
906 int flags; /* flags as above */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800907 unsigned char *typetable; /* table of types */
908 unsigned char stattypetable[STATIC_ARG_TBL_SIZE];
909 int tablesize; /* current size of type table */
910 int tablemax; /* largest used index in table */
911 int nextarg; /* 1-based argument index */
912 wchar_t wc;
913 void* ps;
914
915 /*
916 * Add an argument type to the table, expanding if necessary.
917 */
918#define ADDTYPE(type) \
919 ((nextarg >= tablesize) ? \
920 __grow_type_table(&typetable, &tablesize) : 0, \
921 (nextarg > tablemax) ? tablemax = nextarg : 0, \
922 typetable[nextarg++] = type)
923
924#define ADDSARG() \
925 ((flags&MAXINT) ? ADDTYPE(T_MAXINT) : \
926 ((flags&PTRINT) ? ADDTYPE(T_PTRINT) : \
927 ((flags&SIZEINT) ? ADDTYPE(T_SSIZEINT) : \
928 ((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \
929 ((flags&LONGINT) ? ADDTYPE(T_LONG) : \
930 ((flags&SHORTINT) ? ADDTYPE(T_SHORT) : ADDTYPE(T_INT)))))))
931
932#define ADDUARG() \
933 ((flags&MAXINT) ? ADDTYPE(T_MAXUINT) : \
934 ((flags&PTRINT) ? ADDTYPE(T_PTRINT) : \
935 ((flags&SIZEINT) ? ADDTYPE(T_SIZEINT) : \
936 ((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \
937 ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : \
938 ((flags&SHORTINT) ? ADDTYPE(T_U_SHORT) : ADDTYPE(T_U_INT)))))))
939
940 /*
941 * Add * arguments to the type array.
942 */
943#define ADDASTER() \
944 n2 = 0; \
945 cp = fmt; \
946 while (is_digit(*cp)) { \
947 n2 = 10 * n2 + to_digit(*cp); \
948 cp++; \
949 } \
950 if (*cp == '$') { \
951 int hold = nextarg; \
952 nextarg = n2; \
953 ADDTYPE(T_INT); \
954 nextarg = hold; \
955 fmt = ++cp; \
956 } else { \
957 ADDTYPE(T_INT); \
958 }
959 fmt = (char *)fmt0;
960 typetable = stattypetable;
961 tablesize = STATIC_ARG_TBL_SIZE;
962 tablemax = 0;
963 nextarg = 1;
964 memset(typetable, T_UNUSED, STATIC_ARG_TBL_SIZE);
965 memset(&ps, 0, sizeof(ps));
966
967 /*
968 * Scan the format for conversions (`%' character).
969 */
970 for (;;) {
971 cp = fmt;
972#if 1 /* BIONIC */
973 n = -1;
974 while ((wc = *fmt) != 0) {
975 if (wc == '%') {
976 n = 1;
977 break;
978 }
979 fmt++;
980 }
981#else
982 while ((n = mbrtowc(&wc, fmt, MB_CUR_MAX, &ps)) > 0) {
983 fmt += n;
984 if (wc == '%') {
985 fmt--;
986 break;
987 }
988 }
989#endif
990 if (n <= 0)
991 goto done;
992 fmt++; /* skip over '%' */
993
994 flags = 0;
995
996rflag: ch = *fmt++;
997reswitch: switch (ch) {
998 case ' ':
999 case '#':
1000 goto rflag;
1001 case '*':
1002 ADDASTER();
1003 goto rflag;
1004 case '-':
1005 case '+':
1006 goto rflag;
1007 case '.':
1008 if ((ch = *fmt++) == '*') {
1009 ADDASTER();
1010 goto rflag;
1011 }
1012 while (is_digit(ch)) {
1013 ch = *fmt++;
1014 }
1015 goto reswitch;
1016 case '0':
1017 goto rflag;
1018 case '1': case '2': case '3': case '4':
1019 case '5': case '6': case '7': case '8': case '9':
1020 n = 0;
1021 do {
1022 n = 10 * n + to_digit(ch);
1023 ch = *fmt++;
1024 } while (is_digit(ch));
1025 if (ch == '$') {
1026 nextarg = n;
1027 goto rflag;
1028 }
1029 goto reswitch;
1030#ifdef FLOATING_POINT
1031 case 'L':
1032 flags |= LONGDBL;
1033 goto rflag;
1034#endif
1035 case 'h':
1036 if (*fmt == 'h') {
1037 fmt++;
1038 flags |= CHARINT;
1039 } else {
1040 flags |= SHORTINT;
1041 }
1042 goto rflag;
1043 case 'l':
1044 if (*fmt == 'l') {
1045 fmt++;
1046 flags |= LLONGINT;
1047 } else {
1048 flags |= LONGINT;
1049 }
1050 goto rflag;
1051 case 'q':
1052 flags |= LLONGINT;
1053 goto rflag;
1054 case 't':
1055 flags |= PTRINT;
1056 goto rflag;
1057 case 'z':
1058 flags |= SIZEINT;
1059 goto rflag;
1060 case 'c':
1061 ADDTYPE(T_INT);
1062 break;
1063 case 'D':
1064 flags |= LONGINT;
1065 /*FALLTHROUGH*/
1066 case 'd':
1067 case 'i':
1068 ADDSARG();
1069 break;
1070#ifdef FLOATING_POINT
1071 case 'e':
1072 case 'E':
1073 case 'f':
1074 case 'g':
1075 case 'G':
1076 if (flags & LONGDBL)
1077 ADDTYPE(T_LONG_DOUBLE);
1078 else
1079 ADDTYPE(T_DOUBLE);
1080 break;
1081#endif /* FLOATING_POINT */
1082 case 'n':
1083 if (flags & LLONGINT)
1084 ADDTYPE(TP_LLONG);
1085 else if (flags & LONGINT)
1086 ADDTYPE(TP_LONG);
1087 else if (flags & SHORTINT)
1088 ADDTYPE(TP_SHORT);
1089 else if (flags & PTRINT)
1090 ADDTYPE(TP_PTRINT);
1091 else if (flags & SIZEINT)
1092 ADDTYPE(TP_SSIZEINT);
1093 else if (flags & MAXINT)
1094 ADDTYPE(TP_MAXINT);
1095 else
1096 ADDTYPE(TP_INT);
1097 continue; /* no output */
1098 case 'O':
1099 flags |= LONGINT;
1100 /*FALLTHROUGH*/
1101 case 'o':
1102 ADDUARG();
1103 break;
1104 case 'p':
1105 ADDTYPE(TP_VOID);
1106 break;
1107 case 's':
1108 ADDTYPE(TP_CHAR);
1109 break;
1110 case 'U':
1111 flags |= LONGINT;
1112 /*FALLTHROUGH*/
1113 case 'u':
1114 case 'X':
1115 case 'x':
1116 ADDUARG();
1117 break;
1118 default: /* "%?" prints ?, unless ? is NUL */
1119 if (ch == '\0')
1120 goto done;
1121 break;
1122 }
1123 }
1124done:
1125 /*
1126 * Build the argument table.
1127 */
1128 if (tablemax >= STATIC_ARG_TBL_SIZE) {
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001129 *argtablesiz = sizeof(union arg) * (tablemax + 1);
1130 *argtable = mmap(NULL, *argtablesiz,
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001131 PROT_WRITE|PROT_READ, MAP_ANON|MAP_PRIVATE, -1, 0);
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001132 if (*argtable == MAP_FAILED)
1133 return (-1);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001134 }
1135
1136#if 0
1137 /* XXX is this required? */
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001138 (*argtable)[0].intarg = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001139#endif
1140 for (n = 1; n <= tablemax; n++) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001141 switch (typetable[n]) {
1142 case T_UNUSED:
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001143 (*argtable)[n].intarg = va_arg(ap, int);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001144 break;
1145 case T_SHORT:
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001146 (*argtable)[n].intarg = va_arg(ap, int);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001147 break;
1148 case T_U_SHORT:
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001149 (*argtable)[n].intarg = va_arg(ap, int);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001150 break;
1151 case TP_SHORT:
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001152 (*argtable)[n].pshortarg = va_arg(ap, short *);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001153 break;
1154 case T_INT:
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001155 (*argtable)[n].intarg = va_arg(ap, int);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001156 break;
1157 case T_U_INT:
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001158 (*argtable)[n].uintarg = va_arg(ap, unsigned int);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001159 break;
1160 case TP_INT:
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001161 (*argtable)[n].pintarg = va_arg(ap, int *);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001162 break;
1163 case T_LONG:
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001164 (*argtable)[n].longarg = va_arg(ap, long);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001165 break;
1166 case T_U_LONG:
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001167 (*argtable)[n].ulongarg = va_arg(ap, unsigned long);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001168 break;
1169 case TP_LONG:
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001170 (*argtable)[n].plongarg = va_arg(ap, long *);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001171 break;
1172 case T_LLONG:
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001173 (*argtable)[n].longlongarg = va_arg(ap, long long);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001174 break;
1175 case T_U_LLONG:
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001176 (*argtable)[n].ulonglongarg = va_arg(ap, unsigned long long);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001177 break;
1178 case TP_LLONG:
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001179 (*argtable)[n].plonglongarg = va_arg(ap, long long *);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001180 break;
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001181#ifdef FLOATING_POINT
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001182 case T_DOUBLE:
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001183 (*argtable)[n].doublearg = va_arg(ap, double);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001184 break;
1185 case T_LONG_DOUBLE:
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001186 (*argtable)[n].longdoublearg = va_arg(ap, long double);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001187 break;
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001188#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001189 case TP_CHAR:
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001190 (*argtable)[n].pchararg = va_arg(ap, char *);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001191 break;
1192 case TP_VOID:
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001193 (*argtable)[n].pvoidarg = va_arg(ap, void *);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001194 break;
1195 case T_PTRINT:
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001196 (*argtable)[n].ptrdiffarg = va_arg(ap, ptrdiff_t);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001197 break;
1198 case TP_PTRINT:
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001199 (*argtable)[n].pptrdiffarg = va_arg(ap, ptrdiff_t *);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001200 break;
1201 case T_SIZEINT:
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001202 (*argtable)[n].sizearg = va_arg(ap, size_t);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001203 break;
1204 case T_SSIZEINT:
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001205 (*argtable)[n].ssizearg = va_arg(ap, ssize_t);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001206 break;
1207 case TP_SSIZEINT:
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001208 (*argtable)[n].pssizearg = va_arg(ap, ssize_t *);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001209 break;
1210 case TP_MAXINT:
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001211 (*argtable)[n].intmaxarg = va_arg(ap, intmax_t);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001212 break;
1213 }
1214 }
1215
1216 if (typetable != NULL && typetable != stattypetable) {
1217 munmap(typetable, *argtablesiz);
1218 typetable = NULL;
1219 }
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001220 return (0);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001221}
1222
1223/*
1224 * Increase the size of the type table.
1225 */
1226static int
1227__grow_type_table(unsigned char **typetable, int *tablesize)
1228{
1229 unsigned char *oldtable = *typetable;
1230 int newsize = *tablesize * 2;
1231
1232 if (*tablesize == STATIC_ARG_TBL_SIZE) {
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001233 *typetable = mmap(NULL, newsize, PROT_WRITE|PROT_READ,
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001234 MAP_ANON|MAP_PRIVATE, -1, 0);
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001235 if (*typetable == MAP_FAILED)
1236 return (-1);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001237 memcpy( *typetable, oldtable, *tablesize);
1238 } else {
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001239 unsigned char *new = mmap(NULL, newsize, PROT_WRITE|PROT_READ,
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001240 MAP_ANON|MAP_PRIVATE, -1, 0);
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001241 if (new == MAP_FAILED)
1242 return (-1);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001243 memmove(new, *typetable, *tablesize);
1244 munmap(*typetable, *tablesize);
1245 *typetable = new;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001246 }
1247 memset(*typetable + *tablesize, T_UNUSED, (newsize - *tablesize));
1248
1249 *tablesize = newsize;
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001250 return (0);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001251}
1252
1253
1254#ifdef FLOATING_POINT
1255
1256extern char *__dtoa(double, int, int, int *, int *, char **);
1257
1258static char *
1259cvt(double value, int ndigits, int flags, char *sign, int *decpt, int ch,
1260 int *length)
1261{
1262 int mode, dsgn;
1263 char *digits, *bp, *rve;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001264
1265 if (ch == 'f') {
1266 mode = 3; /* ndigits after the decimal point */
1267 } else {
1268 /* To obtain ndigits after the decimal point for the 'e'
1269 * and 'E' formats, round to ndigits + 1 significant
1270 * figures.
1271 */
1272 if (ch == 'e' || ch == 'E') {
1273 ndigits++;
1274 }
1275 mode = 2; /* ndigits significant digits */
1276 }
1277
1278 if (value < 0) {
1279 value = -value;
1280 *sign = '-';
1281 } else
1282 *sign = '\000';
1283 digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001284 if ((ch != 'g' && ch != 'G') || flags & ALT) {/* Print trailing zeros */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001285 bp = digits + ndigits;
1286 if (ch == 'f') {
1287 if (*digits == '0' && value)
1288 *decpt = -ndigits + 1;
1289 bp += *decpt;
1290 }
1291 if (value == 0) /* kludge for __dtoa irregularity */
1292 rve = bp;
1293 while (rve < bp)
1294 *rve++ = '0';
1295 }
1296 *length = rve - digits;
1297 return (digits);
1298}
1299
1300static int
1301exponent(char *p0, int exp, int fmtch)
1302{
1303 char *p, *t;
1304 char expbuf[MAXEXP];
1305
1306 p = p0;
1307 *p++ = fmtch;
1308 if (exp < 0) {
1309 exp = -exp;
1310 *p++ = '-';
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001311 } else
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001312 *p++ = '+';
1313 t = expbuf + MAXEXP;
1314 if (exp > 9) {
1315 do {
1316 *--t = to_char(exp % 10);
1317 } while ((exp /= 10) > 9);
1318 *--t = to_char(exp);
Alexander Ivchenkoedd7c2e2014-04-01 17:01:39 +04001319 for (; t < expbuf + MAXEXP; *p++ = *t++)
1320 /* nothing */;
1321 } else {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001322 *p++ = '0';
1323 *p++ = to_char(exp);
1324 }
1325 return (p - p0);
1326}
1327
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001328#endif /* FLOATING_POINT */