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