1 /* $OpenBSD: vfprintf.c,v 1.57 2009/10/28 21:15:02 naddy Exp $ */
3 * Copyright (c) 1990 The Regents of the University of California.
6 * This code is derived from software contributed to Berkeley by
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
35 * Actual printf innards.
37 * This code is large and complicated...
40 //#define FLOATING_POINT
42 #include <sys/types.h>
62 unsigned long ulongarg
;
63 long long longlongarg
;
64 unsigned long long ulonglongarg
;
72 signed char *pschararg
;
76 long long *plonglongarg
;
77 ptrdiff_t *pptrdiffarg
;
82 long double longdoublearg
;
86 static int __find_arguments(const char *fmt0
, va_list ap
, union arg
**argtable
,
88 static int __grow_type_table(unsigned char **typetable
, int *tablesize
);
91 * Flush out all the vectors defined by the given uio,
92 * then reset it so that it can be reused.
95 __sprint(LFILE
*fp
, struct __suio
*uio
)
99 if (uio
->uio_resid
== 0) {
103 err
= __sfvwrite(fp
, uio
);
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.
115 //__sbprintf(LFILE *fp, const char *fmt, va_list ap)
119 // struct __sfileext fakeext;
120 // unsigned char buf[BUFSIZ];
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;
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 */
134 // /* do the work, then copy any error status */
135 // ret = ust_safe_vfprintf(&fake, fmt, ap);
136 // if (ret >= 0 && fflush(&fake))
138 // if (fake._flags & __SERR)
139 // fp->_flags |= __SERR;
144 #ifdef FLOATING_POINT
152 extern char *__dtoa(double, int, int, int *, int *, char **);
153 extern void __freedtoa(char *);
154 static int exponent(char *, int, int);
155 #endif /* FLOATING_POINT */
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.
166 #define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */
170 * Macros for converting digits to letters and vice versa
172 #define to_digit(c) ((c) - '0')
173 #define is_digit(c) ((unsigned)to_digit(c) <= 9)
174 #define to_char(n) ((n) + '0')
177 * Flags used during conversion.
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) */
192 int ust_safe_vfprintf(LFILE
*fp
, const char *fmt0
, va_list ap
)
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) */
198 struct __siov
*iovp
; /* for PRINT macro */
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) */
206 #ifdef FLOATING_POINT
208 * We can decompose the printed representation of floating
209 * point numbers into several parts, some of which may be empty:
211 * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
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
221 char *decimal_point
= localeconv()->decimal_point
;
222 int signflag
; /* true if float is negative */
223 union { /* floating point arguments %[aAeEfFgG] */
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
;
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 */
242 const char *xdigs
; /* digits for %[xX] conversion */
244 struct __suio uio
; /* output information: summary */
245 struct __siov iov
[NIOV
];/* ... and individual io vectors */
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
];
251 int nextarg
; /* 1-based argument index */
252 va_list orgap
; /* original argument pointer */
255 * Choose PADSIZE to trade efficiency vs. size. If larger printf
256 * fields occur frequently, increase PADSIZE and make the initialisers
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'};
265 static const char xdigs_lower
[16] = "0123456789abcdef";
266 static const char xdigs_upper
[16] = "0123456789ABCDEF";
269 * BEWARE, these `goto error' on error, and PAD uses `n'.
271 #define PRINT(ptr, len) do { \
272 iovp->iov_base = (ptr); \
273 iovp->iov_len = (len); \
274 uio.uio_resid += (len); \
276 if (++uio.uio_iovcnt >= NIOV) { \
277 if (__sprint(fp, &uio)) \
282 #define PAD(howmany, with) do { \
283 if ((n = (howmany)) > 0) { \
284 while (n > PADSIZE) { \
285 PRINT(with, PADSIZE); \
291 #define PRINTANDPAD(p, ep, len, with) do { \
297 PAD((len) - (n2 > 0 ? n2 : 0), (with)); \
299 #define FLUSH() do { \
300 if (uio.uio_resid && __sprint(fp, &uio)) \
302 uio.uio_iovcnt = 0; \
307 * To extend shorts properly, we need both signed and unsigned
308 * argument extraction methods.
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) : \
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)))
330 * Append a digit to a value and check for overflow.
332 #define APPEND_DIGIT(val, dig) do { \
333 if ((val) > INT_MAX / 10) \
336 if ((val) > INT_MAX - to_digit((dig))) \
338 (val) += to_digit((dig)); \
342 * Get * arguments, including the form *nn$. Preserve the nextarg
343 * that the argument can be gotten once the type is determined.
345 #define GETASTER(val) \
348 while (is_digit(*cp)) { \
349 APPEND_DIGIT(n2, *cp); \
353 int hold = nextarg; \
354 if (argtable == NULL) { \
355 argtable = statargtable; \
356 __find_arguments(fmt0, orgap, &argtable, &argtablesiz); \
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).
371 #define GETARG(type) \
372 ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
373 (nextarg++, va_arg(ap, type)))
375 _SET_ORIENTATION(fp
, -1);
376 /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
382 /* optimise fprintf(stderr) (and other unbuffered Unix files) */
383 // if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
385 // return (__sbprintf(fp, fmt0, ap));
391 uio
.uio_iov
= iovp
= iov
;
396 memset(&ps
, 0, sizeof(ps
));
398 * Scan the format for conversions (`%' character).
402 while ((n
= mbrtowc(&wc
, fmt
, MB_CUR_MAX
, &ps
)) > 0) {
410 ptrdiff_t m
= fmt
- cp
;
411 if (m
< 0 || m
> INT_MAX
- ret
)
418 fmt
++; /* skip over '%' */
428 reswitch
: switch (ch
) {
431 * ``If the space and + flags both appear, the space
432 * flag will be ignored.''
442 /* grouping not implemented */
446 * ``A negative field width argument is taken as a
447 * - flag followed by a positive field width.''
449 * They don't exclude field widths read from args.
454 if (width
== INT_MIN
)
465 if ((ch
= *fmt
++) == '*') {
467 prec
= n
< 0 ? -1 : n
;
471 while (is_digit(ch
)) {
477 if (argtable
== NULL
) {
478 argtable
= statargtable
;
479 __find_arguments(fmt0
, orgap
,
480 &argtable
, &argtablesiz
);
488 * ``Note that 0 is taken as a flag, not as the
489 * beginning of a field width.''
494 case '1': case '2': case '3': case '4':
495 case '5': case '6': case '7': case '8': case '9':
500 } while (is_digit(ch
));
503 if (argtable
== NULL
) {
504 argtable
= statargtable
;
505 __find_arguments(fmt0
, orgap
,
506 &argtable
, &argtablesiz
);
512 #ifdef FLOATING_POINT
546 *(cp
= buf
) = GETARG(int);
556 if ((intmax_t)_umax
< 0) {
562 #ifdef FLOATING_POINT
577 __freedtoa(dtoaresult
);
578 if (flags
& LONGDBL
) {
579 fparg
.ldbl
= GETARG(long double);
581 __hldtoa(fparg
.ldbl
, xdigs
, prec
,
582 &expt
, &signflag
, &dtoaend
);
583 if (dtoaresult
== NULL
) {
588 fparg
.dbl
= GETARG(double);
590 __hdtoa(fparg
.dbl
, xdigs
, prec
,
591 &expt
, &signflag
, &dtoaend
);
592 if (dtoaresult
== NULL
) {
605 if (prec
< 0) /* account for digit before decpt */
616 expchar
= ch
- ('g' - 'e');
623 __freedtoa(dtoaresult
);
624 if (flags
& LONGDBL
) {
625 fparg
.ldbl
= GETARG(long double);
627 __ldtoa(&fparg
.ldbl
, expchar
? 2 : 3, prec
,
628 &expt
, &signflag
, &dtoaend
);
629 if (dtoaresult
== NULL
) {
634 fparg
.dbl
= GETARG(double);
636 __dtoa(fparg
.dbl
, expchar
? 2 : 3, prec
,
637 &expt
, &signflag
, &dtoaend
);
638 if (dtoaresult
== NULL
) {
648 if (expt
== INT_MAX
) { /* inf or nan */
650 cp
= (ch
>= 'a') ? "nan" : "NAN";
653 cp
= (ch
>= 'a') ? "inf" : "INF";
660 if (ch
== 'g' || ch
== 'G') {
661 if (expt
> -4 && expt
<= prec
) {
662 /* Make %[gG] smell like %[fF] */
672 * Make %[gG] smell like %[eE], but
673 * trim trailing zeroes if no # flag.
680 expsize
= exponent(expstr
, expt
- 1, expchar
);
681 size
= expsize
+ prec
;
682 if (prec
> 1 || flags
& ALT
)
685 /* space for digits before decimal point */
690 /* space for decimal pt and following digits */
691 if (prec
|| flags
& ALT
)
696 #endif /* FLOATING_POINT */
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
;
713 *GETARG(int *) = ret
;
714 continue; /* no output */
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-
731 _umax
= (u_long
)GETARG(void *);
737 if ((cp
= GETARG(char *)) == NULL
)
741 * can't use strlen; can only look for the
742 * NUL in the first `prec' characters, and
743 * strlen() will go further.
745 char *p
= memchr(cp
, 0, prec
);
747 size
= p
? (p
- cp
) : prec
;
751 if ((len
= strlen(cp
)) > INT_MAX
)
771 /* leading 0x/X only if non-zero */
772 if (flags
& ALT
&& _umax
!= 0)
775 /* unsigned conversions */
778 * ``... diouXx conversions ... if a precision is
779 * specified, the 0 flag will be ignored.''
782 number
: if ((dprec
= prec
) >= 0)
786 * ``The result of converting a zero value with an
787 * explicit precision of zero is no characters.''
791 if (_umax
!= 0 || prec
!= 0) {
793 * Unsigned mod is hard, and unsigned mod
794 * by a constant is easier than that by
795 * a variable; hence this switch.
800 *--cp
= to_char(_umax
& 7);
803 /* handle octal leading 0 */
804 if (flags
& ALT
&& *cp
!= '0')
809 /* many numbers are 1 digit */
810 while (_umax
>= 10) {
811 *--cp
= to_char(_umax
% 10);
814 *--cp
= to_char(_umax
);
819 *--cp
= xdigs
[_umax
& 15];
825 cp
= "bug in ust_safe_vfprintf: bad base";
830 size
= buf
+ BUF
- cp
;
831 if (size
> BUF
) /* should never happen */
835 default: /* "%?" prints ?, unless ? is NUL */
838 /* pretend it was %c with argument ch */
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.
857 * Compute actual size, so we know how much to pad.
858 * size excludes decimal prec; realsz includes it.
860 realsz
= dprec
> size
? dprec
: size
;
866 /* right-adjusting blank padding */
867 if ((flags
& (LADJUST
|ZEROPAD
)) == 0)
868 PAD(width
- realsz
, blanks
);
873 if (ox
[1]) { /* ox[1] is either x, X, or \0 */
878 /* right-adjusting zero padding */
879 if ((flags
& (LADJUST
|ZEROPAD
)) == ZEROPAD
)
880 PAD(width
- realsz
, zeroes
);
882 /* leading zeroes from decimal precision */
883 PAD(dprec
- size
, zeroes
);
885 /* the string or number proper */
886 #ifdef FLOATING_POINT
887 if ((flags
& FPT
) == 0) {
889 } else { /* glue together f_p fragments */
890 if (!expchar
) { /* %[fF] or sufficiently short %[gG] */
893 if (prec
|| flags
& ALT
)
894 PRINT(decimal_point
, 1);
896 /* already handled initial 0's */
899 PRINTANDPAD(cp
, dtoaend
, lead
, zeroes
);
901 if (prec
|| flags
& ALT
)
902 PRINT(decimal_point
, 1);
904 PRINTANDPAD(cp
, dtoaend
, prec
, zeroes
);
905 } else { /* %[eE] or sufficiently long %[gG] */
906 if (prec
> 1 || flags
& ALT
) {
908 buf
[1] = *decimal_point
;
911 PAD(prec
- ndig
, zeroes
);
915 PRINT(expstr
, expsize
);
921 /* left-adjusting padding (always blank) */
923 PAD(width
- realsz
, blanks
);
925 /* finally, adjust ret */
928 if (width
> INT_MAX
- ret
)
932 FLUSH(); /* copy out the I/O vectors */
947 #ifdef FLOATING_POINT
949 __freedtoa(dtoaresult
);
951 if (argtable
!= NULL
&& argtable
!= statargtable
) {
952 munmap(argtable
, argtablesiz
);
959 * Type ids for argument type table.
975 #define T_LONG_DOUBLE 14
981 #define T_SSIZEINT 20
982 #define TP_SSIZEINT 21
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..)
998 __find_arguments(const char *fmt0
, va_list ap
, union arg
**argtable
,
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 */
1016 * Add an argument type to the table, expanding if necessary.
1018 #define ADDTYPE(type) \
1019 ((nextarg >= tablesize) ? \
1020 __grow_type_table(&typetable, &tablesize) : 0, \
1021 (nextarg > tablemax) ? tablemax = nextarg : 0, \
1022 typetable[nextarg++] = type)
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))))))))
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))))))))
1043 * Add * arguments to the type array.
1045 #define ADDASTER() \
1048 while (is_digit(*cp)) { \
1049 APPEND_DIGIT(n2, *cp); \
1053 int hold = nextarg; \
1062 typetable
= stattypetable
;
1063 tablesize
= STATIC_ARG_TBL_SIZE
;
1066 memset(typetable
, T_UNUSED
, STATIC_ARG_TBL_SIZE
);
1067 memset(&ps
, 0, sizeof(ps
));
1070 * Scan the format for conversions (`%' character).
1074 while ((n
= mbrtowc(&wc
, fmt
, MB_CUR_MAX
, &ps
)) > 0) {
1083 fmt
++; /* skip over '%' */
1088 reswitch
: switch (ch
) {
1100 if ((ch
= *fmt
++) == '*') {
1104 while (is_digit(ch
)) {
1110 case '1': case '2': case '3': case '4':
1111 case '5': case '6': case '7': case '8': case '9':
1114 APPEND_DIGIT(n
,ch
);
1116 } while (is_digit(ch
));
1122 #ifdef FLOATING_POINT
1162 #ifdef FLOATING_POINT
1171 if (flags
& LONGDBL
)
1172 ADDTYPE(T_LONG_DOUBLE
);
1176 #endif /* FLOATING_POINT */
1178 if (flags
& LLONGINT
)
1180 else if (flags
& LONGINT
)
1182 else if (flags
& SHORTINT
)
1184 else if (flags
& PTRINT
)
1186 else if (flags
& SIZEINT
)
1187 ADDTYPE(TP_SSIZEINT
);
1188 else if (flags
& MAXINT
)
1192 continue; /* no output */
1213 default: /* "%?" prints ?, unless ? is NUL */
1221 * Build the argument table.
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
)
1232 /* XXX is this required? */
1233 (*argtable
)[0].intarg
= 0;
1235 for (n
= 1; n
<= tablemax
; n
++) {
1236 switch (typetable
[n
]) {
1243 (*argtable
)[n
].intarg
= va_arg(ap
, int);
1246 (*argtable
)[n
].pshortarg
= va_arg(ap
, short *);
1249 (*argtable
)[n
].uintarg
= va_arg(ap
, unsigned int);
1252 (*argtable
)[n
].pintarg
= va_arg(ap
, int *);
1255 (*argtable
)[n
].longarg
= va_arg(ap
, long);
1258 (*argtable
)[n
].ulongarg
= va_arg(ap
, unsigned long);
1261 (*argtable
)[n
].plongarg
= va_arg(ap
, long *);
1264 (*argtable
)[n
].longlongarg
= va_arg(ap
, long long);
1267 (*argtable
)[n
].ulonglongarg
= va_arg(ap
, unsigned long long);
1270 (*argtable
)[n
].plonglongarg
= va_arg(ap
, long long *);
1272 #ifdef FLOATING_POINT
1274 (*argtable
)[n
].doublearg
= va_arg(ap
, double);
1277 (*argtable
)[n
].longdoublearg
= va_arg(ap
, long double);
1281 (*argtable
)[n
].pchararg
= va_arg(ap
, char *);
1284 (*argtable
)[n
].pvoidarg
= va_arg(ap
, void *);
1287 (*argtable
)[n
].ptrdiffarg
= va_arg(ap
, ptrdiff_t);
1290 (*argtable
)[n
].pptrdiffarg
= va_arg(ap
, ptrdiff_t *);
1293 (*argtable
)[n
].sizearg
= va_arg(ap
, size_t);
1296 (*argtable
)[n
].ssizearg
= va_arg(ap
, ssize_t
);
1299 (*argtable
)[n
].pssizearg
= va_arg(ap
, ssize_t
*);
1302 (*argtable
)[n
].intmaxarg
= va_arg(ap
, intmax_t);
1313 if (typetable
!= NULL
&& typetable
!= stattypetable
) {
1314 munmap(typetable
, *argtablesiz
);
1321 * Increase the size of the type table.
1324 __grow_type_table(unsigned char **typetable
, int *tablesize
)
1326 unsigned char *oldtable
= *typetable
;
1327 int newsize
= *tablesize
* 2;
1329 if (newsize
< getpagesize())
1330 newsize
= getpagesize();
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
)
1337 bcopy(oldtable
, *typetable
, *tablesize
);
1339 unsigned char *new = mmap(NULL
, newsize
, PROT_WRITE
|PROT_READ
,
1340 MAP_ANON
|MAP_PRIVATE
, -1, 0);
1341 if (new == MAP_FAILED
)
1343 memmove(new, *typetable
, *tablesize
);
1344 munmap(*typetable
, *tablesize
);
1347 memset(*typetable
+ *tablesize
, T_UNUSED
, (newsize
- *tablesize
));
1349 *tablesize
= newsize
;
1354 #ifdef FLOATING_POINT
1356 exponent(char *p0
, int exp
, int fmtch
)
1359 char expbuf
[MAXEXPDIG
];
1368 t
= expbuf
+ MAXEXPDIG
;
1371 *--t
= to_char(exp
% 10);
1372 } while ((exp
/= 10) > 9);
1373 *--t
= to_char(exp
);
1374 for (; t
< expbuf
+ MAXEXPDIG
; *p
++ = *t
++)
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.
1383 if (fmtch
== 'e' || fmtch
== 'E')
1385 *p
++ = to_char(exp
);
1389 #endif /* FLOATING_POINT */
This page took 0.067962 seconds and 4 git commands to generate.