]>
git.saurik.com Git - apple/libc.git/blob - stdio/vfprintf.c
eb485ac78e24234e7a27d524cdf4ec32746845ac
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * Copyright (c) 1990, 1993
27 * The Regents of the University of California. All rights reserved.
29 * This code is derived from software contributed to Berkeley by
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * Actual printf innards.
64 * This code is large and complicated...
67 #include <sys/types.h>
73 #include <sys/sysctl.h>
84 /* Define FLOATING_POINT to get floating point. */
85 #define FLOATING_POINT
90 unsigned long ulongarg
;
101 long double longdoublearg
;
104 unsigned char vuchararg
[16];
105 signed char vchararg
[16];
106 unsigned short vushortarg
[8];
107 signed short vshortarg
[8];
108 unsigned int vuintarg
[4];
109 signed int vintarg
[4];
114 static int __sprint
__P((FILE *, struct __suio
*));
115 static int __sbprintf
__P((FILE *, const char *, va_list));
116 static char * __ultoa
__P((u_long
, char *, int, int, char *));
117 static char * __uqtoa
__P((u_quad_t
, char *, int, int, char *));
118 static void __find_arguments
__P((const char *, va_list, union arg
**));
119 static void __grow_type_table
__P((int, unsigned char **, int *));
122 * Get the argument indexed by nextarg. If the argument table is
123 * built, use it to get the argument. If its not, get the next
124 * argument (and arguments must be gotten sequentially).
126 #define GETARG(type) \
127 ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
128 (nextarg++, va_arg(ap, type)))
131 static void getvec(union arg
*dst
, const union arg
*argtable
, int nextarg
, va_list ap
)
133 vector
unsigned char tmp
;
135 tmp
= GETARG(vector
unsigned char);
136 memcpy( dst
, &tmp
, 16 );
142 * Flush out all the vectors defined by the given uio,
143 * then reset it so that it can be reused.
148 register struct __suio
*uio
;
152 if (uio
->uio_resid
== 0) {
156 err
= __sfvwrite(fp
, uio
);
163 * Helper function for `fprintf to unbuffered unix file': creates a
164 * temporary buffer. We only work on write-only files; this avoids
165 * worries about ungetc buffers and so forth.
168 __sbprintf(fp
, fmt
, ap
)
175 unsigned char buf
[BUFSIZ
];
177 /* copy the important variables */
178 fake
._flags
= fp
->_flags
& ~__SNBF
;
179 fake
._file
= fp
->_file
;
180 fake
._cookie
= fp
->_cookie
;
181 fake
._write
= fp
->_write
;
183 /* set up the buffer */
184 fake
._bf
._base
= fake
._p
= buf
;
185 fake
._bf
._size
= fake
._w
= sizeof(buf
);
186 fake
._lbfsize
= 0; /* not actually used, but Just In Case */
188 /* do the work, then copy any error status */
189 ret
= vfprintf(&fake
, fmt
, ap
);
190 if (ret
>= 0 && fflush(&fake
))
192 if (fake
._flags
& __SERR
)
193 fp
->_flags
|= __SERR
;
198 * Macros for converting digits to letters and vice versa
200 #define to_digit(c) ((c) - '0')
201 #define is_digit(c) ((unsigned)to_digit(c) <= 9)
202 #define to_char(n) ((n) + '0')
205 * Convert an unsigned long to ASCII for printf purposes, returning
206 * a pointer to the first character of the string representation.
207 * Octal numbers can be forced to have a leading zero; hex numbers
208 * use the given digits.
211 __ultoa(val
, endp
, base
, octzero
, xdigs
)
217 register char *cp
= endp
;
221 * Handle the three cases separately, in the hope of getting
222 * better/faster code.
226 if (val
< 10) { /* many numbers are 1 digit */
227 *--cp
= to_char(val
);
231 * On many machines, unsigned arithmetic is harder than
232 * signed arithmetic, so we do at most one unsigned mod and
233 * divide; this is sufficient to reduce the range of
234 * the incoming value to where signed arithmetic works.
236 if (val
> LONG_MAX
) {
237 *--cp
= to_char(val
% 10);
242 *--cp
= to_char(sval
% 10);
249 *--cp
= to_char(val
& 7);
252 if (octzero
&& *cp
!= '0')
258 *--cp
= xdigs
[val
& 15];
269 /* Identical to __ultoa, but for quads. */
271 __uqtoa(val
, endp
, base
, octzero
, xdigs
)
272 register u_quad_t val
;
277 register char *cp
= endp
;
278 register quad_t sval
;
280 /* quick test for small values; __ultoa is typically much faster */
281 /* (perhaps instead we should run until small, then call __ultoa?) */
282 if (val
<= ULONG_MAX
)
283 return (__ultoa((u_long
)val
, endp
, base
, octzero
, xdigs
));
287 *--cp
= to_char(val
% 10);
290 if (val
> QUAD_MAX
) {
291 *--cp
= to_char(val
% 10);
296 *--cp
= to_char(sval
% 10);
303 *--cp
= to_char(val
& 7);
306 if (octzero
&& *cp
!= '0')
312 *--cp
= xdigs
[val
& 15];
323 #ifdef FLOATING_POINT
327 #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
330 static char *cvt
__P((double, int, int, char *, int *, int, int *, char **));
331 static int exponent
__P((char *, int, int));
333 #if defined(__APPLE__)
335 * We don't want to be dependent on any libm symbols so use the versions in Libc
341 extern int isnan(double);
342 extern int isinf(double);
344 #endif /* __APPLE __ */
346 #else /* no FLOATING_POINT */
350 #endif /* FLOATING_POINT */
352 #define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */
355 * Flags used during conversion.
357 #define ALT 0x001 /* alternate form */
358 #define HEXPREFIX 0x002 /* add 0x or 0X prefix */
359 #define LADJUST 0x004 /* left adjustment */
360 #define LONGDBL 0x008 /* long double */
361 #define LONGINT 0x010 /* long integer */
362 #define QUADINT 0x020 /* quad integer */
363 #define SHORTINT 0x040 /* short integer */
364 #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */
365 #define FPT 0x100 /* Floating point number */
366 #define VECTOR 0x200 /* Altivec vector */
368 vfprintf(fp
, fmt0
, ap
)
373 register char *fmt
; /* format string */
374 register int ch
; /* character from fmt */
375 register int n
, n2
; /* handy integer (short term usage) */
376 register char *cp
; /* handy char pointer (short term usage) */
377 register struct __siov
*iovp
;/* for PRINT macro */
378 register int flags
; /* flags as above */
379 int ret
; /* return value accumulator */
380 int width
; /* width from format (%8d), or 0 */
381 int prec
; /* precision from format (%.3d), or -1 */
382 char sign
; /* sign prefix (' ', '+', '-', or \0) */
383 #ifdef FLOATING_POINT
384 char softsign
; /* temporary negative sign for floats */
385 double _double
= 0; /* double precision arguments %[eEfgG] */
386 int expt
; /* integer value of exponent */
387 int expsize
= 0; /* character count for expstr */
388 int ndig
; /* actual number of digits returned by cvt */
389 char expstr
[7]; /* buffer for exponent string */
390 char *dtoaresult
; /* buffer allocated by dtoa */
393 union arg vval
; /* Vector argument. */
394 char *pct
; /* Pointer to '%' at beginning of specifier. */
395 char vsep
; /* Vector separator character. */
397 u_long ulval
= 0; /* integer arguments %[diouxX] */
398 u_quad_t uqval
= 0; /* %q integers */
399 int base
; /* base for [diouxX] conversion */
400 int dprec
; /* a copy of prec if [diouxX], 0 otherwise */
401 int realsz
; /* field size expanded by dprec, sign, etc */
402 int size
; /* size of converted field or string */
403 int prsize
; /* max size of printed field */
404 char *xdigs
= NULL
; /* digits for [xX] conversion */
406 struct __suio uio
; /* output information: summary */
407 struct __siov iov
[NIOV
];/* ... and individual io vectors */
408 char buf
[BUF
]; /* space for %c, %[diouxX], %[eEfgG] */
409 char ox
[2]; /* space for 0x hex-prefix */
410 union arg
*argtable
; /* args, built due to positional arg */
411 union arg statargtable
[STATIC_ARG_TBL_SIZE
];
412 int nextarg
; /* 1-based argument index */
413 va_list orgap
; /* original argument pointer */
416 * Choose PADSIZE to trade efficiency vs. size. If larger printf
417 * fields occur frequently, increase PADSIZE and make the initialisers
420 #define PADSIZE 16 /* pad chunk size */
421 static char blanks
[PADSIZE
] =
422 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
423 static char zeroes
[PADSIZE
] =
424 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
427 * BEWARE, these `goto error' on error, and PAD uses `n'.
429 #define PRINT(ptr, len) { \
430 iovp->iov_base = (ptr); \
431 iovp->iov_len = (len); \
432 uio.uio_resid += (len); \
434 if (++uio.uio_iovcnt >= NIOV) { \
435 if (__sprint(fp, &uio)) \
440 #define PAD(howmany, with) { \
441 if ((n = (howmany)) > 0) { \
442 while (n > PADSIZE) { \
443 PRINT(with, PADSIZE); \
450 if (uio.uio_resid && __sprint(fp, &uio)) \
452 uio.uio_iovcnt = 0; \
458 * To extend shorts properly, we need both signed and unsigned
459 * argument extraction methods.
462 (flags&LONGINT ? GETARG(long) : \
463 flags&SHORTINT ? (long)(short)GETARG(int) : \
466 (flags&LONGINT ? GETARG(u_long) : \
467 flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
468 (u_long)GETARG(u_int))
471 * Get * arguments, including the form *nn$. Preserve the nextarg
472 * that the argument can be gotten once the type is determined.
474 #define GETASTER(val) \
477 while (is_digit(*cp)) { \
478 n2 = 10 * n2 + to_digit(*cp); \
482 int hold = nextarg; \
483 if (argtable == NULL) { \
484 argtable = statargtable; \
485 __find_arguments (fmt0, orgap, &argtable); \
488 val = GETARG (int); \
492 val = GETARG (int); \
494 #ifdef FLOATING_POINT
498 /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
500 /* FUNLOCKFILE(fp); */
504 /* optimise fprintf(stderr) (and other unbuffered Unix files) */
505 if ((fp
->_flags
& (__SNBF
|__SWR
|__SRW
)) == (__SNBF
|__SWR
) &&
507 /* FUNLOCKFILE(fp); */
508 return (__sbprintf(fp
, fmt0
, ap
));
515 uio
.uio_iov
= iovp
= iov
;
521 * Scan the format for conversions (`%' character).
524 for (cp
= fmt
; (ch
= *fmt
) != '\0' && ch
!= '%'; fmt
++)
526 if ((n
= fmt
- cp
) != 0) {
527 if ((unsigned)ret
+ n
> INT_MAX
) {
539 fmt
++; /* skip over '%' */
547 vsep
= 'X'; /* Illegal value, changed to defaults later. */
551 reswitch
: switch (ch
) {
554 * ``If the space and + flags both appear, the space
555 * flag will be ignored.''
565 case ',': case ';': case ':': case '_':
571 * ``A negative field width argument is taken as a
572 * - flag followed by a positive field width.''
574 * They don't exclude field widths read from args.
588 if ((ch
= *fmt
++) == '*') {
590 prec
= n
< 0 ? -1 : n
;
594 while (is_digit(ch
)) {
595 n
= 10 * n
+ to_digit(ch
);
598 prec
= n
< 0 ? -1 : n
;
602 * ``Note that 0 is taken as a flag, not as the
603 * beginning of a field width.''
608 case '1': case '2': case '3': case '4':
609 case '5': case '6': case '7': case '8': case '9':
612 n
= 10 * n
+ to_digit(ch
);
614 } while (is_digit(ch
));
617 if (argtable
== NULL
) {
618 argtable
= statargtable
;
619 __find_arguments (fmt0
, orgap
,
626 #ifdef FLOATING_POINT
649 if (sizeof(size_t) == sizeof(long))
651 if (sizeof(size_t) == sizeof(quad_t
))
656 if (flags
& VECTOR
) {
657 getvec(&vval
, argtable
, nextarg
, ap
);
662 *(cp
= buf
) = GETARG(int);
672 if (flags
& VECTOR
) {
673 getvec(&vval
, argtable
, nextarg
, ap
);
677 if (flags
& QUADINT
) {
678 uqval
= GETARG(quad_t
);
679 if ((quad_t
)uqval
< 0) {
685 if ((long)ulval
< 0) {
692 #ifdef FLOATING_POINT
697 if (flags
& VECTOR
) {
699 getvec(&vval
, argtable
, nextarg
, ap
);
708 if (flags
& VECTOR
) {
710 getvec(&vval
, argtable
, nextarg
, ap
);
717 fp_begin
: if (prec
== -1)
720 /* XXX this loses precision. */
721 _double
= (double)GETARG(long double);
723 _double
= GETARG(double);
724 /* do this before tricky precision changes */
725 if (isinf(_double
)) {
732 if (isnan(_double
)) {
738 if (dtoaresult
!= NULL
) {
742 cp
= cvt(_double
, prec
, flags
, &softsign
,
743 &expt
, ch
, &ndig
, &dtoaresult
);
744 if (ch
== 'g' || ch
== 'G') {
745 if (expt
<= -4 || expt
> prec
)
746 ch
= (ch
== 'g') ? 'e' : 'E';
750 if (ch
<= 'e') { /* 'e' or 'E' fmt */
752 expsize
= exponent(expstr
, expt
, ch
);
753 size
= expsize
+ ndig
;
754 if (ndig
> 1 || flags
& ALT
)
756 } else if (ch
== 'f') { /* f fmt */
759 if (prec
|| flags
& ALT
)
763 } else if (expt
>= ndig
) { /* fixed g fmt */
768 size
= ndig
+ (expt
> 0 ?
774 #endif /* FLOATING_POINT */
777 *GETARG(quad_t
*) = ret
;
778 else if (flags
& LONGINT
)
779 *GETARG(long *) = ret
;
780 else if (flags
& SHORTINT
)
781 *GETARG(short *) = ret
;
783 *GETARG(int *) = ret
;
784 continue; /* no output */
790 if (flags
& VECTOR
) {
791 getvec(&vval
, argtable
, nextarg
, ap
);
797 uqval
= GETARG(u_quad_t
);
804 * ``The argument shall be a pointer to void. The
805 * value of the pointer is converted to a sequence
806 * of printable characters, in an implementation-
811 if (flags
& VECTOR
) {
812 getvec(&vval
, argtable
, nextarg
, ap
);
817 ulval
= (u_long
)GETARG(void *);
819 xdigs
= "0123456789abcdef";
820 flags
= (flags
& ~QUADINT
) | HEXPREFIX
;
824 if ((cp
= GETARG(char *)) == NULL
)
828 * can't use strlen; can only look for the
829 * NUL in the first `prec' characters, and
830 * strlen() will go further.
832 char *p
= memchr(cp
, 0, (size_t)prec
);
849 if (flags
& VECTOR
) {
850 getvec(&vval
, argtable
, nextarg
, ap
);
856 uqval
= GETARG(u_quad_t
);
862 xdigs
= "0123456789ABCDEF";
865 xdigs
= "0123456789abcdef";
868 if (flags
& VECTOR
) {
869 getvec(&vval
, argtable
, nextarg
, ap
);
875 uqval
= GETARG(u_quad_t
);
879 /* leading 0x/X only if non-zero */
881 (flags
& QUADINT
? uqval
!= 0 : ulval
!= 0))
884 /* unsigned conversions */
887 * ``... diouXx conversions ... if a precision is
888 * specified, the 0 flag will be ignored.''
891 number
: if ((dprec
= prec
) >= 0)
895 * ``The result of converting a zero value with an
896 * explicit precision of zero is no characters.''
900 if (flags
& QUADINT
) {
901 if (uqval
!= 0 || prec
!= 0)
902 cp
= __uqtoa(uqval
, cp
, base
,
905 if (ulval
!= 0 || prec
!= 0)
906 cp
= __ultoa(ulval
, cp
, base
,
909 size
= buf
+ BUF
- cp
;
911 default: /* "%?" prints ?, unless ? is NUL */
914 /* pretend it was %c with argument ch */
923 if (flags
& VECTOR
) {
925 * Do the minimum amount of work necessary to construct
926 * a format specifier that can be used to recursively
927 * call vfprintf() for each element in the vector.
929 int i
, j
; /* Counter. */
930 int vcnt
; /* Number of elements in vector. */
931 char *vfmt
; /* Pointer to format specifier. */
932 char vfmt_buf
[32]; /* Static buffer for format spec. */
933 int vwidth
= 0; /* Width specified via '*'. */
934 int vprec
= 0; /* Precision specified via '*'. */
935 union { /* Element. */
939 char *vstr
; /* Used for asprintf(). */
940 int vlen
; /* Length returned by asprintf(). */
943 * Set vfmt. If vfmt_buf may not be big enough,
944 * malloc() space, taking care to free it later.
946 if (&fmt
[-1] - pct
< sizeof(vfmt_buf
))
949 vfmt
= (char *)malloc(&fmt
[-1] - pct
+ 1);
951 /* Set the separator character, if not specified. */
959 /* Create the format specifier. */
960 for (i
= j
= 0; i
< &fmt
[-1] - pct
; i
++) {
962 case ',': case ';': case ':': case '_':
963 case 'v': case 'h': case 'l':
967 if (pct
[i
- 1] != '.')
978 * Determine the number of elements in the vector and
979 * finish up the format specifier.
981 if (flags
& SHORTINT
) {
984 } else if (flags
& LONGINT
) {
998 * The default case should never
1015 /* Get a vector element. */
1016 #define VPRINT(cnt, ind, args...) do { \
1017 if (flags & FPT) { \
1018 velm.f = vval.vfloatarg[ind]; \
1019 vlen = asprintf(&vstr, vfmt , ## args, velm.f); \
1023 /* The default case should never happen. */ \
1025 velm.i = vval.vintarg[ind]; \
1028 velm.i = vval.vshortarg[ind]; \
1031 velm.i = vval.vchararg[ind]; \
1034 vlen = asprintf(&vstr, vfmt , ## args, velm.i); \
1037 PRINT(vstr, vlen); \
1042 /* Actually print. */
1045 /* First element. */
1047 for (i
= 1; i
< vcnt
; i
++) {
1055 /* First element. */
1056 VPRINT(vcnt
, 0, prec
);
1057 for (i
= 1; i
< vcnt
; i
++) {
1062 VPRINT(vcnt
, i
, prec
);
1067 /* First element. */
1068 VPRINT(vcnt
, 0, width
);
1069 for (i
= 1; i
< vcnt
; i
++) {
1074 VPRINT(vcnt
, i
, width
);
1077 /* First element. */
1078 VPRINT(vcnt
, 0, width
, prec
);
1079 for (i
= 1; i
< vcnt
; i
++) {
1084 VPRINT(vcnt
, i
, width
, prec
);
1090 if (vfmt
!= vfmt_buf
)
1097 * All reasonable formats wind up here. At this point, `cp'
1098 * points to a string which (if not flags&LADJUST) should be
1099 * padded out to `width' places. If flags&ZEROPAD, it should
1100 * first be prefixed by any sign or other prefix; otherwise,
1101 * it should be blank padded before the prefix is emitted.
1102 * After any left-hand padding and prefixing, emit zeroes
1103 * required by a decimal [diouxX] precision, then print the
1104 * string proper, then emit zeroes required by any leftover
1105 * floating precision; finally, if LADJUST, pad with blanks.
1107 * Compute actual size, so we know how much to pad.
1108 * size excludes decimal prec; realsz includes it.
1110 realsz
= dprec
> size
? dprec
: size
;
1113 else if (flags
& HEXPREFIX
)
1116 prsize
= width
> realsz
? width
: realsz
;
1117 if ((unsigned)ret
+ prsize
> INT_MAX
) {
1122 /* right-adjusting blank padding */
1123 if ((flags
& (LADJUST
|ZEROPAD
)) == 0)
1124 PAD(width
- realsz
, blanks
);
1129 } else if (flags
& HEXPREFIX
) {
1135 /* right-adjusting zero padding */
1136 if ((flags
& (LADJUST
|ZEROPAD
)) == ZEROPAD
)
1137 PAD(width
- realsz
, zeroes
);
1139 /* leading zeroes from decimal precision */
1140 PAD(dprec
- size
, zeroes
);
1142 /* the string or number proper */
1143 #ifdef FLOATING_POINT
1144 if ((flags
& FPT
) == 0) {
1146 } else { /* glue together f_p fragments */
1147 if (ch
>= 'f') { /* 'f' or 'g' */
1149 /* kludge for __dtoa irregularity */
1151 (flags
& ALT
) == 0) {
1155 PAD(ndig
- 1, zeroes
);
1157 } else if (expt
<= 0) {
1161 } else if (expt
>= ndig
) {
1163 PAD(expt
- ndig
, zeroes
);
1170 PRINT(cp
, ndig
-expt
);
1172 } else { /* 'e' or 'E' */
1173 if (ndig
> 1 || flags
& ALT
) {
1179 } else /* 0.[0..] */
1180 /* __dtoa irregularity */
1181 PAD(ndig
- 1, zeroes
);
1184 PRINT(expstr
, expsize
);
1191 /* left-adjusting padding (always blank) */
1192 if (flags
& LADJUST
)
1193 PAD(width
- realsz
, blanks
);
1195 /* finally, adjust ret */
1198 FLUSH(); /* copy out the I/O vectors */
1203 #ifdef FLOATING_POINT
1204 if (dtoaresult
!= NULL
)
1209 /* FUNLOCKFILE(fp); */
1210 if ((argtable
!= NULL
) && (argtable
!= statargtable
))
1217 * Type ids for argument type table.
1233 #define T_LONG_DOUBLE 14
1239 * Find all arguments when a positional parameter is encountered. Returns a
1240 * table, indexed by argument number, of pointers to each arguments. The
1241 * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
1242 * It will be replaces with a malloc-ed one if it overflows.
1245 __find_arguments (fmt0
, ap
, argtable
)
1248 union arg
**argtable
;
1250 register char *fmt
; /* format string */
1251 register int ch
; /* character from fmt */
1252 register int n
, n2
; /* handy integer (short term usage) */
1253 register char *cp
; /* handy char pointer (short term usage) */
1254 register int flags
; /* flags as above */
1255 int width
; /* width from format (%8d), or 0 */
1256 unsigned char *typetable
; /* table of types */
1257 unsigned char stattypetable
[STATIC_ARG_TBL_SIZE
];
1258 int tablesize
; /* current size of type table */
1259 int tablemax
; /* largest used index in table */
1260 int nextarg
; /* 1-based argument index */
1263 * Add an argument type to the table, expanding if necessary.
1265 #define ADDTYPE(type) \
1266 ((nextarg >= tablesize) ? \
1267 __grow_type_table(nextarg, &typetable, &tablesize) : 0, \
1268 (nextarg > tablemax) ? tablemax = nextarg : 0, \
1269 typetable[nextarg++] = type)
1272 ((flags&LONGINT) ? ADDTYPE(T_LONG) : \
1273 ((flags&SHORTINT) ? ADDTYPE(T_SHORT) : ADDTYPE(T_INT)))
1276 ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : \
1277 ((flags&SHORTINT) ? ADDTYPE(T_U_SHORT) : ADDTYPE(T_U_INT)))
1280 * Add * arguments to the type array.
1282 #define ADDASTER() \
1285 while (is_digit(*cp)) { \
1286 n2 = 10 * n2 + to_digit(*cp); \
1290 int hold = nextarg; \
1299 typetable
= stattypetable
;
1300 tablesize
= STATIC_ARG_TBL_SIZE
;
1303 memset (typetable
, T_UNUSED
, STATIC_ARG_TBL_SIZE
);
1306 * Scan the format for conversions (`%' character).
1309 for (cp
= fmt
; (ch
= *fmt
) != '\0' && ch
!= '%'; fmt
++)
1313 fmt
++; /* skip over '%' */
1319 reswitch
: switch (ch
) {
1330 if ((ch
= *fmt
++) == '*') {
1334 while (is_digit(ch
)) {
1340 case '1': case '2': case '3': case '4':
1341 case '5': case '6': case '7': case '8': case '9':
1344 n
= 10 * n
+ to_digit(ch
);
1346 } while (is_digit(ch
));
1353 #ifdef FLOATING_POINT
1362 if (flags
& LONGINT
)
1388 if (flags
& QUADINT
) {
1394 #ifdef FLOATING_POINT
1405 if (flags
& LONGDBL
)
1406 ADDTYPE(T_LONG_DOUBLE
);
1410 #endif /* FLOATING_POINT */
1412 if (flags
& QUADINT
)
1414 else if (flags
& LONGINT
)
1416 else if (flags
& SHORTINT
)
1420 continue; /* no output */
1430 if (flags
& QUADINT
)
1455 if (flags
& QUADINT
)
1467 if (flags
& QUADINT
)
1472 default: /* "%?" prints ?, unless ? is NUL */
1480 * Build the argument table.
1482 if (tablemax
>= STATIC_ARG_TBL_SIZE
) {
1483 *argtable
= (union arg
*)
1484 malloc (sizeof (union arg
) * (tablemax
+ 1));
1487 (*argtable
) [0].intarg
= NULL
;
1488 for (n
= 1; n
<= tablemax
; n
++) {
1489 switch (typetable
[n
]) {
1491 (*argtable
) [n
].intarg
= va_arg (ap
, int);
1494 (*argtable
) [n
].intarg
= va_arg (ap
, int);
1497 (*argtable
) [n
].intarg
= va_arg (ap
, int);
1500 (*argtable
) [n
].pshortarg
= va_arg (ap
, short *);
1503 (*argtable
) [n
].intarg
= va_arg (ap
, int);
1506 (*argtable
) [n
].uintarg
= va_arg (ap
, unsigned int);
1509 (*argtable
) [n
].pintarg
= va_arg (ap
, int *);
1512 (*argtable
) [n
].longarg
= va_arg (ap
, long);
1515 (*argtable
) [n
].ulongarg
= va_arg (ap
, unsigned long);
1518 (*argtable
) [n
].plongarg
= va_arg (ap
, long *);
1521 (*argtable
) [n
].quadarg
= va_arg (ap
, quad_t
);
1524 (*argtable
) [n
].uquadarg
= va_arg (ap
, u_quad_t
);
1527 (*argtable
) [n
].pquadarg
= va_arg (ap
, quad_t
*);
1529 #ifdef FLOATING_POINT
1531 (*argtable
) [n
].doublearg
= va_arg (ap
, double);
1534 (*argtable
) [n
].longdoublearg
= va_arg (ap
, long double);
1540 getvec( &((*argtable
) [n
]), NULL
, tmp
, ap
);
1544 (*argtable
) [n
].pchararg
= va_arg (ap
, char *);
1547 (*argtable
) [n
].pvoidarg
= va_arg (ap
, void *);
1552 if ((typetable
!= NULL
) && (typetable
!= stattypetable
))
1557 * Increase the size of the type table.
1560 __grow_type_table (nextarg
, typetable
, tablesize
)
1562 unsigned char **typetable
;
1565 unsigned char *const oldtable
= *typetable
;
1566 const int oldsize
= *tablesize
;
1567 unsigned char *newtable
;
1568 int newsize
= oldsize
* 2;
1570 if (newsize
< nextarg
+ 1)
1571 newsize
= nextarg
+ 1;
1572 if (oldsize
== STATIC_ARG_TBL_SIZE
) {
1573 if ((newtable
= malloc (newsize
)) == NULL
)
1574 abort(); /* XXX handle better */
1575 bcopy (oldtable
, newtable
, oldsize
);
1577 if ((newtable
= realloc (oldtable
, newsize
)) == NULL
)
1578 abort(); /* XXX handle better */
1580 memset (&newtable
[oldsize
], T_UNUSED
, (newsize
- oldsize
));
1582 *typetable
= newtable
;
1583 *tablesize
= newsize
;
1587 #ifdef FLOATING_POINT
1589 extern char *__dtoa
__P((double, int, int, int *, int *, char **, char **));
1592 cvt(value
, ndigits
, flags
, sign
, decpt
, ch
, length
, dtoaresultp
)
1594 int ndigits
, flags
, *decpt
, ch
, *length
;
1599 char *digits
, *bp
, *rve
;
1602 mode
= 3; /* ndigits after the decimal point */
1605 * To obtain ndigits after the decimal point for the 'e'
1606 * and 'E' formats, round to ndigits + 1 significant
1609 if (ch
== 'e' || ch
== 'E')
1611 mode
= 2; /* ndigits significant digits */
1618 digits
= __dtoa(value
, mode
, ndigits
, decpt
, &dsgn
, &rve
, dtoaresultp
);
1619 if ((ch
!= 'g' && ch
!= 'G') || flags
& ALT
) {
1620 /* print trailing zeros */
1621 bp
= digits
+ ndigits
;
1623 if (*digits
== '0' && value
)
1624 *decpt
= -ndigits
+ 1;
1627 if (value
== 0) /* kludge for __dtoa irregularity */
1632 *length
= rve
- digits
;
1637 exponent(p0
, exp
, fmtch
)
1641 register char *p
, *t
;
1642 char expbuf
[MAXEXP
];
1652 t
= expbuf
+ MAXEXP
;
1655 *--t
= to_char(exp
% 10);
1656 } while ((exp
/= 10) > 9);
1657 *--t
= to_char(exp
);
1658 for (; t
< expbuf
+ MAXEXP
; *p
++ = *t
++);
1662 *p
++ = to_char(exp
);
1666 #endif /* FLOATING_POINT */