2 * Copyright (c) 1990, 2006 The Regents of the University of California.
5 * This code is derived from software contributed to Berkeley by
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 <<vprintf>>, <<vfprintf>>, <<vsprintf>>---format argument list
53 int vprintf(const char *<[fmt]>, va_list <[list]>);
54 int vfprintf(FILE *<[fp]>, const char *<[fmt]>, va_list <[list]>);
55 int vsprintf(char *<[str]>, const char *<[fmt]>, va_list <[list]>);
56 int vasprintf(char **<[strp]>, const char *<[fmt]>, va_list <[list]>);
57 int vsnprintf(char *<[str]>, size_t <[size]>, const char *<[fmt]>,
60 int _vprintf_r(struct _reent *<[reent]>, const char *<[fmt]>,
62 int _vfprintf_r(struct _reent *<[reent]>, FILE *<[fp]>, const char *<[fmt]>,
64 int _vasprintf_r(struct _reent *<[reent]>, char **<[str]>,
65 const char *<[fmt]>, va_list <[list]>);
66 int _vsprintf_r(struct _reent *<[reent]>, char *<[str]>,
67 const char *<[fmt]>, va_list <[list]>);
68 int _vsnprintf_r(struct _reent *<[reent]>, char *<[str]>, size_t <[size]>,
69 const char *<[fmt]>, va_list <[list]>);
74 int vprintf( <[fmt]>, <[list]>)
78 int vfprintf(<[fp]>, <[fmt]>, <[list]>)
83 int vasprintf(<[strp]>, <[fmt]>, <[list]>)
88 int vsprintf(<[str]>, <[fmt]>, <[list]>)
93 int vsnprintf(<[str]>, <[size]>, <[fmt]>, <[list]>)
99 int _vprintf_r(<[reent]>, <[fmt]>, <[list]>)
100 struct _reent *<[reent]>;
104 int _vfprintf_r(<[reent]>, <[fp]>, <[fmt]>, <[list]>)
105 struct _reent *<[reent]>;
110 int _vasprintf_r(<[reent]>, <[strp]>, <[fmt]>, <[list]>)
111 struct _reent *<[reent]>;
116 int _vsprintf_r(<[reent]>, <[str]>, <[fmt]>, <[list]>)
117 struct _reent *<[reent]>;
122 int _vsnprintf_r(<[reent]>, <[str]>, <[size]>, <[fmt]>, <[list]>)
123 struct _reent *<[reent]>;
130 <<vprintf>>, <<vfprintf>>, <<vasprintf>>, <<vsprintf>> and <<vsnprintf>> are
131 (respectively) variants of <<printf>>, <<fprintf>>, <<asprintf>>, <<sprintf>>,
132 and <<snprintf>>. They differ only in allowing their caller to pass the
133 variable argument list as a <<va_list>> object (initialized by <<va_start>>)
134 rather than directly accepting a variable number of arguments.
137 The return values are consistent with the corresponding functions:
138 <<vasprintf>>/<<vsprintf>> returns the number of bytes in the output string,
139 save that the concluding <<NULL>> is not counted.
140 <<vprintf>> and <<vfprintf>> return the number of characters transmitted.
141 If an error occurs, <<vprintf>> and <<vfprintf>> return <<EOF>> and
142 <<vasprintf>> returns -1. No error returns occur for <<vsprintf>>.
145 ANSI C requires all three functions.
147 Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
148 <<lseek>>, <<read>>, <<sbrk>>, <<write>>.
151 #if defined(LIBC_SCCS) && !defined(lint)
152 /*static char *sccsid = "from: @(#)vfprintf.c 5.50 (Berkeley) 12/16/92";*/
153 static char *rcsid = "$Id$";
154 #endif /* LIBC_SCCS and not lint */
157 * Actual printf innards.
159 * This code is large and complicated...
164 #define VFPRINTF vfiprintf
165 #define _VFPRINTF_R _vfiprintf_r
167 #define VFPRINTF vfprintf
168 #define _VFPRINTF_R _vfprintf_r
169 #ifndef NO_FLOATING_POINT
170 #define FLOATING_POINT
175 #if defined _WANT_IO_POS_ARGS
188 #include <sys/lock.h>
196 #include "vfieeefp.h"
198 /* Currently a test is made to see if long double processing is warranted.
199 This could be changed in the future should the _ldtoa_r code be
200 preferred over _dtoa_r. */
202 #if defined _WANT_IO_LONG_DOUBLE && (LDBL_MANT_DIG > DBL_MANT_DIG)
207 #if defined _WANT_IO_LONG_LONG && defined __GNUC__
212 * Flush out all the vectors defined by the given uio,
213 * then reset it so that it can be reused.
216 _DEFUN(__sprint_r, (ptr, fp, uio),
217 struct _reent *ptr _AND
219 register struct __suio *uio)
223 if (uio->uio_resid == 0) {
227 err = __sfvwrite_r(ptr, fp, uio);
234 * Helper function for `fprintf to unbuffered unix file': creates a
235 * temporary buffer. We only work on write-only files; this avoids
236 * worries about ungetc buffers and so forth.
239 _DEFUN(__sbprintf, (rptr, fp, fmt, ap),
240 struct _reent *rptr _AND
241 register FILE *fp _AND
242 _CONST char *fmt _AND
247 unsigned char buf[BUFSIZ];
249 /* copy the important variables */
250 fake._flags = fp->_flags & ~__SNBF;
251 fake._file = fp->_file;
252 fake._cookie = fp->_cookie;
253 fake._write = fp->_write;
255 /* set up the buffer */
256 fake._bf._base = fake._p = buf;
257 fake._bf._size = fake._w = sizeof (buf);
258 fake._lbfsize = 0; /* not actually used, but Just In Case */
259 #ifndef __SINGLE_THREAD__
260 __lock_init_recursive (fake._lock);
263 /* do the work, then copy any error status */
264 ret = _VFPRINTF_R (rptr, &fake, fmt, ap);
265 if (ret >= 0 && fflush(&fake))
267 if (fake._flags & __SERR)
268 fp->_flags |= __SERR;
270 #ifndef __SINGLE_THREAD__
271 __lock_close_recursive (fake._lock);
277 #ifdef FLOATING_POINT
282 #if ((MAXEXP+MAXFRACT+1) > MB_LEN_MAX)
283 # define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
285 # define BUF MB_LEN_MAX
292 _EXFUN(cvt, (struct _reent *, double, int, int, char *, int *, int, int *));
295 _EXFUN(cvt, (struct _reent *, _LONG_DOUBLE, int, int, char *, int *, int, int *));
296 extern int _EXFUN(_ldcheck,(_LONG_DOUBLE *));
299 static int _EXFUN(exponent, (char *, int, int));
301 #else /* no FLOATING_POINT */
305 #endif /* FLOATING_POINT */
308 #define quad_t long long
309 #define u_quad_t unsigned long long
312 #define u_quad_t unsigned long
315 typedef quad_t * quad_ptr_t;
316 typedef _PTR void_ptr_t;
317 typedef char * char_ptr_t;
318 typedef long * long_ptr_t;
319 typedef int * int_ptr_t;
320 typedef short * short_ptr_t;
323 #define MAX_POS_ARGS 32
333 _LONG_DOUBLE val__LONG_DOUBLE;
334 int_ptr_t val_int_ptr_t;
335 short_ptr_t val_short_ptr_t;
336 long_ptr_t val_long_ptr_t;
337 char_ptr_t val_char_ptr_t;
338 quad_ptr_t val_quad_ptr_t;
339 void_ptr_t val_void_ptr_t;
341 u_quad_t val_u_quad_t;
345 static union arg_val *
346 _EXFUN(get_arg, (struct _reent *data, int n, char *fmt,
347 va_list *ap, int *numargs, union arg_val *args,
348 int *arg_type, char **last_fmt));
349 #endif /* !_NO_POS_ARGS */
352 * Macros for converting digits to letters and vice versa
354 #define to_digit(c) ((c) - '0')
355 #define is_digit(c) ((unsigned)to_digit (c) <= 9)
356 #define to_char(n) ((n) + '0')
359 * Flags used during conversion.
361 #define ALT 0x001 /* alternate form */
362 #define HEXPREFIX 0x002 /* add 0x or 0X prefix */
363 #define LADJUST 0x004 /* left adjustment */
364 #define LONGDBL 0x008 /* long double */
365 #define LONGINT 0x010 /* long integer */
367 #define QUADINT 0x020 /* quad integer */
368 #else /* ifdef _NO_LONGLONG, make QUADINT equivalent to LONGINT, so
369 that %lld behaves the same as %ld, not as %d, as expected if:
370 sizeof (long long) = sizeof long > sizeof int */
371 #define QUADINT LONGINT
373 #define SHORTINT 0x040 /* short integer */
374 #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */
375 #define FPT 0x100 /* Floating point number */
376 #define CHARINT 0x200 /* char as integer */
378 int _EXFUN(_VFPRINTF_R, (struct _reent *, FILE *, _CONST char *, va_list));
381 _DEFUN(VFPRINTF, (fp, fmt0, ap),
383 _CONST char *fmt0 _AND
387 result = _VFPRINTF_R (_REENT, fp, fmt0, ap);
392 _DEFUN(_VFPRINTF_R, (data, fp, fmt0, ap),
393 struct _reent *data _AND
395 _CONST char *fmt0 _AND
398 register char *fmt; /* format string */
399 register int ch; /* character from fmt */
400 register int n, m; /* handy integers (short term usage) */
401 register char *cp; /* handy char pointer (short term usage) */
402 register struct __siov *iovp;/* for PRINT macro */
403 register int flags; /* flags as above */
404 char *fmt_anchor; /* current format spec being processed */
405 int N; /* arg number */
406 int arg_index; /* index into args processed directly */
408 int numargs; /* number of varargs read */
409 char *saved_fmt; /* saved fmt pointer */
410 union arg_val args[MAX_POS_ARGS];
411 int arg_type[MAX_POS_ARGS];
412 int is_pos_arg; /* is current format positional? */
413 int old_is_pos_arg; /* is current format positional? */
415 int ret; /* return value accumulator */
416 int width; /* width from format (%8d), or 0 */
417 int prec; /* precision from format (%.3d), or -1 */
418 char sign; /* sign prefix (' ', '+', '-', or \0) */
419 #ifdef FLOATING_POINT
420 char *decimal_point = localeconv()->decimal_point;
421 char softsign; /* temporary negative sign for floats */
423 union { int i; double d; } _double_ = {0};
424 #define _fpvalue (_double_.d)
426 union { int i; _LONG_DOUBLE ld; } _long_double_ = {0};
427 #define _fpvalue (_long_double_.ld)
430 int expt; /* integer value of exponent */
431 int expsize = 0; /* character count for expstr */
432 int ndig = 0; /* actual number of digits returned by cvt */
433 char expstr[7]; /* buffer for exponent string */
435 u_quad_t _uquad; /* integer arguments %[diouxX] */
436 enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
437 int dprec; /* a copy of prec if [diouxX], 0 otherwise */
438 int realsz; /* field size expanded by dprec */
439 int size; /* size of converted field or string */
440 char *xdigs = NULL; /* digits for [xX] conversion */
442 struct __suio uio; /* output information: summary */
443 struct __siov iov[NIOV];/* ... and individual io vectors */
444 char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
445 char ox[2]; /* space for 0x hex-prefix */
448 mbstate_t state; /* mbtowc calls from library must not change state */
450 char *malloc_buf = NULL;/* handy pointer for malloced buffers */
453 * Choose PADSIZE to trade efficiency vs. size. If larger printf
454 * fields occur frequently, increase PADSIZE and make the initialisers
457 #define PADSIZE 16 /* pad chunk size */
458 static _CONST char blanks[PADSIZE] =
459 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
460 static _CONST char zeroes[PADSIZE] =
461 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
464 memset (&state, '\0', sizeof (state));
467 * BEWARE, these `goto error' on error, and PAD uses `n'.
469 #define PRINT(ptr, len) { \
470 iovp->iov_base = (ptr); \
471 iovp->iov_len = (len); \
472 uio.uio_resid += (len); \
474 if (++uio.uio_iovcnt >= NIOV) { \
475 if (__sprint_r(data, fp, &uio)) \
480 #define PAD(howmany, with) { \
481 if ((n = (howmany)) > 0) { \
482 while (n > PADSIZE) { \
483 PRINT (with, PADSIZE); \
490 if (uio.uio_resid && __sprint_r(data, fp, &uio)) \
492 uio.uio_iovcnt = 0; \
496 /* Macros to support positional arguments */
498 #define GET_ARG(n, ap, type) \
501 ? args[n].val_##type \
502 : get_arg (data, n, fmt_anchor, &ap, &numargs, args, arg_type, &saved_fmt)->val_##type \
503 : arg_index++ < numargs \
504 ? args[n].val_##type \
505 : numargs < MAX_POS_ARGS \
506 ? args[numargs++].val_##type = va_arg (ap, type) \
507 : va_arg (ap, type) \
510 #define GET_ARG(n, ap, type) (va_arg (ap, type))
514 * To extend shorts properly, we need both signed and unsigned
515 * argument extraction methods.
519 (flags&QUADINT ? GET_ARG (N, ap, quad_t) : \
520 flags&LONGINT ? GET_ARG (N, ap, long) : \
521 flags&SHORTINT ? (long)(short)GET_ARG (N, ap, int) : \
522 flags&CHARINT ? (long)(signed char)GET_ARG (N, ap, int) : \
523 (long)GET_ARG (N, ap, int))
525 (flags&QUADINT ? GET_ARG (N, ap, u_quad_t) : \
526 flags&LONGINT ? GET_ARG (N, ap, u_long) : \
527 flags&SHORTINT ? (u_long)(u_short)GET_ARG (N, ap, int) : \
528 flags&CHARINT ? (u_long)(unsigned char)GET_ARG (N, ap, int) : \
529 (u_long)GET_ARG (N, ap, u_int))
532 (flags&LONGINT ? GET_ARG (N, ap, long) : \
533 flags&SHORTINT ? (long)(short)GET_ARG (N, ap, int) : \
534 flags&CHARINT ? (long)(signed char)GET_ARG (N, ap, int) : \
535 (long)GET_ARG (N, ap, int))
537 (flags&LONGINT ? GET_ARG (N, ap, u_long) : \
538 flags&SHORTINT ? (u_long)(u_short)GET_ARG (N, ap, int) : \
539 flags&CHARINT ? (u_long)(unsigned char)GET_ARG (N, ap, int) : \
540 (u_long)GET_ARG (N, ap, u_int))
543 CHECK_INIT (data, fp);
546 /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
547 if (cantwrite (data, fp)) {
552 /* optimise fprintf(stderr) (and other unbuffered Unix files) */
553 if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
556 return (__sbprintf (data, fp, fmt0, ap));
560 uio.uio_iov = iovp = iov;
573 * Scan the format for conversions (`%' character).
578 while ((n = _mbtowc_r (data, &wc, fmt, MB_CUR_MAX, &state)) > 0) {
584 while (*fmt != '\0' && *fmt != '%')
587 if ((m = fmt - cp) != 0) {
599 fmt++; /* skip over '%' */
612 reswitch: switch (ch) {
614 /* In the C locale, LC_NUMERIC requires
615 thousands_sep to be the empty string. And since
616 no other locales are supported (yet), this flag
617 is currently a no-op. */
621 * ``If the space and + flags both appear, the space
622 * flag will be ignored.''
634 /* we must check for positional arg used for dynamic width */
635 old_is_pos_arg = is_pos_arg;
637 if (is_digit (*fmt)) {
643 n = 10 * n + to_digit (ch);
645 } while (is_digit (ch));
648 if (n <= MAX_POS_ARGS) {
660 #endif /* !_NO_POS_ARGS */
663 * ``A negative field width argument is taken as a
664 * - flag followed by a positive field width.''
666 * They don't exclude field widths read from args.
668 width = GET_ARG (n, ap, int);
670 is_pos_arg = old_is_pos_arg;
683 if ((ch = *fmt++) == '*') {
686 /* we must check for positional arg used for dynamic width */
687 old_is_pos_arg = is_pos_arg;
689 if (is_digit (*fmt)) {
695 n = 10 * n + to_digit (ch);
697 } while (is_digit (ch));
700 if (n <= MAX_POS_ARGS) {
712 #endif /* !_NO_POS_ARGS */
713 prec = GET_ARG (n, ap, int);
715 is_pos_arg = old_is_pos_arg;
722 while (is_digit (ch)) {
723 n = 10 * n + to_digit (ch);
726 prec = n < 0 ? -1 : n;
730 * ``Note that 0 is taken as a flag, not as the
731 * beginning of a field width.''
736 case '1': case '2': case '3': case '4':
737 case '5': case '6': case '7': case '8': case '9':
740 n = 10 * n + to_digit (ch);
742 } while (is_digit (ch));
745 if (n <= MAX_POS_ARGS) {
753 #endif /* !_NO_POS_ARGS */
756 #ifdef FLOATING_POINT
781 if (sizeof (intmax_t) == sizeof (long))
787 if (sizeof (size_t) < sizeof (int))
788 /* POSIX states size_t is 16 or more bits, as is short. */
790 else if (sizeof (size_t) == sizeof (int))
791 /* no flag needed */;
792 else if (sizeof (size_t) <= sizeof (long))
795 /* POSIX states that at least one programming
796 environment must support size_t no wider than
797 long, but that means other environments can
798 have size_t as wide as long long. */
802 if (sizeof (ptrdiff_t) < sizeof (int))
803 /* POSIX states ptrdiff_t is 16 or more bits, as
806 else if (sizeof (ptrdiff_t) == sizeof (int))
807 /* no flag needed */;
808 else if (sizeof (ptrdiff_t) <= sizeof (long))
811 /* POSIX states that at least one programming
812 environment must support ptrdiff_t no wider than
813 long, but that means other environments can
814 have ptrdiff_t as wide as long long. */
820 if (ch == 'C' || (flags & LONGINT)) {
823 memset ((_PTR)&ps, '\0', sizeof (mbstate_t));
824 if ((size = (int)_wcrtomb_r (data, cp,
825 (wchar_t)GET_ARG (N, ap, wint_t),
827 fp->_flags |= __SERR;
832 *cp = GET_ARG (N, ap, int);
844 if ((quad_t)_uquad < 0)
846 if ((long) _uquad < 0)
855 #ifdef FLOATING_POINT
864 } else if ((ch == 'g' || ch == 'G') && prec == 0) {
869 if (flags & LONGDBL) {
870 _fpvalue = (double) GET_ARG (N, ap, _LONG_DOUBLE);
872 _fpvalue = GET_ARG (N, ap, double);
875 /* do this before tricky precision changes */
876 if (isinf (_fpvalue)) {
879 if (ch == 'E' || ch == 'F' || ch == 'G')
886 if (isnan (_fpvalue)) {
887 if (ch == 'E' || ch == 'F' || ch == 'G')
895 #else /* !_NO_LONGDBL */
897 if (flags & LONGDBL) {
898 _fpvalue = GET_ARG (N, ap, _LONG_DOUBLE);
900 _fpvalue = (_LONG_DOUBLE)GET_ARG (N, ap, double);
903 /* do this before tricky precision changes */
904 tmp = _ldcheck (&_fpvalue);
908 if (ch == 'E' || ch == 'F' || ch == 'G')
916 if (ch == 'E' || ch == 'F' || ch == 'G')
923 #endif /* !_NO_LONGDBL */
927 cp = cvt (data, _fpvalue, prec, flags, &softsign,
930 if (ch == 'g' || ch == 'G') {
931 if (expt <= -4 || expt > prec)
932 ch = (ch == 'g') ? 'e' : 'E';
936 if (ch <= 'e') { /* 'e' or 'E' fmt */
938 expsize = exponent (expstr, expt, ch);
939 size = expsize + ndig;
940 if (ndig > 1 || flags & ALT)
942 } else if (ch == 'f') { /* f fmt */
945 if (prec || flags & ALT)
948 size = (prec || flags & ALT)
951 } else if (expt >= ndig) { /* fixed g fmt */
956 size = ndig + (expt > 0 ?
962 #endif /* FLOATING_POINT */
966 *GET_ARG (N, ap, quad_ptr_t) = ret;
970 *GET_ARG (N, ap, long_ptr_t) = ret;
971 else if (flags & SHORTINT)
972 *GET_ARG (N, ap, short_ptr_t) = ret;
973 else if (flags & CHARINT)
974 *GET_ARG (N, ap, char_ptr_t) = ret;
976 *GET_ARG (N, ap, int_ptr_t) = ret;
977 continue; /* no output */
987 * ``The argument shall be a pointer to void. The
988 * value of the pointer is converted to a sequence
989 * of printable characters, in an implementation-
994 _uquad = (u_long)(unsigned _POINTER_INT)GET_ARG (N, ap, void_ptr_t);
996 xdigs = "0123456789abcdef";
1003 if ((cp = GET_ARG (N, ap, char_ptr_t)) == NULL) {
1007 else if (ch == 'S' || (flags & LONGINT)) {
1009 _CONST wchar_t *wcp;
1011 wcp = (_CONST wchar_t *)cp;
1013 memset ((_PTR)&ps, '\0', sizeof (mbstate_t));
1015 /* Count number of bytes needed for multibyte
1016 string that will be produced from widechar
1020 if (wcp[m] == L'\0')
1022 if ((n = (int)_wcrtomb_r (data,
1023 buf, wcp[m], &ps)) == -1) {
1024 fp->_flags |= __SERR;
1027 if (n + size > prec)
1036 if ((size = (int)_wcsrtombs_r (data,
1037 NULL, &wcp, 0, &ps)) == -1) {
1038 fp->_flags |= __SERR;
1041 wcp = (_CONST wchar_t *)cp;
1048 (char *)_malloc_r (data, size + 1)) == NULL) {
1049 fp->_flags |= __SERR;
1053 /* Convert widechar string to multibyte string. */
1054 memset ((_PTR)&ps, '\0', sizeof (mbstate_t));
1055 if (_wcsrtombs_r (data, malloc_buf,
1056 &wcp, size, &ps) != size) {
1057 fp->_flags |= __SERR;
1063 else if (prec >= 0) {
1065 * can't use strlen; can only look for the
1066 * NUL in the first `prec' characters, and
1067 * strlen () will go further.
1069 char *p = memchr (cp, 0, prec);
1089 xdigs = "0123456789ABCDEF";
1092 xdigs = "0123456789abcdef";
1093 hex: _uquad = UARG ();
1095 /* leading 0x/X only if non-zero */
1096 if (flags & ALT && _uquad != 0)
1099 /* unsigned conversions */
1100 nosign: sign = '\0';
1102 * ``... diouXx conversions ... if a precision is
1103 * specified, the 0 flag will be ignored.''
1106 number: if ((dprec = prec) >= 0)
1110 * ``The result of converting a zero value with an
1111 * explicit precision of zero is no characters.''
1115 if (_uquad != 0 || prec != 0) {
1117 * Unsigned mod is hard, and unsigned mod
1118 * by a constant is easier than that by
1119 * a variable; hence this switch.
1124 *--cp = to_char (_uquad & 7);
1127 /* handle octal leading 0 */
1128 if (flags & ALT && *cp != '0')
1133 /* many numbers are 1 digit */
1134 while (_uquad >= 10) {
1135 *--cp = to_char (_uquad % 10);
1138 *--cp = to_char (_uquad);
1143 *--cp = xdigs[_uquad & 15];
1149 cp = "bug in vfprintf: bad base";
1155 * ...result is to be converted to an 'alternate form'.
1156 * For o conversion, it increases the precision to force
1157 * the first digit of the result to be a zero."
1160 * To demonstrate this case, compile and run:
1161 * printf ("%#.0o",0);
1163 else if (base == OCT && (flags & ALT))
1166 size = buf + BUF - cp;
1169 default: /* "%?" prints ?, unless ? is NUL */
1172 /* pretend it was %c with argument ch */
1181 * All reasonable formats wind up here. At this point, `cp'
1182 * points to a string which (if not flags&LADJUST) should be
1183 * padded out to `width' places. If flags&ZEROPAD, it should
1184 * first be prefixed by any sign or other prefix; otherwise,
1185 * it should be blank padded before the prefix is emitted.
1186 * After any left-hand padding and prefixing, emit zeroes
1187 * required by a decimal [diouxX] precision, then print the
1188 * string proper, then emit zeroes required by any leftover
1189 * floating precision; finally, if LADJUST, pad with blanks.
1191 * Compute actual size, so we know how much to pad.
1192 * size excludes decimal prec; realsz includes it.
1194 realsz = dprec > size ? dprec : size;
1197 else if (flags & HEXPREFIX)
1200 /* right-adjusting blank padding */
1201 if ((flags & (LADJUST|ZEROPAD)) == 0)
1202 PAD (width - realsz, blanks);
1207 } else if (flags & HEXPREFIX) {
1213 /* right-adjusting zero padding */
1214 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
1215 PAD (width - realsz, zeroes);
1217 /* leading zeroes from decimal precision */
1218 PAD (dprec - size, zeroes);
1220 /* the string or number proper */
1221 #ifdef FLOATING_POINT
1222 if ((flags & FPT) == 0) {
1224 } else { /* glue together f_p fragments */
1225 if (ch >= 'f') { /* 'f' or 'g' */
1226 if (_fpvalue == 0) {
1227 /* kludge for __dtoa irregularity */
1229 if (expt < ndig || (flags & ALT) != 0) {
1230 PRINT (decimal_point, 1);
1231 PAD (ndig - 1, zeroes);
1233 } else if (expt <= 0) {
1236 PRINT (decimal_point, 1);
1237 PAD (-expt, zeroes);
1240 } else if (expt >= ndig) {
1242 PAD (expt - ndig, zeroes);
1249 PRINT (cp, ndig-expt);
1251 } else { /* 'e' or 'E' */
1252 if (ndig > 1 || flags & ALT) {
1258 } else /* 0.[0..] */
1259 /* __dtoa irregularity */
1260 PAD (ndig - 1, zeroes);
1263 PRINT (expstr, expsize);
1269 /* left-adjusting padding (always blank) */
1270 if (flags & LADJUST)
1271 PAD (width - realsz, blanks);
1273 /* finally, adjust ret */
1274 ret += width > realsz ? width : realsz;
1276 FLUSH (); /* copy out the I/O vectors */
1278 if (malloc_buf != NULL) {
1279 _free_r (data, malloc_buf);
1286 if (malloc_buf != NULL)
1287 _free_r (data, malloc_buf);
1289 return (__sferror (fp) ? EOF : ret);
1293 #ifdef FLOATING_POINT
1296 extern char *_dtoa_r _PARAMS((struct _reent *, double, int,
1297 int, int *, int *, char **));
1299 extern char *_ldtoa_r _PARAMS((struct _reent *, _LONG_DOUBLE, int,
1300 int, int *, int *, char **));
1302 #define word0(x) ldword0(x)
1307 _DEFUN(cvt, (data, value, ndigits, flags, sign, decpt, ch, length),
1308 struct _reent *data _AND
1318 _DEFUN(cvt, (data, value, ndigits, flags, sign, decpt, ch, length),
1319 struct _reent *data _AND
1320 _LONG_DOUBLE value _AND
1330 char *digits, *bp, *rve;
1332 union double_union tmp;
1342 mode = 3; /* ndigits after the decimal point */
1344 /* To obtain ndigits after the decimal point for the 'e'
1345 * and 'E' formats, round to ndigits + 1 significant
1348 if (ch == 'e' || ch == 'E') {
1351 mode = 2; /* ndigits significant digits */
1357 if (word0 (tmp) & Sign_bit) { /* this will check for < 0 and -0.0 */
1363 digits = _dtoa_r (data, value, mode, ndigits, decpt, &dsgn, &rve);
1364 #else /* !_NO_LONGDBL */
1366 if (ld.ieee.sign) { /* this will check for < 0 and -0.0 */
1372 digits = _ldtoa_r (data, value, mode, ndigits, decpt, &dsgn, &rve);
1373 #endif /* !_NO_LONGDBL */
1375 if ((ch != 'g' && ch != 'G') || flags & ALT) { /* Print trailing zeros */
1376 bp = digits + ndigits;
1378 if (*digits == '0' && value)
1379 *decpt = -ndigits + 1;
1382 if (value == 0) /* kludge for __dtoa irregularity */
1387 *length = rve - digits;
1392 _DEFUN(exponent, (p0, exp, fmtch),
1397 register char *p, *t;
1411 *--t = to_char (exp % 10);
1412 } while ((exp /= 10) > 9);
1413 *--t = to_char (exp);
1414 for (; t < expbuf + 40; *p++ = *t++);
1418 *p++ = to_char (exp);
1422 #endif /* FLOATING_POINT */
1425 #ifndef _NO_POS_ARGS
1427 /* Positional argument support.
1428 Written by Jeff Johnston
1430 Copyright (c) 2002 Red Hat Incorporated.
1431 All rights reserved.
1433 Redistribution and use in source and binary forms, with or without
1434 modification, are permitted provided that the following conditions are met:
1436 Redistributions of source code must retain the above copyright
1437 notice, this list of conditions and the following disclaimer.
1439 Redistributions in binary form must reproduce the above copyright
1440 notice, this list of conditions and the following disclaimer in the
1441 documentation and/or other materials provided with the distribution.
1443 The name of Red Hat Incorporated may not be used to endorse
1444 or promote products derived from this software without specific
1445 prior written permission.
1447 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1448 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1449 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1450 DISCLAIMED. IN NO EVENT SHALL RED HAT INCORPORATED BE LIABLE FOR ANY
1451 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1452 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1453 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1454 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1455 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1456 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
1462 MODFR, /* spec modifier */
1463 SPEC, /* format specifier */
1466 FLAG, /* format flag */
1467 OTHER, /* all other chars */
1468 MAX_CH_CLASS /* place-holder */
1473 SFLAG, /* seen a flag */
1474 WDIG, /* seen digits in width area */
1475 WIDTH, /* processed width */
1476 SMOD, /* seen spec modifier */
1477 SDOT, /* seen dot */
1478 VARW, /* have variable width specifier */
1479 VARP, /* have variable precision specifier */
1480 PREC, /* processed precision */
1481 VWDIG, /* have digits in variable width specification */
1482 VPDIG, /* have digits in variable precision specification */
1484 MAX_STATE, /* place-holder */
1488 NOOP, /* do nothing */
1489 NUMBER, /* build a number from digits */
1490 SKIPNUM, /* skip over digits */
1491 GETMOD, /* get and process format modifier */
1492 GETARG, /* get and process argument */
1493 GETPW, /* get variable precision or width */
1494 GETPWB, /* get variable precision or width and pushback fmt char */
1495 GETPOS, /* get positional parameter value */
1496 PWPOS, /* get positional parameter value for variable width or precision */
1499 _CONST static CH_CLASS chclass[256] = {
1500 /* 00-07 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1501 /* 08-0f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1502 /* 10-17 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1503 /* 18-1f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1504 /* 20-27 */ FLAG, OTHER, OTHER, FLAG, DOLLAR, OTHER, OTHER, FLAG,
1505 /* 28-2f */ OTHER, OTHER, STAR, FLAG, OTHER, FLAG, DOT, OTHER,
1506 /* 30-37 */ ZERO, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT,
1507 /* 38-3f */ DIGIT, DIGIT, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1508 /* 40-47 */ OTHER, OTHER, OTHER, SPEC, SPEC, SPEC, OTHER, SPEC,
1509 /* 48-4f */ OTHER, OTHER, OTHER, OTHER, MODFR, OTHER, OTHER, SPEC,
1510 /* 50-57 */ OTHER, OTHER, OTHER, SPEC, OTHER, SPEC, OTHER, SPEC,
1511 /* 58-5f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1512 /* 60-67 */ OTHER, OTHER, OTHER, SPEC, SPEC, SPEC, SPEC, SPEC,
1513 /* 68-6f */ MODFR, SPEC, MODFR, OTHER, MODFR, OTHER, OTHER, SPEC,
1514 /* 70-77 */ SPEC, MODFR, OTHER, SPEC, MODFR, SPEC, OTHER, OTHER,
1515 /* 78-7f */ SPEC, OTHER, MODFR, OTHER, OTHER, OTHER, OTHER, OTHER,
1516 /* 80-87 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1517 /* 88-8f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1518 /* 90-97 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1519 /* 98-9f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1520 /* a0-a7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1521 /* a8-af */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1522 /* b0-b7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1523 /* b8-bf */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1524 /* c0-c7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1525 /* c8-cf */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1526 /* d0-d7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1527 /* d8-df */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1528 /* e0-e7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1529 /* e8-ef */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1530 /* f0-f7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1531 /* f8-ff */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
1534 _CONST static STATE state_table[MAX_STATE][MAX_CH_CLASS] = {
1535 /* '0' '1-9' '$' MODFR SPEC '.' '*' FLAG OTHER */
1536 /* START */ { SFLAG, WDIG, DONE, SMOD, DONE, SDOT, VARW, SFLAG, DONE },
1537 /* SFLAG */ { SFLAG, WDIG, DONE, SMOD, DONE, SDOT, VARW, SFLAG, DONE },
1538 /* WDIG */ { DONE, DONE, WIDTH, SMOD, DONE, SDOT, DONE, DONE, DONE },
1539 /* WIDTH */ { DONE, DONE, DONE, SMOD, DONE, SDOT, DONE, DONE, DONE },
1540 /* SMOD */ { DONE, DONE, DONE, DONE, DONE, DONE, DONE, DONE, DONE },
1541 /* SDOT */ { SDOT, PREC, DONE, SMOD, DONE, DONE, VARP, DONE, DONE },
1542 /* VARW */ { DONE, VWDIG, DONE, SMOD, DONE, SDOT, DONE, DONE, DONE },
1543 /* VARP */ { DONE, VPDIG, DONE, SMOD, DONE, DONE, DONE, DONE, DONE },
1544 /* PREC */ { DONE, DONE, DONE, SMOD, DONE, DONE, DONE, DONE, DONE },
1545 /* VWDIG */ { DONE, DONE, WIDTH, DONE, DONE, DONE, DONE, DONE, DONE },
1546 /* VPDIG */ { DONE, DONE, PREC, DONE, DONE, DONE, DONE, DONE, DONE },
1549 _CONST static ACTION action_table[MAX_STATE][MAX_CH_CLASS] = {
1550 /* '0' '1-9' '$' MODFR SPEC '.' '*' FLAG OTHER */
1551 /* START */ { NOOP, NUMBER, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP },
1552 /* SFLAG */ { NOOP, NUMBER, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP },
1553 /* WDIG */ { NOOP, NOOP, GETPOS, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP },
1554 /* WIDTH */ { NOOP, NOOP, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP },
1555 /* SMOD */ { NOOP, NOOP, NOOP, NOOP, GETARG, NOOP, NOOP, NOOP, NOOP },
1556 /* SDOT */ { NOOP, SKIPNUM, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP },
1557 /* VARW */ { NOOP, NUMBER, NOOP, GETPW, GETPWB, GETPW, NOOP, NOOP, NOOP },
1558 /* VARP */ { NOOP, NUMBER, NOOP, GETPW, GETPWB, NOOP, NOOP, NOOP, NOOP },
1559 /* PREC */ { NOOP, NOOP, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP },
1560 /* VWDIG */ { NOOP, NOOP, PWPOS, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP },
1561 /* VPDIG */ { NOOP, NOOP, PWPOS, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP },
1564 /* function to get positional parameter N where n = N - 1 */
1565 static union arg_val *
1566 _DEFUN(get_arg, (data, n, fmt, ap, numargs_p, args, arg_type, last_fmt),
1567 struct _reent *data _AND
1572 union arg_val *args _AND
1579 int numargs = *numargs_p;
1581 STATE state, next_state;
1584 int max_pos_arg = n;
1585 enum types { INT, LONG_INT, SHORT_INT, CHAR_INT, QUAD_INT, CHAR, CHAR_PTR, DOUBLE, LONG_DOUBLE, WIDE_CHAR };
1592 /* if this isn't the first call, pick up where we left off last time */
1593 if (*last_fmt != NULL)
1597 memset (&wc_state, '\0', sizeof (wc_state));
1600 /* we need to process either to end of fmt string or until we have actually
1601 read the desired parameter from the vararg list. */
1602 while (*fmt && n >= numargs)
1605 while ((nbytes = _mbtowc_r (data, &wc, fmt, MB_CUR_MAX, &wc_state)) > 0)
1615 while (*fmt != '\0' && *fmt != '%')
1627 /* Use state/action table to process format specifiers. We ignore invalid
1628 formats and we are only interested in information that tells us how to
1629 read the vararg list. */
1630 while (state != DONE)
1633 chtype = chclass[ch];
1634 next_state = state_table[state][chtype];
1635 action = action_table[state][chtype];
1640 case GETMOD: /* we have format modifier */
1659 if (sizeof (intmax_t) == sizeof (long))
1665 if (sizeof (size_t) < sizeof (int))
1666 /* POSIX states size_t is 16 or more bits, as is short. */
1668 else if (sizeof (size_t) == sizeof (int))
1669 /* no flag needed */;
1670 else if (sizeof (size_t) <= sizeof (long))
1673 /* POSIX states that at least one programming
1674 environment must support size_t no wider than
1675 long, but that means other environments can
1676 have size_t as wide as long long. */
1680 if (sizeof (ptrdiff_t) < sizeof (int))
1681 /* POSIX states ptrdiff_t is 16 or more bits, as
1684 else if (sizeof (ptrdiff_t) == sizeof (int))
1685 /* no flag needed */;
1686 else if (sizeof (ptrdiff_t) <= sizeof (long))
1689 /* POSIX states that at least one programming
1690 environment must support ptrdiff_t no wider than
1691 long, but that means other environments can
1692 have ptrdiff_t as wide as long long. */
1707 case GETARG: /* we have format specifier */
1709 numargs &= (MAX_POS_ARGS - 1);
1710 /* process the specifier and translate it to a type to fetch from varargs */
1719 if (flags & LONGINT)
1720 spec_type = LONG_INT;
1721 else if (flags & SHORTINT)
1722 spec_type = SHORT_INT;
1723 else if (flags & CHARINT)
1724 spec_type = CHAR_INT;
1725 #ifndef _NO_LONGLONG
1726 else if (flags & QUADINT)
1727 spec_type = QUAD_INT;
1735 spec_type = LONG_INT;
1743 if (flags & LONGDBL)
1744 spec_type = LONG_DOUBLE;
1752 spec_type = CHAR_PTR;
1758 spec_type = WIDE_CHAR;
1762 /* if we have a positional parameter, just store the type, otherwise
1763 fetch the parameter from the vararg list */
1765 arg_type[pos] = spec_type;
1771 args[numargs++].val_long = va_arg (*ap, long);
1774 args[numargs++].val_quad_t = va_arg (*ap, quad_t);
1777 args[numargs++].val_wint_t = va_arg (*ap, wint_t);
1783 args[numargs++].val_int = va_arg (*ap, int);
1786 args[numargs++].val_char_ptr_t = va_arg (*ap, char *);
1789 args[numargs++].val_double = va_arg (*ap, double);
1792 args[numargs++].val__LONG_DOUBLE = va_arg (*ap, _LONG_DOUBLE);
1798 case GETPOS: /* we have positional specifier */
1799 if (arg_type[0] == -1)
1800 memset (arg_type, 0, sizeof (int) * MAX_POS_ARGS);
1802 max_pos_arg = (max_pos_arg > pos ? max_pos_arg : pos);
1804 case PWPOS: /* we have positional specifier for width or precision */
1805 if (arg_type[0] == -1)
1806 memset (arg_type, 0, sizeof (int) * MAX_POS_ARGS);
1808 arg_type[number] = INT;
1809 max_pos_arg = (max_pos_arg > number ? max_pos_arg : number);
1811 case GETPWB: /* we require format pushback */
1814 case GETPW: /* we have a variable precision or width to acquire */
1815 args[numargs++].val_int = va_arg (*ap, int);
1817 case NUMBER: /* we have a number to process */
1818 number = (ch - '0');
1819 while ((ch = *fmt) != '\0' && is_digit (ch))
1821 number = number * 10 + (ch - '0');
1825 case SKIPNUM: /* we have a number to skip */
1826 while ((ch = *fmt) != '\0' && is_digit (ch))
1831 break; /* do nothing */
1836 /* process all arguments up to at least the one we are looking for and if we
1837 have seen the end of the string, then process up to the max argument needed */
1839 last_arg = max_pos_arg;
1843 while (numargs <= last_arg)
1845 switch (arg_type[numargs])
1848 args[numargs++].val_long = va_arg (*ap, long);
1851 args[numargs++].val_quad_t = va_arg (*ap, quad_t);
1854 args[numargs++].val_char_ptr_t = va_arg (*ap, char *);
1857 args[numargs++].val_double = va_arg (*ap, double);
1860 args[numargs++].val__LONG_DOUBLE = va_arg (*ap, _LONG_DOUBLE);
1863 args[numargs++].val_wint_t = va_arg (*ap, wint_t);
1870 args[numargs++].val_int = va_arg (*ap, int);
1875 /* alter the global numargs value and keep a reference to the last bit of the fmt
1876 string we processed here because the caller will continue processing where we started */
1877 *numargs_p = numargs;
1881 #endif /* !_NO_POS_ARGS */