]>
git.saurik.com Git - apple/libc.git/blob - stdio/vfprintf.c
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1990, 1993
24 * The Regents of the University of California. All rights reserved.
26 * This code is derived from software contributed to Berkeley by
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. All advertising materials mentioning features or use of this software
38 * must display the following acknowledgement:
39 * This product includes software developed by the University of
40 * California, Berkeley and its contributors.
41 * 4. Neither the name of the University nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * Actual printf innards.
61 * This code is large and complicated...
64 #include <sys/types.h>
70 #include <sys/sysctl.h>
81 /* Define FLOATING_POINT to get floating point. */
82 #define FLOATING_POINT
87 unsigned long ulongarg
;
98 long double longdoublearg
;
101 unsigned char vuchararg
[16];
102 signed char vchararg
[16];
103 unsigned short vushortarg
[8];
104 signed short vshortarg
[8];
105 unsigned int vuintarg
[4];
106 signed int vintarg
[4];
111 static int __sprint
__P((FILE *, struct __suio
*));
112 static int __sbprintf
__P((FILE *, const char *, va_list));
113 static char * __ultoa
__P((u_long
, char *, int, int, char *));
114 static char * __uqtoa
__P((u_quad_t
, char *, int, int, char *));
115 static void __find_arguments
__P((const char *, va_list, union arg
**));
116 static void __grow_type_table
__P((int, unsigned char **, int *));
119 * Get the argument indexed by nextarg. If the argument table is
120 * built, use it to get the argument. If its not, get the next
121 * argument (and arguments must be gotten sequentially).
123 #define GETARG(type) \
124 ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
125 (nextarg++, va_arg(ap, type)))
128 static void getvec(union arg
*dst
, const union arg
*argtable
, int nextarg
, va_list ap
)
130 vector
unsigned char tmp
;
132 tmp
= GETARG(vector
unsigned char);
133 memcpy( dst
, &tmp
, 16 );
139 * Flush out all the vectors defined by the given uio,
140 * then reset it so that it can be reused.
145 register struct __suio
*uio
;
149 if (uio
->uio_resid
== 0) {
153 err
= __sfvwrite(fp
, uio
);
160 * Helper function for `fprintf to unbuffered unix file': creates a
161 * temporary buffer. We only work on write-only files; this avoids
162 * worries about ungetc buffers and so forth.
165 __sbprintf(fp
, fmt
, ap
)
172 unsigned char buf
[BUFSIZ
];
174 /* copy the important variables */
175 fake
._flags
= fp
->_flags
& ~__SNBF
;
176 fake
._file
= fp
->_file
;
177 fake
._cookie
= fp
->_cookie
;
178 fake
._write
= fp
->_write
;
180 /* set up the buffer */
181 fake
._bf
._base
= fake
._p
= buf
;
182 fake
._bf
._size
= fake
._w
= sizeof(buf
);
183 fake
._lbfsize
= 0; /* not actually used, but Just In Case */
185 /* do the work, then copy any error status */
186 ret
= vfprintf(&fake
, fmt
, ap
);
187 if (ret
>= 0 && fflush(&fake
))
189 if (fake
._flags
& __SERR
)
190 fp
->_flags
|= __SERR
;
195 * Macros for converting digits to letters and vice versa
197 #define to_digit(c) ((c) - '0')
198 #define is_digit(c) ((unsigned)to_digit(c) <= 9)
199 #define to_char(n) ((n) + '0')
202 * Convert an unsigned long to ASCII for printf purposes, returning
203 * a pointer to the first character of the string representation.
204 * Octal numbers can be forced to have a leading zero; hex numbers
205 * use the given digits.
208 __ultoa(val
, endp
, base
, octzero
, xdigs
)
214 register char *cp
= endp
;
218 * Handle the three cases separately, in the hope of getting
219 * better/faster code.
223 if (val
< 10) { /* many numbers are 1 digit */
224 *--cp
= to_char(val
);
228 * On many machines, unsigned arithmetic is harder than
229 * signed arithmetic, so we do at most one unsigned mod and
230 * divide; this is sufficient to reduce the range of
231 * the incoming value to where signed arithmetic works.
233 if (val
> LONG_MAX
) {
234 *--cp
= to_char(val
% 10);
239 *--cp
= to_char(sval
% 10);
246 *--cp
= to_char(val
& 7);
249 if (octzero
&& *cp
!= '0')
255 *--cp
= xdigs
[val
& 15];
266 /* Identical to __ultoa, but for quads. */
268 __uqtoa(val
, endp
, base
, octzero
, xdigs
)
269 register u_quad_t val
;
274 register char *cp
= endp
;
275 register quad_t sval
;
277 /* quick test for small values; __ultoa is typically much faster */
278 /* (perhaps instead we should run until small, then call __ultoa?) */
279 if (val
<= ULONG_MAX
)
280 return (__ultoa((u_long
)val
, endp
, base
, octzero
, xdigs
));
284 *--cp
= to_char(val
% 10);
287 if (val
> QUAD_MAX
) {
288 *--cp
= to_char(val
% 10);
293 *--cp
= to_char(sval
% 10);
300 *--cp
= to_char(val
& 7);
303 if (octzero
&& *cp
!= '0')
309 *--cp
= xdigs
[val
& 15];
320 #ifdef FLOATING_POINT
324 #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
327 static char *cvt
__P((double, int, int, char *, int *, int, int *, char **));
328 static int exponent
__P((char *, int, int));
330 #if defined(__APPLE__)
332 * We don't want to be dependent on any libm symbols so use the versions in Libc
338 extern int isnan(double);
339 extern int isinf(double);
341 #endif /* __APPLE __ */
343 #else /* no FLOATING_POINT */
347 #endif /* FLOATING_POINT */
349 #define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */
352 * Flags used during conversion.
354 #define ALT 0x001 /* alternate form */
355 #define HEXPREFIX 0x002 /* add 0x or 0X prefix */
356 #define LADJUST 0x004 /* left adjustment */
357 #define LONGDBL 0x008 /* long double */
358 #define LONGINT 0x010 /* long integer */
359 #define QUADINT 0x020 /* quad integer */
360 #define SHORTINT 0x040 /* short integer */
361 #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */
362 #define FPT 0x100 /* Floating point number */
363 #define VECTOR 0x200 /* Altivec vector */
365 vfprintf(fp
, fmt0
, ap
)
370 register char *fmt
; /* format string */
371 register int ch
; /* character from fmt */
372 register int n
, n2
; /* handy integer (short term usage) */
373 register char *cp
; /* handy char pointer (short term usage) */
374 register struct __siov
*iovp
;/* for PRINT macro */
375 register int flags
; /* flags as above */
376 int ret
; /* return value accumulator */
377 int width
; /* width from format (%8d), or 0 */
378 int prec
; /* precision from format (%.3d), or -1 */
379 char sign
; /* sign prefix (' ', '+', '-', or \0) */
380 #ifdef FLOATING_POINT
381 char softsign
; /* temporary negative sign for floats */
382 double _double
= 0; /* double precision arguments %[eEfgG] */
383 int expt
; /* integer value of exponent */
384 int expsize
= 0; /* character count for expstr */
385 int ndig
; /* actual number of digits returned by cvt */
386 char expstr
[7]; /* buffer for exponent string */
387 char *dtoaresult
; /* buffer allocated by dtoa */
390 union arg vval
; /* Vector argument. */
391 char *pct
; /* Pointer to '%' at beginning of specifier. */
392 char vsep
; /* Vector separator character. */
394 u_long ulval
= 0; /* integer arguments %[diouxX] */
395 u_quad_t uqval
= 0; /* %q integers */
396 int base
; /* base for [diouxX] conversion */
397 int dprec
; /* a copy of prec if [diouxX], 0 otherwise */
398 int realsz
; /* field size expanded by dprec, sign, etc */
399 int size
; /* size of converted field or string */
400 int prsize
; /* max size of printed field */
401 char *xdigs
= NULL
; /* digits for [xX] conversion */
403 struct __suio uio
; /* output information: summary */
404 struct __siov iov
[NIOV
];/* ... and individual io vectors */
405 char buf
[BUF
]; /* space for %c, %[diouxX], %[eEfgG] */
406 char ox
[2]; /* space for 0x hex-prefix */
407 union arg
*argtable
; /* args, built due to positional arg */
408 union arg statargtable
[STATIC_ARG_TBL_SIZE
];
409 int nextarg
; /* 1-based argument index */
410 va_list orgap
; /* original argument pointer */
413 * Choose PADSIZE to trade efficiency vs. size. If larger printf
414 * fields occur frequently, increase PADSIZE and make the initialisers
417 #define PADSIZE 16 /* pad chunk size */
418 static char blanks
[PADSIZE
] =
419 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
420 static char zeroes
[PADSIZE
] =
421 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
424 * BEWARE, these `goto error' on error, and PAD uses `n'.
426 #define PRINT(ptr, len) { \
427 iovp->iov_base = (ptr); \
428 iovp->iov_len = (len); \
429 uio.uio_resid += (len); \
431 if (++uio.uio_iovcnt >= NIOV) { \
432 if (__sprint(fp, &uio)) \
437 #define PAD(howmany, with) { \
438 if ((n = (howmany)) > 0) { \
439 while (n > PADSIZE) { \
440 PRINT(with, PADSIZE); \
447 if (uio.uio_resid && __sprint(fp, &uio)) \
449 uio.uio_iovcnt = 0; \
455 * To extend shorts properly, we need both signed and unsigned
456 * argument extraction methods.
459 (flags&LONGINT ? GETARG(long) : \
460 flags&SHORTINT ? (long)(short)GETARG(int) : \
463 (flags&LONGINT ? GETARG(u_long) : \
464 flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
465 (u_long)GETARG(u_int))
468 * Get * arguments, including the form *nn$. Preserve the nextarg
469 * that the argument can be gotten once the type is determined.
471 #define GETASTER(val) \
474 while (is_digit(*cp)) { \
475 n2 = 10 * n2 + to_digit(*cp); \
479 int hold = nextarg; \
480 if (argtable == NULL) { \
481 argtable = statargtable; \
482 __find_arguments (fmt0, orgap, &argtable); \
485 val = GETARG (int); \
489 val = GETARG (int); \
491 #ifdef FLOATING_POINT
495 /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
497 /* FUNLOCKFILE(fp); */
501 /* optimise fprintf(stderr) (and other unbuffered Unix files) */
502 if ((fp
->_flags
& (__SNBF
|__SWR
|__SRW
)) == (__SNBF
|__SWR
) &&
504 /* FUNLOCKFILE(fp); */
505 return (__sbprintf(fp
, fmt0
, ap
));
512 uio
.uio_iov
= iovp
= iov
;
518 * Scan the format for conversions (`%' character).
521 for (cp
= fmt
; (ch
= *fmt
) != '\0' && ch
!= '%'; fmt
++)
523 if ((n
= fmt
- cp
) != 0) {
524 if ((unsigned)ret
+ n
> INT_MAX
) {
536 fmt
++; /* skip over '%' */
544 vsep
= 'X'; /* Illegal value, changed to defaults later. */
548 reswitch
: switch (ch
) {
551 * ``If the space and + flags both appear, the space
552 * flag will be ignored.''
562 case ',': case ';': case ':': case '_':
568 * ``A negative field width argument is taken as a
569 * - flag followed by a positive field width.''
571 * They don't exclude field widths read from args.
585 if ((ch
= *fmt
++) == '*') {
587 prec
= n
< 0 ? -1 : n
;
591 while (is_digit(ch
)) {
592 n
= 10 * n
+ to_digit(ch
);
595 prec
= n
< 0 ? -1 : n
;
599 * ``Note that 0 is taken as a flag, not as the
600 * beginning of a field width.''
605 case '1': case '2': case '3': case '4':
606 case '5': case '6': case '7': case '8': case '9':
609 n
= 10 * n
+ to_digit(ch
);
611 } while (is_digit(ch
));
614 if (argtable
== NULL
) {
615 argtable
= statargtable
;
616 __find_arguments (fmt0
, orgap
,
623 #ifdef FLOATING_POINT
646 if (sizeof(size_t) == sizeof(long))
648 if (sizeof(size_t) == sizeof(quad_t
))
653 if (flags
& VECTOR
) {
654 getvec(&vval
, argtable
, nextarg
, ap
);
659 *(cp
= buf
) = GETARG(int);
669 if (flags
& VECTOR
) {
670 getvec(&vval
, argtable
, nextarg
, ap
);
674 if (flags
& QUADINT
) {
675 uqval
= GETARG(quad_t
);
676 if ((quad_t
)uqval
< 0) {
682 if ((long)ulval
< 0) {
689 #ifdef FLOATING_POINT
694 if (flags
& VECTOR
) {
696 getvec(&vval
, argtable
, nextarg
, ap
);
705 if (flags
& VECTOR
) {
707 getvec(&vval
, argtable
, nextarg
, ap
);
714 fp_begin
: if (prec
== -1)
717 /* XXX this loses precision. */
718 _double
= (double)GETARG(long double);
720 _double
= GETARG(double);
721 /* do this before tricky precision changes */
722 if (isinf(_double
)) {
729 if (isnan(_double
)) {
735 if (dtoaresult
!= NULL
) {
739 cp
= cvt(_double
, prec
, flags
, &softsign
,
740 &expt
, ch
, &ndig
, &dtoaresult
);
741 if (ch
== 'g' || ch
== 'G') {
742 if (expt
<= -4 || expt
> prec
)
743 ch
= (ch
== 'g') ? 'e' : 'E';
747 if (ch
<= 'e') { /* 'e' or 'E' fmt */
749 expsize
= exponent(expstr
, expt
, ch
);
750 size
= expsize
+ ndig
;
751 if (ndig
> 1 || flags
& ALT
)
753 } else if (ch
== 'f') { /* f fmt */
756 if (prec
|| flags
& ALT
)
760 } else if (expt
>= ndig
) { /* fixed g fmt */
765 size
= ndig
+ (expt
> 0 ?
771 #endif /* FLOATING_POINT */
774 *GETARG(quad_t
*) = ret
;
775 else if (flags
& LONGINT
)
776 *GETARG(long *) = ret
;
777 else if (flags
& SHORTINT
)
778 *GETARG(short *) = ret
;
780 *GETARG(int *) = ret
;
781 continue; /* no output */
787 if (flags
& VECTOR
) {
788 getvec(&vval
, argtable
, nextarg
, ap
);
794 uqval
= GETARG(u_quad_t
);
801 * ``The argument shall be a pointer to void. The
802 * value of the pointer is converted to a sequence
803 * of printable characters, in an implementation-
808 if (flags
& VECTOR
) {
809 getvec(&vval
, argtable
, nextarg
, ap
);
814 ulval
= (u_long
)GETARG(void *);
816 xdigs
= "0123456789abcdef";
817 flags
= (flags
& ~QUADINT
) | HEXPREFIX
;
821 if ((cp
= GETARG(char *)) == NULL
)
825 * can't use strlen; can only look for the
826 * NUL in the first `prec' characters, and
827 * strlen() will go further.
829 char *p
= memchr(cp
, 0, (size_t)prec
);
846 if (flags
& VECTOR
) {
847 getvec(&vval
, argtable
, nextarg
, ap
);
853 uqval
= GETARG(u_quad_t
);
859 xdigs
= "0123456789ABCDEF";
862 xdigs
= "0123456789abcdef";
865 if (flags
& VECTOR
) {
866 getvec(&vval
, argtable
, nextarg
, ap
);
872 uqval
= GETARG(u_quad_t
);
876 /* leading 0x/X only if non-zero */
878 (flags
& QUADINT
? uqval
!= 0 : ulval
!= 0))
881 /* unsigned conversions */
884 * ``... diouXx conversions ... if a precision is
885 * specified, the 0 flag will be ignored.''
888 number
: if ((dprec
= prec
) >= 0)
892 * ``The result of converting a zero value with an
893 * explicit precision of zero is no characters.''
897 if (flags
& QUADINT
) {
898 if (uqval
!= 0 || prec
!= 0)
899 cp
= __uqtoa(uqval
, cp
, base
,
902 if (ulval
!= 0 || prec
!= 0)
903 cp
= __ultoa(ulval
, cp
, base
,
906 size
= buf
+ BUF
- cp
;
908 default: /* "%?" prints ?, unless ? is NUL */
911 /* pretend it was %c with argument ch */
920 if (flags
& VECTOR
) {
922 * Do the minimum amount of work necessary to construct
923 * a format specifier that can be used to recursively
924 * call vfprintf() for each element in the vector.
926 int i
, j
; /* Counter. */
927 int vcnt
; /* Number of elements in vector. */
928 char *vfmt
; /* Pointer to format specifier. */
929 char vfmt_buf
[32]; /* Static buffer for format spec. */
930 int vwidth
= 0; /* Width specified via '*'. */
931 int vprec
= 0; /* Precision specified via '*'. */
932 union { /* Element. */
936 char *vstr
; /* Used for asprintf(). */
937 int vlen
; /* Length returned by asprintf(). */
940 * Set vfmt. If vfmt_buf may not be big enough,
941 * malloc() space, taking care to free it later.
943 if (&fmt
[-1] - pct
< sizeof(vfmt_buf
))
946 vfmt
= (char *)malloc(&fmt
[-1] - pct
+ 1);
948 /* Set the separator character, if not specified. */
956 /* Create the format specifier. */
957 for (i
= j
= 0; i
< &fmt
[-1] - pct
; i
++) {
959 case ',': case ';': case ':': case '_':
960 case 'v': case 'h': case 'l':
964 if (pct
[i
- 1] != '.')
975 * Determine the number of elements in the vector and
976 * finish up the format specifier.
978 if (flags
& SHORTINT
) {
981 } else if (flags
& LONGINT
) {
995 * The default case should never
1012 /* Get a vector element. */
1013 #define VPRINT(cnt, ind, args...) do { \
1014 if (flags & FPT) { \
1015 velm.f = vval.vfloatarg[ind]; \
1016 vlen = asprintf(&vstr, vfmt , ## args, velm.f); \
1020 /* The default case should never happen. */ \
1022 velm.i = vval.vintarg[ind]; \
1025 velm.i = vval.vshortarg[ind]; \
1028 velm.i = vval.vchararg[ind]; \
1031 vlen = asprintf(&vstr, vfmt , ## args, velm.i); \
1034 PRINT(vstr, vlen); \
1039 /* Actually print. */
1042 /* First element. */
1044 for (i
= 1; i
< vcnt
; i
++) {
1052 /* First element. */
1053 VPRINT(vcnt
, 0, prec
);
1054 for (i
= 1; i
< vcnt
; i
++) {
1059 VPRINT(vcnt
, i
, prec
);
1064 /* First element. */
1065 VPRINT(vcnt
, 0, width
);
1066 for (i
= 1; i
< vcnt
; i
++) {
1071 VPRINT(vcnt
, i
, width
);
1074 /* First element. */
1075 VPRINT(vcnt
, 0, width
, prec
);
1076 for (i
= 1; i
< vcnt
; i
++) {
1081 VPRINT(vcnt
, i
, width
, prec
);
1087 if (vfmt
!= vfmt_buf
)
1094 * All reasonable formats wind up here. At this point, `cp'
1095 * points to a string which (if not flags&LADJUST) should be
1096 * padded out to `width' places. If flags&ZEROPAD, it should
1097 * first be prefixed by any sign or other prefix; otherwise,
1098 * it should be blank padded before the prefix is emitted.
1099 * After any left-hand padding and prefixing, emit zeroes
1100 * required by a decimal [diouxX] precision, then print the
1101 * string proper, then emit zeroes required by any leftover
1102 * floating precision; finally, if LADJUST, pad with blanks.
1104 * Compute actual size, so we know how much to pad.
1105 * size excludes decimal prec; realsz includes it.
1107 realsz
= dprec
> size
? dprec
: size
;
1110 else if (flags
& HEXPREFIX
)
1113 prsize
= width
> realsz
? width
: realsz
;
1114 if ((unsigned)ret
+ prsize
> INT_MAX
) {
1119 /* right-adjusting blank padding */
1120 if ((flags
& (LADJUST
|ZEROPAD
)) == 0)
1121 PAD(width
- realsz
, blanks
);
1126 } else if (flags
& HEXPREFIX
) {
1132 /* right-adjusting zero padding */
1133 if ((flags
& (LADJUST
|ZEROPAD
)) == ZEROPAD
)
1134 PAD(width
- realsz
, zeroes
);
1136 /* leading zeroes from decimal precision */
1137 PAD(dprec
- size
, zeroes
);
1139 /* the string or number proper */
1140 #ifdef FLOATING_POINT
1141 if ((flags
& FPT
) == 0) {
1143 } else { /* glue together f_p fragments */
1144 if (ch
>= 'f') { /* 'f' or 'g' */
1146 /* kludge for __dtoa irregularity */
1148 (flags
& ALT
) == 0) {
1152 PAD(ndig
- 1, zeroes
);
1154 } else if (expt
<= 0) {
1158 } else if (expt
>= ndig
) {
1160 PAD(expt
- ndig
, zeroes
);
1167 PRINT(cp
, ndig
-expt
);
1169 } else { /* 'e' or 'E' */
1170 if (ndig
> 1 || flags
& ALT
) {
1176 } else /* 0.[0..] */
1177 /* __dtoa irregularity */
1178 PAD(ndig
- 1, zeroes
);
1181 PRINT(expstr
, expsize
);
1188 /* left-adjusting padding (always blank) */
1189 if (flags
& LADJUST
)
1190 PAD(width
- realsz
, blanks
);
1192 /* finally, adjust ret */
1195 FLUSH(); /* copy out the I/O vectors */
1200 #ifdef FLOATING_POINT
1201 if (dtoaresult
!= NULL
)
1206 /* FUNLOCKFILE(fp); */
1207 if ((argtable
!= NULL
) && (argtable
!= statargtable
))
1214 * Type ids for argument type table.
1230 #define T_LONG_DOUBLE 14
1236 * Find all arguments when a positional parameter is encountered. Returns a
1237 * table, indexed by argument number, of pointers to each arguments. The
1238 * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
1239 * It will be replaces with a malloc-ed one if it overflows.
1242 __find_arguments (fmt0
, ap
, argtable
)
1245 union arg
**argtable
;
1247 register char *fmt
; /* format string */
1248 register int ch
; /* character from fmt */
1249 register int n
, n2
; /* handy integer (short term usage) */
1250 register char *cp
; /* handy char pointer (short term usage) */
1251 register int flags
; /* flags as above */
1252 int width
; /* width from format (%8d), or 0 */
1253 unsigned char *typetable
; /* table of types */
1254 unsigned char stattypetable
[STATIC_ARG_TBL_SIZE
];
1255 int tablesize
; /* current size of type table */
1256 int tablemax
; /* largest used index in table */
1257 int nextarg
; /* 1-based argument index */
1260 * Add an argument type to the table, expanding if necessary.
1262 #define ADDTYPE(type) \
1263 ((nextarg >= tablesize) ? \
1264 __grow_type_table(nextarg, &typetable, &tablesize) : 0, \
1265 (nextarg > tablemax) ? tablemax = nextarg : 0, \
1266 typetable[nextarg++] = type)
1269 ((flags&LONGINT) ? ADDTYPE(T_LONG) : \
1270 ((flags&SHORTINT) ? ADDTYPE(T_SHORT) : ADDTYPE(T_INT)))
1273 ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : \
1274 ((flags&SHORTINT) ? ADDTYPE(T_U_SHORT) : ADDTYPE(T_U_INT)))
1277 * Add * arguments to the type array.
1279 #define ADDASTER() \
1282 while (is_digit(*cp)) { \
1283 n2 = 10 * n2 + to_digit(*cp); \
1287 int hold = nextarg; \
1296 typetable
= stattypetable
;
1297 tablesize
= STATIC_ARG_TBL_SIZE
;
1300 memset (typetable
, T_UNUSED
, STATIC_ARG_TBL_SIZE
);
1303 * Scan the format for conversions (`%' character).
1306 for (cp
= fmt
; (ch
= *fmt
) != '\0' && ch
!= '%'; fmt
++)
1310 fmt
++; /* skip over '%' */
1316 reswitch
: switch (ch
) {
1327 if ((ch
= *fmt
++) == '*') {
1331 while (is_digit(ch
)) {
1337 case '1': case '2': case '3': case '4':
1338 case '5': case '6': case '7': case '8': case '9':
1341 n
= 10 * n
+ to_digit(ch
);
1343 } while (is_digit(ch
));
1350 #ifdef FLOATING_POINT
1359 if (flags
& LONGINT
)
1385 if (flags
& QUADINT
) {
1391 #ifdef FLOATING_POINT
1402 if (flags
& LONGDBL
)
1403 ADDTYPE(T_LONG_DOUBLE
);
1407 #endif /* FLOATING_POINT */
1409 if (flags
& QUADINT
)
1411 else if (flags
& LONGINT
)
1413 else if (flags
& SHORTINT
)
1417 continue; /* no output */
1427 if (flags
& QUADINT
)
1452 if (flags
& QUADINT
)
1464 if (flags
& QUADINT
)
1469 default: /* "%?" prints ?, unless ? is NUL */
1477 * Build the argument table.
1479 if (tablemax
>= STATIC_ARG_TBL_SIZE
) {
1480 *argtable
= (union arg
*)
1481 malloc (sizeof (union arg
) * (tablemax
+ 1));
1484 (*argtable
) [0].intarg
= NULL
;
1485 for (n
= 1; n
<= tablemax
; n
++) {
1486 switch (typetable
[n
]) {
1488 (*argtable
) [n
].intarg
= va_arg (ap
, int);
1491 (*argtable
) [n
].intarg
= va_arg (ap
, int);
1494 (*argtable
) [n
].intarg
= va_arg (ap
, int);
1497 (*argtable
) [n
].pshortarg
= va_arg (ap
, short *);
1500 (*argtable
) [n
].intarg
= va_arg (ap
, int);
1503 (*argtable
) [n
].uintarg
= va_arg (ap
, unsigned int);
1506 (*argtable
) [n
].pintarg
= va_arg (ap
, int *);
1509 (*argtable
) [n
].longarg
= va_arg (ap
, long);
1512 (*argtable
) [n
].ulongarg
= va_arg (ap
, unsigned long);
1515 (*argtable
) [n
].plongarg
= va_arg (ap
, long *);
1518 (*argtable
) [n
].quadarg
= va_arg (ap
, quad_t
);
1521 (*argtable
) [n
].uquadarg
= va_arg (ap
, u_quad_t
);
1524 (*argtable
) [n
].pquadarg
= va_arg (ap
, quad_t
*);
1526 #ifdef FLOATING_POINT
1528 (*argtable
) [n
].doublearg
= va_arg (ap
, double);
1531 (*argtable
) [n
].longdoublearg
= va_arg (ap
, long double);
1537 getvec( &((*argtable
) [n
]), NULL
, tmp
, ap
);
1541 (*argtable
) [n
].pchararg
= va_arg (ap
, char *);
1544 (*argtable
) [n
].pvoidarg
= va_arg (ap
, void *);
1549 if ((typetable
!= NULL
) && (typetable
!= stattypetable
))
1554 * Increase the size of the type table.
1557 __grow_type_table (nextarg
, typetable
, tablesize
)
1559 unsigned char **typetable
;
1562 unsigned char *const oldtable
= *typetable
;
1563 const int oldsize
= *tablesize
;
1564 unsigned char *newtable
;
1565 int newsize
= oldsize
* 2;
1567 if (newsize
< nextarg
+ 1)
1568 newsize
= nextarg
+ 1;
1569 if (oldsize
== STATIC_ARG_TBL_SIZE
) {
1570 if ((newtable
= malloc (newsize
)) == NULL
)
1571 abort(); /* XXX handle better */
1572 bcopy (oldtable
, newtable
, oldsize
);
1574 if ((newtable
= realloc (oldtable
, newsize
)) == NULL
)
1575 abort(); /* XXX handle better */
1577 memset (&newtable
[oldsize
], T_UNUSED
, (newsize
- oldsize
));
1579 *typetable
= newtable
;
1580 *tablesize
= newsize
;
1584 #ifdef FLOATING_POINT
1586 extern char *__dtoa
__P((double, int, int, int *, int *, char **, char **));
1589 cvt(value
, ndigits
, flags
, sign
, decpt
, ch
, length
, dtoaresultp
)
1591 int ndigits
, flags
, *decpt
, ch
, *length
;
1596 char *digits
, *bp
, *rve
;
1599 mode
= 3; /* ndigits after the decimal point */
1602 * To obtain ndigits after the decimal point for the 'e'
1603 * and 'E' formats, round to ndigits + 1 significant
1606 if (ch
== 'e' || ch
== 'E')
1608 mode
= 2; /* ndigits significant digits */
1615 digits
= __dtoa(value
, mode
, ndigits
, decpt
, &dsgn
, &rve
, dtoaresultp
);
1616 if ((ch
!= 'g' && ch
!= 'G') || flags
& ALT
) {
1617 /* print trailing zeros */
1618 bp
= digits
+ ndigits
;
1620 if (*digits
== '0' && value
)
1621 *decpt
= -ndigits
+ 1;
1624 if (value
== 0) /* kludge for __dtoa irregularity */
1629 *length
= rve
- digits
;
1634 exponent(p0
, exp
, fmtch
)
1638 register char *p
, *t
;
1639 char expbuf
[MAXEXP
];
1649 t
= expbuf
+ MAXEXP
;
1652 *--t
= to_char(exp
% 10);
1653 } while ((exp
/= 10) > 9);
1654 *--t
= to_char(exp
);
1655 for (; t
< expbuf
+ MAXEXP
; *p
++ = *t
++);
1659 *p
++ = to_char(exp
);
1663 #endif /* FLOATING_POINT */