2 * Copyright (c) 1990 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
38 * Actual printf innards.
40 * This code is large and complicated...
43 #include <sys/types.h>
56 #include <errno_private.h>
61 static void __find_arguments (const char *fmt0
, va_list ap
,
63 static int __grow_type_table (unsigned char **typetable
,
67 * Flush out all the vectors defined by the given uio,
68 * then reset it so that it can be reused.
72 __sprint(FILE *fp
, register struct __suio
*uio
)
76 if (uio
->uio_resid
== 0) {
80 err
= __sfvwrite(fp
, uio
);
88 * Helper function for `fprintf to unbuffered unix file': creates a
89 * temporary buffer. We only work on write-only files; this avoids
90 * worries about ungetc buffers and so forth.
94 __sbprintf(register FILE *fp
, const char *fmt
, va_list ap
)
98 unsigned char buf
[BUFSIZ
];
100 /* copy the important variables */
101 fake
._flags
= fp
->_flags
& ~__SNBF
;
102 fake
._file
= fp
->_file
;
103 fake
._cookie
= fp
->_cookie
;
104 fake
._write
= fp
->_write
;
106 /* set up the buffer */
107 fake
._bf
._base
= fake
._p
= buf
;
108 fake
._bf
._size
= fake
._w
= sizeof(buf
);
109 fake
._lbfsize
= 0; /* not actually used, but Just In Case */
111 /* do the work, then copy any error status */
112 ret
= vfprintf(&fake
, fmt
, ap
);
113 if (ret
>= 0 && fflush(&fake
))
115 if (fake
._flags
& __SERR
)
116 fp
->_flags
|= __SERR
;
121 #ifdef FLOATING_POINT
126 #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
129 static char *cvt (double, int, int, char *, int *, int, int *);
130 static int exponent (char *, int, int);
132 #else /* no FLOATING_POINT */
134 #endif /* FLOATING_POINT */
136 #define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */
140 * Macros for converting digits to letters and vice versa
142 #define to_digit(c) ((c) - '0')
143 #define is_digit(c) ((unsigned)to_digit(c) <= 9)
144 #define to_char(n) ((n) + '0')
147 * Flags used during conversion.
149 #define ALT 0x001 /* alternate form */
150 #define HEXPREFIX 0x002 /* add 0x or 0X prefix */
151 #define LADJUST 0x004 /* left adjustment */
152 #define LONGDBL 0x008 /* long double; unimplemented */
153 #define LONGINT 0x010 /* long integer */
154 #define QUADINT 0x020 /* quad integer */
155 #define SHORTINT 0x040 /* short integer */
156 #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */
157 #define FPT 0x100 /* Floating point number */
160 vfprintf(FILE *fp
, const char *fmt0
, va_list ap
)
162 register char *fmt
; /* format string */
163 register int ch
; /* character from fmt */
164 register int n
, m
, n2
; /* handy integers (short term usage) */
165 register char *cp
; /* handy char pointer (short term usage) */
166 register struct __siov
*iovp
;/* for PRINT macro */
167 register int flags
; /* flags as above */
168 int ret
; /* return value accumulator */
169 int width
; /* width from format (%8d), or 0 */
170 int prec
; /* precision from format (%.3d), or -1 */
171 char sign
; /* sign prefix (' ', '+', '-', or \0) */
173 #ifdef FLOATING_POINT
174 char *decimal_point
= localeconv()->decimal_point
;
175 char softsign
; /* temporary negative sign for floats */
176 double _double
; /* double precision arguments %[eEfgG] */
177 int expt
; /* integer value of exponent */
178 int expsize
; /* character count for expstr */
179 int ndig
; /* actual number of digits returned by cvt */
180 char expstr
[7]; /* buffer for exponent string */
183 #ifdef __GNUC__ /* gcc has builtin quad type (long long) SOS */
184 #define quad_t long long
185 #define u_quad_t unsigned long long
188 u_quad_t _uquad
; /* integer arguments %[diouxX] */
189 enum { OCT
, DEC
, HEX
} base
;/* base for [diouxX] conversion */
190 int dprec
; /* a copy of prec if [diouxX], 0 otherwise */
191 int realsz
; /* field size expanded by dprec */
192 int size
; /* size of converted field or string */
193 char *xdigs
=NULL
; /* digits for [xX] conversion */
195 struct __suio uio
; /* output information: summary */
196 struct __siov iov
[NIOV
];/* ... and individual io vectors */
197 char buf
[BUF
]; /* space for %c, %[diouxX], %[eEfgG] */
198 char ox
[2]; /* space for 0x hex-prefix */
199 va_list *argtable
; /* args, built due to positional arg */
200 va_list statargtable
[STATIC_ARG_TBL_SIZE
];
201 int nextarg
; /* 1-based argument index */
202 va_list orgap
; /* original argument pointer */
205 * Choose PADSIZE to trade efficiency vs. size. If larger printf
206 * fields occur frequently, increase PADSIZE and make the initialisers
209 #define PADSIZE 16 /* pad chunk size */
210 static char blanks
[PADSIZE
] =
211 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
212 static char zeroes
[PADSIZE
] =
213 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
216 * BEWARE, these `goto error' on error, and PAD uses `n'.
218 #define PRINT(ptr, len) do { \
219 iovp->iov_base = (ptr); \
220 iovp->iov_len = (len); \
221 uio.uio_resid += (len); \
223 if (++uio.uio_iovcnt >= NIOV) { \
224 if (__sprint(fp, &uio)) \
229 #define PAD(howmany, with) do { \
230 if ((n = (howmany)) > 0) { \
231 while (n > PADSIZE) { \
232 PRINT(with, PADSIZE); \
238 #define FLUSH() do { \
239 if (uio.uio_resid && __sprint(fp, &uio)) \
241 uio.uio_iovcnt = 0; \
246 * To extend shorts properly, we need both signed and unsigned
247 * argument extraction methods.
250 (flags&QUADINT ? va_arg(ap, quad_t) : \
251 flags&LONGINT ? GETARG(long) : \
252 flags&SHORTINT ? (long)(short)GETARG(int) : \
255 (flags&QUADINT ? va_arg(ap, u_quad_t) : \
256 flags&LONGINT ? GETARG(u_long) : \
257 flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
258 (u_long)GETARG(u_int))
261 * Get * arguments, including the form *nn$. Preserve the nextarg
262 * that the argument can be gotten once the type is determined.
264 #define GETASTER(val) \
267 while (is_digit(*cp)) { \
268 n2 = 10 * n2 + to_digit(*cp); \
272 int hold = nextarg; \
273 if (argtable == NULL) { \
274 argtable = statargtable; \
275 __find_arguments(fmt0, orgap, &argtable); \
287 * Get the argument indexed by nextarg. If the argument table is
288 * built, use it to get the argument. If its not, get the next
289 * argument (and arguments must be gotten sequentially).
291 #define GETARG(type) \
292 (((argtable != NULL) ? (void)(ap = argtable[nextarg]) : (void)0), \
293 nextarg++, va_arg(ap, type))
295 /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
301 /* optimise fprintf(stderr) (and other unbuffered Unix files) */
302 if ((fp
->_flags
& (__SNBF
|__SWR
|__SRW
)) == (__SNBF
|__SWR
) &&
304 return (__sbprintf(fp
, fmt0
, ap
));
310 uio
.uio_iov
= iovp
= iov
;
316 * Scan the format for conversions (`%' character).
320 while ((n
= mbtowc(&wc
, fmt
, MB_CUR_MAX
)) > 0) {
327 if ((m
= fmt
- cp
) != 0) {
333 fmt
++; /* skip over '%' */
342 reswitch
: switch (ch
) {
345 * ``If the space and + flags both appear, the space
346 * flag will be ignored.''
357 * ``A negative field width argument is taken as a
358 * - flag followed by a positive field width.''
360 * They don't exclude field widths read from args.
374 if ((ch
= *fmt
++) == '*') {
376 prec
= n
< 0 ? -1 : n
;
380 while (is_digit(ch
)) {
381 n
= 10 * n
+ to_digit(ch
);
386 if (argtable
== NULL
) {
387 argtable
= statargtable
;
388 __find_arguments(fmt0
, orgap
,
393 prec
= n
< 0 ? -1 : n
;
397 * ``Note that 0 is taken as a flag, not as the
398 * beginning of a field width.''
403 case '1': case '2': case '3': case '4':
404 case '5': case '6': case '7': case '8': case '9':
407 n
= 10 * n
+ to_digit(ch
);
409 } while (is_digit(ch
));
412 if (argtable
== NULL
) {
413 argtable
= statargtable
;
414 __find_arguments(fmt0
, orgap
,
423 #ifdef FLOATING_POINT
443 *(cp
= buf
) = GETARG(int);
453 if ((quad_t
)_uquad
< 0) {
459 #ifdef FLOATING_POINT
467 } else if ((ch
== 'g' || ch
== 'G') && prec
== 0) {
471 if (flags
& LONGDBL
) {
472 _double
= (double) GETARG(long double);
474 _double
= GETARG(double);
477 /* do this before tricky precision changes */
478 if (isinf(_double
)) {
485 if (isnan(_double
)) {
492 cp
= cvt(_double
, prec
, flags
, &softsign
,
494 if (ch
== 'g' || ch
== 'G') {
495 if (expt
<= -4 || expt
> prec
)
496 ch
= (ch
== 'g') ? 'e' : 'E';
500 if (ch
<= 'e') { /* 'e' or 'E' fmt */
502 expsize
= exponent(expstr
, expt
, ch
);
503 size
= expsize
+ ndig
;
504 if (ndig
> 1 || flags
& ALT
)
506 } else if (ch
== 'f') { /* f fmt */
509 if (prec
|| flags
& ALT
)
513 } else if (expt
>= ndig
) { /* fixed g fmt */
518 size
= ndig
+ (expt
> 0 ?
524 #endif /* FLOATING_POINT */
527 *GETARG(quad_t
*) = ret
;
528 else if (flags
& LONGINT
)
529 *GETARG(long *) = ret
;
530 else if (flags
& SHORTINT
)
531 *GETARG(short *) = ret
;
533 *GETARG(int *) = ret
;
534 continue; /* no output */
544 * ``The argument shall be a pointer to void. The
545 * value of the pointer is converted to a sequence
546 * of printable characters, in an implementation-
551 _uquad
= (u_long
)GETARG(void *);
553 xdigs
= "0123456789abcdef";
558 if ((cp
= GETARG(char *)) == NULL
)
562 * can't use strlen; can only look for the
563 * NUL in the first `prec' characters, and
564 * strlen() will go further.
566 char *p
= memchr(cp
, 0, prec
);
586 xdigs
= "0123456789ABCDEF";
589 xdigs
= "0123456789abcdef";
590 hex
: _uquad
= UARG();
592 /* leading 0x/X only if non-zero */
593 if (flags
& ALT
&& _uquad
!= 0)
596 /* unsigned conversions */
599 * ``... diouXx conversions ... if a precision is
600 * specified, the 0 flag will be ignored.''
603 number
: if ((dprec
= prec
) >= 0)
607 * ``The result of converting a zero value with an
608 * explicit precision of zero is no characters.''
612 if (_uquad
!= 0 || prec
!= 0) {
614 * Unsigned mod is hard, and unsigned mod
615 * by a constant is easier than that by
616 * a variable; hence this switch.
621 *--cp
= to_char(_uquad
& 7);
624 /* handle octal leading 0 */
625 if (flags
& ALT
&& *cp
!= '0')
630 /* many numbers are 1 digit */
631 while (_uquad
>= 10) {
632 *--cp
= to_char(_uquad
% 10);
635 *--cp
= to_char(_uquad
);
640 *--cp
= xdigs
[_uquad
& 15];
646 cp
= "bug in vfprintf: bad base";
651 size
= buf
+ BUF
- cp
;
654 default: /* "%?" prints ?, unless ? is NUL */
657 /* pretend it was %c with argument ch */
666 * All reasonable formats wind up here. At this point, `cp'
667 * points to a string which (if not flags&LADJUST) should be
668 * padded out to `width' places. If flags&ZEROPAD, it should
669 * first be prefixed by any sign or other prefix; otherwise,
670 * it should be blank padded before the prefix is emitted.
671 * After any left-hand padding and prefixing, emit zeroes
672 * required by a decimal [diouxX] precision, then print the
673 * string proper, then emit zeroes required by any leftover
674 * floating precision; finally, if LADJUST, pad with blanks.
676 * Compute actual size, so we know how much to pad.
677 * size excludes decimal prec; realsz includes it.
679 realsz
= dprec
> size
? dprec
: size
;
682 else if (flags
& HEXPREFIX
)
685 /* right-adjusting blank padding */
686 if ((flags
& (LADJUST
|ZEROPAD
)) == 0)
687 PAD(width
- realsz
, blanks
);
692 } else if (flags
& HEXPREFIX
) {
698 /* right-adjusting zero padding */
699 if ((flags
& (LADJUST
|ZEROPAD
)) == ZEROPAD
)
700 PAD(width
- realsz
, zeroes
);
702 /* leading zeroes from decimal precision */
703 PAD(dprec
- size
, zeroes
);
705 /* the string or number proper */
706 #ifdef FLOATING_POINT
707 if ((flags
& FPT
) == 0) {
709 } else { /* glue together f_p fragments */
710 if (ch
>= 'f') { /* 'f' or 'g' */
712 /* kludge for __dtoa irregularity */
714 if (expt
< ndig
|| (flags
& ALT
) != 0) {
715 PRINT(decimal_point
, 1);
716 PAD(ndig
- 1, zeroes
);
718 } else if (expt
<= 0) {
720 PRINT(decimal_point
, 1);
723 } else if (expt
>= ndig
) {
725 PAD(expt
- ndig
, zeroes
);
732 PRINT(cp
, ndig
-expt
);
734 } else { /* 'e' or 'E' */
735 if (ndig
> 1 || flags
& ALT
) {
742 /* __dtoa irregularity */
743 PAD(ndig
- 1, zeroes
);
746 PRINT(expstr
, expsize
);
752 /* left-adjusting padding (always blank) */
754 PAD(width
- realsz
, blanks
);
756 /* finally, adjust ret */
757 ret
+= width
> realsz
? width
: realsz
;
758 FLUSH(); /* copy out the I/O vectors */
764 if (argtable
!= NULL
&& argtable
!= statargtable
)
766 return (__sferror(fp
) ? EOF
: ret
);
771 * Type ids for argument type table.
787 #define T_LONG_DOUBLE 14
793 * Find all arguments when a positional parameter is encountered. Returns a
794 * table, indexed by argument number, of pointers to each arguments. The
795 * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
796 * It will be replaces with a malloc-ed on if it overflows.
800 __find_arguments(const char *fmt0
, va_list ap
, va_list **argtable
)
802 register char *fmt
; /* format string */
803 register int ch
; /* character from fmt */
804 register int n
, n2
; /* handy integer (short term usage) */
805 register char *cp
; /* handy char pointer (short term usage) */
806 register int flags
; /* flags as above */
807 unsigned char *typetable
; /* table of types */
808 unsigned char stattypetable
[STATIC_ARG_TBL_SIZE
];
809 int tablesize
; /* current size of type table */
810 int tablemax
; /* largest used index in table */
811 int nextarg
; /* 1-based argument index */
814 * Add an argument type to the table, expanding if necessary.
816 #define ADDTYPE(type) \
817 ((nextarg >= tablesize) ? \
818 __grow_type_table(&typetable, &tablesize) : 0, \
819 typetable[nextarg++] = type, \
820 (nextarg > tablemax) ? tablemax = nextarg : 0)
823 ((flags&LONGINT) ? ADDTYPE(T_LONG) : \
824 ((flags&SHORTINT) ? ADDTYPE(T_SHORT) : ADDTYPE(T_INT)))
827 ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : \
828 ((flags&SHORTINT) ? ADDTYPE(T_U_SHORT) : ADDTYPE(T_U_INT)))
831 * Add * arguments to the type array.
836 while (is_digit(*cp)) { \
837 n2 = 10 * n2 + to_digit(*cp); \
841 int hold = nextarg; \
850 typetable
= stattypetable
;
851 tablesize
= STATIC_ARG_TBL_SIZE
;
854 memset(typetable
, T_UNUSED
, STATIC_ARG_TBL_SIZE
);
857 * Scan the format for conversions (`%' character).
860 for (cp
= fmt
; (ch
= *fmt
) != '\0' && ch
!= '%'; fmt
++)
864 fmt
++; /* skip over '%' */
869 reswitch
: switch (ch
) {
880 if ((ch
= *fmt
++) == '*') {
884 while (is_digit(ch
)) {
890 case '1': case '2': case '3': case '4':
891 case '5': case '6': case '7': case '8': case '9':
894 n
= 10 * n
+ to_digit(ch
);
896 } while (is_digit(ch
));
904 #ifdef FLOATING_POINT
931 if (flags
& QUADINT
) {
937 #ifdef FLOATING_POINT
944 ADDTYPE(T_LONG_DOUBLE
);
948 #endif /* FLOATING_POINT */
952 else if (flags
& LONGINT
)
954 else if (flags
& SHORTINT
)
958 continue; /* no output */
990 default: /* "%?" prints ?, unless ? is NUL */
998 * Build the argument table.
1000 if (tablemax
>= STATIC_ARG_TBL_SIZE
) {
1001 *argtable
= (va_list *)
1002 malloc(sizeof (va_list) * (tablemax
+ 1));
1006 /* XXX is this required? */
1007 (*argtable
) [0] = NULL
;
1009 for (n
= 1; n
<= tablemax
; n
++) {
1010 (*argtable
)[n
] = ap
;
1011 switch (typetable
[n
]) {
1013 (void) va_arg(ap
, int);
1016 (void) va_arg(ap
, int);
1019 (void) va_arg(ap
, int);
1022 (void) va_arg(ap
, short *);
1025 (void) va_arg(ap
, int);
1028 (void) va_arg(ap
, unsigned int);
1031 (void) va_arg(ap
, int *);
1034 (void) va_arg(ap
, long);
1037 (void) va_arg(ap
, unsigned long);
1040 (void) va_arg(ap
, long *);
1043 (void) va_arg(ap
, quad_t
);
1046 (void) va_arg(ap
, u_quad_t
);
1049 (void) va_arg(ap
, quad_t
*);
1052 (void) va_arg(ap
, double);
1055 (void) va_arg(ap
, long double);
1058 (void) va_arg(ap
, char *);
1061 (void) va_arg(ap
, void *);
1066 if (typetable
!= NULL
&& typetable
!= stattypetable
)
1072 * Increase the size of the type table.
1076 __grow_type_table(unsigned char **typetable
, int *tablesize
)
1078 unsigned char *oldtable
= *typetable
;
1079 int newsize
= *tablesize
* 2;
1081 if (*tablesize
== STATIC_ARG_TBL_SIZE
) {
1082 *typetable
= (unsigned char *)
1083 malloc(sizeof (unsigned char) * newsize
);
1085 bcopy(oldtable
, *typetable
, *tablesize
);
1087 *typetable
= (unsigned char *)
1088 realloc(*typetable
, sizeof (unsigned char) * newsize
);
1091 memset(*typetable
+ *tablesize
, T_UNUSED
, (newsize
- *tablesize
));
1093 *tablesize
= newsize
;
1098 #ifdef FLOATING_POINT
1100 extern char *__dtoa
__P((double, int, int, int *, int *, char **));
1103 cvt(double value
, int ndigits
, int flags
, char *sign
, int *decpt
, int ch
, int *length
)
1106 char *digits
, *bp
, *rve
;
1109 mode
= 3; /* ndigits after the decimal point */
1111 /* To obtain ndigits after the decimal point for the 'e'
1112 * and 'E' formats, round to ndigits + 1 significant
1115 if (ch
== 'e' || ch
== 'E') {
1118 mode
= 2; /* ndigits significant digits */
1126 digits
= __dtoa(value
, mode
, ndigits
, decpt
, &dsgn
, &rve
);
1127 if ((ch
!= 'g' && ch
!= 'G') || flags
& ALT
) { /* Print trailing zeros */
1128 bp
= digits
+ ndigits
;
1130 if (*digits
== '0' && value
)
1131 *decpt
= -ndigits
+ 1;
1134 if (value
== 0) /* kludge for __dtoa irregularity */
1139 *length
= rve
- digits
;
1145 exponent(char *p0
, int exp
, int fmtch
)
1147 register char *p
, *t
;
1148 char expbuf
[MAXEXP
];
1158 t
= expbuf
+ MAXEXP
;
1161 *--t
= to_char(exp
% 10);
1162 } while ((exp
/= 10) > 9);
1163 *--t
= to_char(exp
);
1164 for (; t
< expbuf
+ MAXEXP
; *p
++ = *t
++);
1168 *p
++ = to_char(exp
);
1172 #endif /* FLOATING_POINT */