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