grrr...fix reverse chronological order
[dragonfly.git] / lib / libcr / stdio / vfprintf.c
1 /*-
2  * Copyright (c) 1990, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Chris Torek.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
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.
23  *
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
34  * SUCH DAMAGE.
35  *
36  * @(#)vfprintf.c       8.1 (Berkeley) 6/4/93
37  * $FreeBSD: src/lib/libc/stdio/vfprintf.c,v 1.22.2.5 2002/10/12 10:46:37 schweikh Exp $
38  * $DragonFly: src/lib/libcr/stdio/Attic/vfprintf.c,v 1.4 2004/07/05 17:31:00 eirikn Exp $
39  */
40
41 /*
42  * Actual printf innards.
43  *
44  * This code is large and complicated...
45  */
46
47 #include <sys/types.h>
48
49 #include <limits.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53
54 #include <stdarg.h>
55
56 #include "libc_private.h"
57 #include "local.h"
58 #include "fvwrite.h"
59
60 /* Define FLOATING_POINT to get floating point. */
61 #define FLOATING_POINT
62
63 static int      __sprint (FILE *, struct __suio *);
64 static int      __sbprintf (FILE *, const char *, va_list);
65 static char *   __ultoa (u_long, char *, int, int, char *);
66 static char *   __uqtoa (u_quad_t, char *, int, int, char *);
67 static void     __find_arguments (const char *, va_list, void ***);
68 static void     __grow_type_table (int, unsigned char **, int *);
69
70 /*
71  * Flush out all the vectors defined by the given uio,
72  * then reset it so that it can be reused.
73  */
74 static int
75 __sprint(FILE *fp, struct __suio *uio)
76 {
77         int err;
78
79         if (uio->uio_resid == 0) {
80                 uio->uio_iovcnt = 0;
81                 return (0);
82         }
83         err = __sfvwrite(fp, uio);
84         uio->uio_resid = 0;
85         uio->uio_iovcnt = 0;
86         return (err);
87 }
88
89 /*
90  * Helper function for `fprintf to unbuffered unix file': creates a
91  * temporary buffer.  We only work on write-only files; this avoids
92  * worries about ungetc buffers and so forth.
93  */
94 static int
95 __sbprintf(FILE *fp, const char *fmt, va_list ap)
96 {
97         int ret;
98         FILE fake;
99         unsigned char buf[BUFSIZ];
100
101         /* copy the important variables */
102         fake._flags = fp->_flags & ~__SNBF;
103         fake._file = fp->_file;
104         fake._cookie = fp->_cookie;
105         fake._write = fp->_write;
106
107         /* set up the buffer */
108         fake._bf._base = fake._p = buf;
109         fake._bf._size = fake._w = sizeof(buf);
110         fake._lbfsize = 0;      /* not actually used, but Just In Case */
111
112         /* do the work, then copy any error status */
113         ret = vfprintf(&fake, fmt, ap);
114         if (ret >= 0 && fflush(&fake))
115                 ret = EOF;
116         if (fake._flags & __SERR)
117                 fp->_flags |= __SERR;
118         return (ret);
119 }
120
121 /*
122  * Macros for converting digits to letters and vice versa
123  */
124 #define to_digit(c)     ((c) - '0')
125 #define is_digit(c)     ((unsigned)to_digit(c) <= 9)
126 #define to_char(n)      ((n) + '0')
127
128 /*
129  * Convert an unsigned long to ASCII for printf purposes, returning
130  * a pointer to the first character of the string representation.
131  * Octal numbers can be forced to have a leading zero; hex numbers
132  * use the given digits.
133  */
134 static char *
135 __ultoa(u_long val, char *endp, int base, int octzero, char *xdigs)
136 {
137         char *cp = endp;
138         long sval;
139
140         /*
141          * Handle the three cases separately, in the hope of getting
142          * better/faster code.
143          */
144         switch (base) {
145         case 10:
146                 if (val < 10) { /* many numbers are 1 digit */
147                         *--cp = to_char(val);
148                         return (cp);
149                 }
150                 /*
151                  * On many machines, unsigned arithmetic is harder than
152                  * signed arithmetic, so we do at most one unsigned mod and
153                  * divide; this is sufficient to reduce the range of
154                  * the incoming value to where signed arithmetic works.
155                  */
156                 if (val > LONG_MAX) {
157                         *--cp = to_char(val % 10);
158                         sval = val / 10;
159                 } else
160                         sval = val;
161                 do {
162                         *--cp = to_char(sval % 10);
163                         sval /= 10;
164                 } while (sval != 0);
165                 break;
166
167         case 8:
168                 do {
169                         *--cp = to_char(val & 7);
170                         val >>= 3;
171                 } while (val);
172                 if (octzero && *cp != '0')
173                         *--cp = '0';
174                 break;
175
176         case 16:
177                 do {
178                         *--cp = xdigs[val & 15];
179                         val >>= 4;
180                 } while (val);
181                 break;
182
183         default:                        /* oops */
184                 abort();
185         }
186         return (cp);
187 }
188
189 /* Identical to __ultoa, but for quads. */
190 static char *
191 __uqtoa(u_quad_t val, char *endp, int base, int octzero, char *xdigs)
192 {
193         char *cp = endp;
194         quad_t sval;
195
196         /* quick test for small values; __ultoa is typically much faster */
197         /* (perhaps instead we should run until small, then call __ultoa?) */
198         if (val <= ULONG_MAX)
199                 return (__ultoa((u_long)val, endp, base, octzero, xdigs));
200         switch (base) {
201         case 10:
202                 if (val < 10) {
203                         *--cp = to_char(val % 10);
204                         return (cp);
205                 }
206                 if (val > QUAD_MAX) {
207                         *--cp = to_char(val % 10);
208                         sval = val / 10;
209                 } else
210                         sval = val;
211                 do {
212                         *--cp = to_char(sval % 10);
213                         sval /= 10;
214                 } while (sval != 0);
215                 break;
216
217         case 8:
218                 do {
219                         *--cp = to_char(val & 7);
220                         val >>= 3;
221                 } while (val);
222                 if (octzero && *cp != '0')
223                         *--cp = '0';
224                 break;
225
226         case 16:
227                 do {
228                         *--cp = xdigs[val & 15];
229                         val >>= 4;
230                 } while (val);
231                 break;
232
233         default:
234                 abort();
235         }
236         return (cp);
237 }
238
239 #ifdef FLOATING_POINT
240 #include <locale.h>
241 #include <math.h>
242 #include "floatio.h"
243
244 #define BUF             (MAXEXP+MAXFRACT+1)     /* + decimal point */
245 #define DEFPREC         6
246
247 static char *cvt (double, int, int, char *, int *, int, int *, char **);
248 static int exponent (char *, int, int);
249
250 #else /* no FLOATING_POINT */
251
252 #define BUF             68
253
254 #endif /* FLOATING_POINT */
255
256 #define STATIC_ARG_TBL_SIZE 8           /* Size of static argument table. */
257
258 /*
259  * Flags used during conversion.
260  */
261 #define ALT             0x001           /* alternate form */
262 #define HEXPREFIX       0x002           /* add 0x or 0X prefix */
263 #define LADJUST         0x004           /* left adjustment */
264 #define LONGDBL         0x008           /* long double */
265 #define LONGINT         0x010           /* long integer */
266 #define QUADINT         0x020           /* quad integer */
267 #define SHORTINT        0x040           /* short integer */
268 #define ZEROPAD         0x080           /* zero (as opposed to blank) pad */
269 #define FPT             0x100           /* Floating point number */
270 int
271 vfprintf(FILE *fp, const char *fmt0, va_list ap)
272 {
273         char *fmt;              /* format string */
274         int ch;                 /* character from fmt */
275         int n, n2;              /* handy integer (short term usage) */
276         char *cp;               /* handy char pointer (short term usage) */
277         struct __siov *iovp;    /* for PRINT macro */
278         int flags;              /* flags as above */
279         int ret;                /* return value accumulator */
280         int width;              /* width from format (%8d), or 0 */
281         int prec;               /* precision from format (%.3d), or -1 */
282         char sign;              /* sign prefix (' ', '+', '-', or \0) */
283 #ifdef FLOATING_POINT
284         char *decimal_point = localeconv()->decimal_point;
285         char softsign;          /* temporary negative sign for floats */
286         double _double;         /* double precision arguments %[eEfgG] */
287         int expt;               /* integer value of exponent */
288         int expsize;            /* character count for expstr */
289         int ndig;               /* actual number of digits returned by cvt */
290         char expstr[7];         /* buffer for exponent string */
291         char *dtoaresult;       /* buffer allocated by dtoa */
292 #endif
293         u_long  ulval;          /* integer arguments %[diouxX] */
294         u_quad_t uqval;         /* %q integers */
295         int base;               /* base for [diouxX] conversion */
296         int dprec;              /* a copy of prec if [diouxX], 0 otherwise */
297         int realsz;             /* field size expanded by dprec, sign, etc */
298         int size;               /* size of converted field or string */
299         int prsize;             /* max size of printed field */
300         char *xdigs;            /* digits for [xX] conversion */
301 #define NIOV 8
302         struct __suio uio;      /* output information: summary */
303         struct __siov iov[NIOV];/* ... and individual io vectors */
304         char buf[BUF];          /* space for %c, %[diouxX], %[eEfgG] */
305         char ox[2];             /* space for 0x hex-prefix */
306         void **argtable;        /* args, built due to positional arg */
307         void *statargtable [STATIC_ARG_TBL_SIZE];
308         int nextarg;            /* 1-based argument index */
309         va_list orgap;          /* original argument pointer */
310
311         /*
312          * Choose PADSIZE to trade efficiency vs. size.  If larger printf
313          * fields occur frequently, increase PADSIZE and make the initialisers
314          * below longer.
315          */
316 #define PADSIZE 16              /* pad chunk size */
317         static char blanks[PADSIZE] =
318          {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
319         static char zeroes[PADSIZE] =
320          {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
321
322         /*
323          * BEWARE, these `goto error' on error, and PAD uses `n'.
324          */
325 #define PRINT(ptr, len) { \
326         iovp->iov_base = (ptr); \
327         iovp->iov_len = (len); \
328         uio.uio_resid += (len); \
329         iovp++; \
330         if (++uio.uio_iovcnt >= NIOV) { \
331                 if (__sprint(fp, &uio)) \
332                         goto error; \
333                 iovp = iov; \
334         } \
335 }
336 #define PAD(howmany, with) { \
337         if ((n = (howmany)) > 0) { \
338                 while (n > PADSIZE) { \
339                         PRINT(with, PADSIZE); \
340                         n -= PADSIZE; \
341                 } \
342                 PRINT(with, n); \
343         } \
344 }
345 #define FLUSH() { \
346         if (uio.uio_resid && __sprint(fp, &uio)) \
347                 goto error; \
348         uio.uio_iovcnt = 0; \
349         iovp = iov; \
350 }
351
352         /*
353          * Get the argument indexed by nextarg.   If the argument table is
354          * built, use it to get the argument.  If its not, get the next
355          * argument (and arguments must be gotten sequentially).
356          */
357 #define GETARG(type) \
358         ((argtable != NULL) ? *((type*)(argtable[nextarg++])) : \
359             (nextarg++, va_arg(ap, type)))
360
361         /*
362          * To extend shorts properly, we need both signed and unsigned
363          * argument extraction methods.
364          */
365 #define SARG() \
366         (flags&LONGINT ? GETARG(long) : \
367             flags&SHORTINT ? (long)(short)GETARG(int) : \
368             (long)GETARG(int))
369 #define UARG() \
370         (flags&LONGINT ? GETARG(u_long) : \
371             flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
372             (u_long)GETARG(u_int))
373
374         /*
375          * Get * arguments, including the form *nn$.  Preserve the nextarg
376          * that the argument can be gotten once the type is determined.
377          */
378 #define GETASTER(val) \
379         n2 = 0; \
380         cp = fmt; \
381         while (is_digit(*cp)) { \
382                 n2 = 10 * n2 + to_digit(*cp); \
383                 cp++; \
384         } \
385         if (*cp == '$') { \
386                 int hold = nextarg; \
387                 if (argtable == NULL) { \
388                         argtable = statargtable; \
389                         __find_arguments (fmt0, orgap, &argtable); \
390                 } \
391                 nextarg = n2; \
392                 val = GETARG (int); \
393                 nextarg = hold; \
394                 fmt = ++cp; \
395         } else { \
396                 val = GETARG (int); \
397         }
398         
399
400 #ifdef FLOATING_POINT
401         dtoaresult = NULL;
402 #endif
403         FLOCKFILE(fp);
404         /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
405         if (cantwrite(fp)) {
406                 FUNLOCKFILE(fp);
407                 return (EOF);
408         }
409
410         /* optimise fprintf(stderr) (and other unbuffered Unix files) */
411         if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
412             fp->_file >= 0) {
413                 FUNLOCKFILE(fp);
414                 return (__sbprintf(fp, fmt0, ap));
415         }
416
417         fmt = (char *)fmt0;
418         argtable = NULL;
419         nextarg = 1;
420         orgap = ap;
421         uio.uio_iov = iovp = iov;
422         uio.uio_resid = 0;
423         uio.uio_iovcnt = 0;
424         ret = 0;
425
426         /*
427          * Scan the format for conversions (`%' character).
428          */
429         for (;;) {
430                 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
431                         /* void */;
432                 if ((n = fmt - cp) != 0) {
433                         if ((unsigned)ret + n > INT_MAX) {
434                                 ret = EOF;
435                                 goto error;
436                         }
437                         PRINT(cp, n);
438                         ret += n;
439                 }
440                 if (ch == '\0')
441                         goto done;
442                 fmt++;          /* skip over '%' */
443
444                 flags = 0;
445                 dprec = 0;
446                 width = 0;
447                 prec = -1;
448                 sign = '\0';
449
450 rflag:          ch = *fmt++;
451 reswitch:       switch (ch) {
452                 case ' ':
453                         /*
454                          * ``If the space and + flags both appear, the space
455                          * flag will be ignored.''
456                          *      -- ANSI X3J11
457                          */
458                         if (!sign)
459                                 sign = ' ';
460                         goto rflag;
461                 case '#':
462                         flags |= ALT;
463                         goto rflag;
464                 case '*':
465                         /*
466                          * ``A negative field width argument is taken as a
467                          * - flag followed by a positive field width.''
468                          *      -- ANSI X3J11
469                          * They don't exclude field widths read from args.
470                          */
471                         GETASTER (width);
472                         if (width >= 0)
473                                 goto rflag;
474                         width = -width;
475                         /* FALLTHROUGH */
476                 case '-':
477                         flags |= LADJUST;
478                         goto rflag;
479                 case '+':
480                         sign = '+';
481                         goto rflag;
482                 case '.':
483                         if ((ch = *fmt++) == '*') {
484                                 GETASTER (n);
485                                 prec = n < 0 ? -1 : n;
486                                 goto rflag;
487                         }
488                         n = 0;
489                         while (is_digit(ch)) {
490                                 n = 10 * n + to_digit(ch);
491                                 ch = *fmt++;
492                         }
493                         prec = n < 0 ? -1 : n;
494                         goto reswitch;
495                 case '0':
496                         /*
497                          * ``Note that 0 is taken as a flag, not as the
498                          * beginning of a field width.''
499                          *      -- ANSI X3J11
500                          */
501                         flags |= ZEROPAD;
502                         goto rflag;
503                 case '1': case '2': case '3': case '4':
504                 case '5': case '6': case '7': case '8': case '9':
505                         n = 0;
506                         do {
507                                 n = 10 * n + to_digit(ch);
508                                 ch = *fmt++;
509                         } while (is_digit(ch));
510                         if (ch == '$') {
511                                 nextarg = n;
512                                 if (argtable == NULL) {
513                                         argtable = statargtable;
514                                         __find_arguments (fmt0, orgap,
515                                                 &argtable);
516                                 }
517                                 goto rflag;
518                         }
519                         width = n;
520                         goto reswitch;
521 #ifdef FLOATING_POINT
522                 case 'L':
523                         flags |= LONGDBL;
524                         goto rflag;
525 #endif
526                 case 'h':
527                         flags |= SHORTINT;
528                         goto rflag;
529                 case 'l':
530                         if (flags & LONGINT)
531                                 flags |= QUADINT;
532                         else
533                                 flags |= LONGINT;
534                         goto rflag;
535                 case 'q':
536                         flags |= QUADINT;
537                         goto rflag;
538                 case 'c':
539                         *(cp = buf) = GETARG(int);
540                         size = 1;
541                         sign = '\0';
542                         break;
543                 case 'D':
544                         flags |= LONGINT;
545                         /*FALLTHROUGH*/
546                 case 'd':
547                 case 'i':
548                         if (flags & QUADINT) {
549                                 uqval = GETARG(quad_t);
550                                 if ((quad_t)uqval < 0) {
551                                         uqval = -uqval;
552                                         sign = '-';
553                                 }
554                         } else {
555                                 ulval = SARG();
556                                 if ((long)ulval < 0) {
557                                         ulval = -ulval;
558                                         sign = '-';
559                                 }
560                         }
561                         base = 10;
562                         goto number;
563 #ifdef FLOATING_POINT
564                 case 'e':
565                 case 'E':
566                 case 'f':
567                         goto fp_begin;
568                 case 'g':
569                 case 'G':
570                         if (prec == 0)
571                                 prec = 1;
572 fp_begin:               if (prec == -1)
573                                 prec = DEFPREC;
574                         if (flags & LONGDBL)
575                                 /* XXX this loses precision. */
576                                 _double = (double)GETARG(long double);
577                         else
578                                 _double = GETARG(double);
579                         /* do this before tricky precision changes */
580                         if (isinf(_double)) {
581                                 if (_double < 0)
582                                         sign = '-';
583                                 cp = "Inf";
584                                 size = 3;
585                                 break;
586                         }
587                         if (isnan(_double)) {
588                                 cp = "NaN";
589                                 size = 3;
590                                 break;
591                         }
592                         flags |= FPT;
593                         if (dtoaresult != NULL) {
594                                 free(dtoaresult);
595                                 dtoaresult = NULL;
596                         }
597                         cp = cvt(_double, prec, flags, &softsign,
598                                 &expt, ch, &ndig, &dtoaresult);
599                         if (ch == 'g' || ch == 'G') {
600                                 if (expt <= -4 || expt > prec)
601                                         ch = (ch == 'g') ? 'e' : 'E';
602                                 else
603                                         ch = 'g';
604                         }
605                         if (ch <= 'e') {        /* 'e' or 'E' fmt */
606                                 --expt;
607                                 expsize = exponent(expstr, expt, ch);
608                                 size = expsize + ndig;
609                                 if (ndig > 1 || flags & ALT)
610                                         ++size;
611                         } else if (ch == 'f') {         /* f fmt */
612                                 if (expt > 0) {
613                                         size = expt;
614                                         if (prec || flags & ALT)
615                                                 size += prec + 1;
616                                 } else  /* "0.X" */
617                                         size = prec + 2;
618                         } else if (expt >= ndig) {      /* fixed g fmt */
619                                 size = expt;
620                                 if (flags & ALT)
621                                         ++size;
622                         } else
623                                 size = ndig + (expt > 0 ?
624                                         1 : 2 - expt);
625
626                         if (softsign)
627                                 sign = '-';
628                         break;
629 #endif /* FLOATING_POINT */
630                 case 'n':
631                         if (flags & QUADINT)
632                                 *GETARG(quad_t *) = ret;
633                         else if (flags & LONGINT)
634                                 *GETARG(long *) = ret;
635                         else if (flags & SHORTINT)
636                                 *GETARG(short *) = ret;
637                         else
638                                 *GETARG(int *) = ret;
639                         continue;       /* no output */
640                 case 'O':
641                         flags |= LONGINT;
642                         /*FALLTHROUGH*/
643                 case 'o':
644                         if (flags & QUADINT)
645                                 uqval = GETARG(u_quad_t);
646                         else
647                                 ulval = UARG();
648                         base = 8;
649                         goto nosign;
650                 case 'p':
651                         /*
652                          * ``The argument shall be a pointer to void.  The
653                          * value of the pointer is converted to a sequence
654                          * of printable characters, in an implementation-
655                          * defined manner.''
656                          *      -- ANSI X3J11
657                          */
658                         ulval = (u_long)GETARG(void *);
659                         base = 16;
660                         xdigs = "0123456789abcdef";
661                         flags = (flags & ~QUADINT) | HEXPREFIX;
662                         ch = 'x';
663                         goto nosign;
664                 case 's':
665                         if ((cp = GETARG(char *)) == NULL)
666                                 cp = "(null)";
667                         if (prec >= 0) {
668                                 /*
669                                  * can't use strlen; can only look for the
670                                  * NUL in the first `prec' characters, and
671                                  * strlen() will go further.
672                                  */
673                                 char *p = memchr(cp, 0, (size_t)prec);
674
675                                 if (p != NULL) {
676                                         size = p - cp;
677                                         if (size > prec)
678                                                 size = prec;
679                                 } else
680                                         size = prec;
681                         } else
682                                 size = strlen(cp);
683                         sign = '\0';
684                         break;
685                 case 'U':
686                         flags |= LONGINT;
687                         /*FALLTHROUGH*/
688                 case 'u':
689                         if (flags & QUADINT)
690                                 uqval = GETARG(u_quad_t);
691                         else
692                                 ulval = UARG();
693                         base = 10;
694                         goto nosign;
695                 case 'X':
696                         xdigs = "0123456789ABCDEF";
697                         goto hex;
698                 case 'x':
699                         xdigs = "0123456789abcdef";
700 hex:                    if (flags & QUADINT)
701                                 uqval = GETARG(u_quad_t);
702                         else
703                                 ulval = UARG();
704                         base = 16;
705                         /* leading 0x/X only if non-zero */
706                         if (flags & ALT &&
707                             (flags & QUADINT ? uqval != 0 : ulval != 0))
708                                 flags |= HEXPREFIX;
709
710                         /* unsigned conversions */
711 nosign:                 sign = '\0';
712                         /*
713                          * ``... diouXx conversions ... if a precision is
714                          * specified, the 0 flag will be ignored.''
715                          *      -- ANSI X3J11
716                          */
717 number:                 if ((dprec = prec) >= 0)
718                                 flags &= ~ZEROPAD;
719
720                         /*
721                          * ``The result of converting a zero value with an
722                          * explicit precision of zero is no characters.''
723                          *      -- ANSI X3J11
724                          */
725                         cp = buf + BUF;
726                         if (flags & QUADINT) {
727                                 if (uqval != 0 || prec != 0)
728                                         cp = __uqtoa(uqval, cp, base,
729                                             flags & ALT, xdigs);
730                         } else {
731                                 if (ulval != 0 || prec != 0)
732                                         cp = __ultoa(ulval, cp, base,
733                                             flags & ALT, xdigs);
734                         }
735                         size = buf + BUF - cp;
736                         break;
737                 default:        /* "%?" prints ?, unless ? is NUL */
738                         if (ch == '\0')
739                                 goto done;
740                         /* pretend it was %c with argument ch */
741                         cp = buf;
742                         *cp = ch;
743                         size = 1;
744                         sign = '\0';
745                         break;
746                 }
747
748                 /*
749                  * All reasonable formats wind up here.  At this point, `cp'
750                  * points to a string which (if not flags&LADJUST) should be
751                  * padded out to `width' places.  If flags&ZEROPAD, it should
752                  * first be prefixed by any sign or other prefix; otherwise,
753                  * it should be blank padded before the prefix is emitted.
754                  * After any left-hand padding and prefixing, emit zeroes
755                  * required by a decimal [diouxX] precision, then print the
756                  * string proper, then emit zeroes required by any leftover
757                  * floating precision; finally, if LADJUST, pad with blanks.
758                  *
759                  * Compute actual size, so we know how much to pad.
760                  * size excludes decimal prec; realsz includes it.
761                  */
762                 realsz = dprec > size ? dprec : size;
763                 if (sign)
764                         realsz++;
765                 else if (flags & HEXPREFIX)
766                         realsz += 2;
767
768                 prsize = width > realsz ? width : realsz;
769                 if ((unsigned)ret + prsize > INT_MAX) {
770                         ret = EOF;
771                         goto error;
772                 }
773
774                 /* right-adjusting blank padding */
775                 if ((flags & (LADJUST|ZEROPAD)) == 0)
776                         PAD(width - realsz, blanks);
777
778                 /* prefix */
779                 if (sign) {
780                         PRINT(&sign, 1);
781                 } else if (flags & HEXPREFIX) {
782                         ox[0] = '0';
783                         ox[1] = ch;
784                         PRINT(ox, 2);
785                 }
786
787                 /* right-adjusting zero padding */
788                 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
789                         PAD(width - realsz, zeroes);
790
791                 /* leading zeroes from decimal precision */
792                 PAD(dprec - size, zeroes);
793
794                 /* the string or number proper */
795 #ifdef FLOATING_POINT
796                 if ((flags & FPT) == 0) {
797                         PRINT(cp, size);
798                 } else {        /* glue together f_p fragments */
799                         if (ch >= 'f') {        /* 'f' or 'g' */
800                                 if (_double == 0) {
801                                         /* kludge for __dtoa irregularity */
802                                         PRINT("0", 1);
803                                         if (expt < ndig || (flags & ALT) != 0) {
804                                                 PRINT(decimal_point, 1);
805                                                 PAD(ndig - 1, zeroes);
806                                         }
807                                 } else if (expt <= 0) {
808                                         PRINT("0", 1);
809                                         PRINT(decimal_point, 1);
810                                         PAD(-expt, zeroes);
811                                         PRINT(cp, ndig);
812                                 } else if (expt >= ndig) {
813                                         PRINT(cp, ndig);
814                                         PAD(expt - ndig, zeroes);
815                                         if (flags & ALT)
816                                                 PRINT(decimal_point, 1);
817                                 } else {
818                                         PRINT(cp, expt);
819                                         cp += expt;
820                                         PRINT(decimal_point, 1);
821                                         PRINT(cp, ndig-expt);
822                                 }
823                         } else {        /* 'e' or 'E' */
824                                 if (ndig > 1 || flags & ALT) {
825                                         ox[0] = *cp++;
826                                         ox[1] = *decimal_point;
827                                         PRINT(ox, 2);
828                                         if (_double) {
829                                                 PRINT(cp, ndig-1);
830                                         } else  /* 0.[0..] */
831                                                 /* __dtoa irregularity */
832                                                 PAD(ndig - 1, zeroes);
833                                 } else  /* XeYYY */
834                                         PRINT(cp, 1);
835                                 PRINT(expstr, expsize);
836                         }
837                 }
838 #else
839                 PRINT(cp, size);
840 #endif
841                 /* left-adjusting padding (always blank) */
842                 if (flags & LADJUST)
843                         PAD(width - realsz, blanks);
844
845                 /* finally, adjust ret */
846                 ret += prsize;
847
848                 FLUSH();        /* copy out the I/O vectors */
849         }
850 done:
851         FLUSH();
852 error:
853 #ifdef FLOATING_POINT
854         if (dtoaresult != NULL)
855                 free(dtoaresult);
856 #endif
857         if (__sferror(fp))
858                 ret = EOF;
859         FUNLOCKFILE(fp);
860         if ((argtable != NULL) && (argtable != statargtable))
861                 free (argtable);
862         return (ret);
863         /* NOTREACHED */
864 }
865
866 /*
867  * Type ids for argument type table.
868  */
869 #define T_UNUSED        0
870 #define T_SHORT         1
871 #define T_U_SHORT       2
872 #define TP_SHORT        3
873 #define T_INT           4
874 #define T_U_INT         5
875 #define TP_INT          6
876 #define T_LONG          7
877 #define T_U_LONG        8
878 #define TP_LONG         9
879 #define T_QUAD          10
880 #define T_U_QUAD        11
881 #define TP_QUAD         12
882 #define T_DOUBLE        13
883 #define T_LONG_DOUBLE   14
884 #define TP_CHAR         15
885 #define TP_VOID         16
886
887 /*
888  * Find all arguments when a positional parameter is encountered.  Returns a
889  * table, indexed by argument number, of pointers to each arguments.  The
890  * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
891  * It will be replaces with a malloc-ed one if it overflows.
892  */ 
893 static void
894 __find_arguments (const char *fmt0, va_list ap, void ***argtable)
895 {
896         char *fmt;              /* format string */
897         int ch;                 /* character from fmt */
898         int n, n2;              /* handy integer (short term usage) */
899         char *cp;               /* handy char pointer (short term usage) */
900         int flags;              /* flags as above */
901         int width;              /* width from format (%8d), or 0 */
902         unsigned char *typetable; /* table of types */
903         unsigned char stattypetable [STATIC_ARG_TBL_SIZE];
904         int tablesize;          /* current size of type table */
905         int tablemax;           /* largest used index in table */
906         int nextarg;            /* 1-based argument index */
907
908         /*
909          * Add an argument type to the table, expanding if necessary.
910          */
911 #define ADDTYPE(type) \
912         ((nextarg >= tablesize) ? \
913                 __grow_type_table(nextarg, &typetable, &tablesize) : 0, \
914         (nextarg > tablemax) ? tablemax = nextarg : 0, \
915         typetable[nextarg++] = type)
916
917 #define ADDSARG() \
918         ((flags&LONGINT) ? ADDTYPE(T_LONG) : \
919                 ((flags&SHORTINT) ? ADDTYPE(T_SHORT) : ADDTYPE(T_INT)))
920
921 #define ADDUARG() \
922         ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : \
923                 ((flags&SHORTINT) ? ADDTYPE(T_U_SHORT) : ADDTYPE(T_U_INT)))
924
925         /*
926          * Add * arguments to the type array.
927          */
928 #define ADDASTER() \
929         n2 = 0; \
930         cp = fmt; \
931         while (is_digit(*cp)) { \
932                 n2 = 10 * n2 + to_digit(*cp); \
933                 cp++; \
934         } \
935         if (*cp == '$') { \
936                 int hold = nextarg; \
937                 nextarg = n2; \
938                 ADDTYPE (T_INT); \
939                 nextarg = hold; \
940                 fmt = ++cp; \
941         } else { \
942                 ADDTYPE (T_INT); \
943         }
944         fmt = (char *)fmt0;
945         typetable = stattypetable;
946         tablesize = STATIC_ARG_TBL_SIZE;
947         tablemax = 0; 
948         nextarg = 1;
949         memset (typetable, T_UNUSED, STATIC_ARG_TBL_SIZE);
950
951         /*
952          * Scan the format for conversions (`%' character).
953          */
954         for (;;) {
955                 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
956                         /* void */;
957                 if (ch == '\0')
958                         goto done;
959                 fmt++;          /* skip over '%' */
960
961                 flags = 0;
962                 width = 0;
963
964 rflag:          ch = *fmt++;
965 reswitch:       switch (ch) {
966                 case ' ':
967                 case '#':
968                         goto rflag;
969                 case '*':
970                         ADDASTER ();
971                         goto rflag;
972                 case '-':
973                 case '+':
974                         goto rflag;
975                 case '.':
976                         if ((ch = *fmt++) == '*') {
977                                 ADDASTER ();
978                                 goto rflag;
979                         }
980                         while (is_digit(ch)) {
981                                 ch = *fmt++;
982                         }
983                         goto reswitch;
984                 case '0':
985                         goto rflag;
986                 case '1': case '2': case '3': case '4':
987                 case '5': case '6': case '7': case '8': case '9':
988                         n = 0;
989                         do {
990                                 n = 10 * n + to_digit(ch);
991                                 ch = *fmt++;
992                         } while (is_digit(ch));
993                         if (ch == '$') {
994                                 nextarg = n;
995                                 goto rflag;
996                         }
997                         width = n;
998                         goto reswitch;
999 #ifdef FLOATING_POINT
1000                 case 'L':
1001                         flags |= LONGDBL;
1002                         goto rflag;
1003 #endif
1004                 case 'h':
1005                         flags |= SHORTINT;
1006                         goto rflag;
1007                 case 'l':
1008                         if (flags & LONGINT)
1009                                 flags |= QUADINT;
1010                         else
1011                                 flags |= LONGINT;
1012                         goto rflag;
1013                 case 'q':
1014                         flags |= QUADINT;
1015                         goto rflag;
1016                 case 'c':
1017                         ADDTYPE(T_INT);
1018                         break;
1019                 case 'D':
1020                         flags |= LONGINT;
1021                         /*FALLTHROUGH*/
1022                 case 'd':
1023                 case 'i':
1024                         if (flags & QUADINT) {
1025                                 ADDTYPE(T_QUAD);
1026                         } else {
1027                                 ADDSARG();
1028                         }
1029                         break;
1030 #ifdef FLOATING_POINT
1031                 case 'e':
1032                 case 'E':
1033                 case 'f':
1034                 case 'g':
1035                 case 'G':
1036                         if (flags & LONGDBL)
1037                                 ADDTYPE(T_LONG_DOUBLE);
1038                         else
1039                                 ADDTYPE(T_DOUBLE);
1040                         break;
1041 #endif /* FLOATING_POINT */
1042                 case 'n':
1043                         if (flags & QUADINT)
1044                                 ADDTYPE(TP_QUAD);
1045                         else if (flags & LONGINT)
1046                                 ADDTYPE(TP_LONG);
1047                         else if (flags & SHORTINT)
1048                                 ADDTYPE(TP_SHORT);
1049                         else
1050                                 ADDTYPE(TP_INT);
1051                         continue;       /* no output */
1052                 case 'O':
1053                         flags |= LONGINT;
1054                         /*FALLTHROUGH*/
1055                 case 'o':
1056                         if (flags & QUADINT)
1057                                 ADDTYPE(T_U_QUAD);
1058                         else
1059                                 ADDUARG();
1060                         break;
1061                 case 'p':
1062                         ADDTYPE(TP_VOID);
1063                         break;
1064                 case 's':
1065                         ADDTYPE(TP_CHAR);
1066                         break;
1067                 case 'U':
1068                         flags |= LONGINT;
1069                         /*FALLTHROUGH*/
1070                 case 'u':
1071                         if (flags & QUADINT)
1072                                 ADDTYPE(T_U_QUAD);
1073                         else
1074                                 ADDUARG();
1075                         break;
1076                 case 'X':
1077                 case 'x':
1078                         if (flags & QUADINT)
1079                                 ADDTYPE(T_U_QUAD);
1080                         else
1081                                 ADDUARG();
1082                         break;
1083                 default:        /* "%?" prints ?, unless ? is NUL */
1084                         if (ch == '\0')
1085                                 goto done;
1086                         break;
1087                 }
1088         }
1089 done:
1090         /*
1091          * Build the argument table.
1092          */
1093         if (tablemax >= STATIC_ARG_TBL_SIZE) {
1094                 *argtable = (void **)
1095                     malloc (sizeof (void *) * (tablemax + 1));
1096         }
1097
1098         (*argtable) [0] = NULL;
1099         for (n = 1; n <= tablemax; n++) {
1100                 switch (typetable [n]) {
1101                     case T_UNUSED:
1102                         (*argtable) [n] = (void *) &va_arg (ap, int);
1103                         break;
1104                     case T_SHORT:
1105                         (*argtable) [n] = (void *) &va_arg (ap, int);
1106                         break;
1107                     case T_U_SHORT:
1108                         (*argtable) [n] = (void *) &va_arg (ap, int);
1109                         break;
1110                     case TP_SHORT:
1111                         (*argtable) [n] = (void *) &va_arg (ap, short *);
1112                         break;
1113                     case T_INT:
1114                         (*argtable) [n] = (void *) &va_arg (ap, int);
1115                         break;
1116                     case T_U_INT:
1117                         (*argtable) [n] = (void *) &va_arg (ap, unsigned int);
1118                         break;
1119                     case TP_INT:
1120                         (*argtable) [n] = (void *) &va_arg (ap, int *);
1121                         break;
1122                     case T_LONG:
1123                         (*argtable) [n] = (void *) &va_arg (ap, long);
1124                         break;
1125                     case T_U_LONG:
1126                         (*argtable) [n] = (void *) &va_arg (ap, unsigned long);
1127                         break;
1128                     case TP_LONG:
1129                         (*argtable) [n] = (void *) &va_arg (ap, long *);
1130                         break;
1131                     case T_QUAD:
1132                         (*argtable) [n] = (void *) &va_arg (ap, quad_t);
1133                         break;
1134                     case T_U_QUAD:
1135                         (*argtable) [n] = (void *) &va_arg (ap, u_quad_t);
1136                         break;
1137                     case TP_QUAD:
1138                         (*argtable) [n] = (void *) &va_arg (ap, quad_t *);
1139                         break;
1140                     case T_DOUBLE:
1141                         (*argtable) [n] = (void *) &va_arg (ap, double);
1142                         break;
1143                     case T_LONG_DOUBLE:
1144                         (*argtable) [n] = (void *) &va_arg (ap, long double);
1145                         break;
1146                     case TP_CHAR:
1147                         (*argtable) [n] = (void *) &va_arg (ap, char *);
1148                         break;
1149                     case TP_VOID:
1150                         (*argtable) [n] = (void *) &va_arg (ap, void *);
1151                         break;
1152                 }
1153         }
1154
1155         if ((typetable != NULL) && (typetable != stattypetable))
1156                 free (typetable);
1157 }
1158
1159 /*
1160  * Increase the size of the type table.
1161  */
1162 static void
1163 __grow_type_table (int nextarg, unsigned char **typetable, int *tablesize)
1164 {
1165         unsigned char *const oldtable = *typetable;
1166         const int oldsize = *tablesize;
1167         unsigned char *newtable;
1168         int newsize = oldsize * 2;
1169
1170         if (newsize < nextarg + 1)
1171                 newsize = nextarg + 1;
1172         if (oldsize == STATIC_ARG_TBL_SIZE) {
1173                 if ((newtable = malloc(newsize)) == NULL)
1174                         abort();                        /* XXX handle better */
1175                 bcopy(oldtable, newtable, oldsize);
1176         } else {
1177                 if ((newtable = reallocf(oldtable, newsize)) == NULL)
1178                         abort();                        /* XXX handle better */
1179         }
1180         memset(&newtable[oldsize], T_UNUSED, newsize - oldsize);
1181
1182         *typetable = newtable;
1183         *tablesize = newsize;
1184 }
1185
1186
1187 #ifdef FLOATING_POINT
1188
1189 extern char *__dtoa (double, int, int, int *, int *, char **, char **);
1190
1191 static char *
1192 cvt(double value, int ndigits, int flags, char *sign, int *decpt,
1193     int ch, int *length, char **dtoaresultp)
1194 {
1195         int mode, dsgn;
1196         char *digits, *bp, *rve;
1197
1198         if (ch == 'f')
1199                 mode = 3;               /* ndigits after the decimal point */
1200         else {
1201                 /*
1202                  * To obtain ndigits after the decimal point for the 'e'
1203                  * and 'E' formats, round to ndigits + 1 significant
1204                  * figures.
1205                  */
1206                 if (ch == 'e' || ch == 'E')
1207                         ndigits++;
1208                 mode = 2;               /* ndigits significant digits */
1209         }
1210         digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve, dtoaresultp);
1211         *sign = dsgn != 0;
1212         if ((ch != 'g' && ch != 'G') || flags & ALT) {
1213                 /* print trailing zeros */
1214                 bp = digits + ndigits;
1215                 if (ch == 'f') {
1216                         if (*digits == '0' && value)
1217                                 *decpt = -ndigits + 1;
1218                         bp += *decpt;
1219                 }
1220                 if (value == 0) /* kludge for __dtoa irregularity */
1221                         rve = bp;
1222                 while (rve < bp)
1223                         *rve++ = '0';
1224         }
1225         *length = rve - digits;
1226         return (digits);
1227 }
1228
1229 static int
1230 exponent(char *p0, int exp, int fmtch)
1231 {
1232         char *p, *t;
1233         char expbuf[MAXEXP];
1234
1235         p = p0;
1236         *p++ = fmtch;
1237         if (exp < 0) {
1238                 exp = -exp;
1239                 *p++ = '-';
1240         }
1241         else
1242                 *p++ = '+';
1243         t = expbuf + MAXEXP;
1244         if (exp > 9) {
1245                 do {
1246                         *--t = to_char(exp % 10);
1247                 } while ((exp /= 10) > 9);
1248                 *--t = to_char(exp);
1249                 for (; t < expbuf + MAXEXP; *p++ = *t++);
1250         }
1251         else {
1252                 *p++ = '0';
1253                 *p++ = to_char(exp);
1254         }
1255         return (p - p0);
1256 }
1257 #endif /* FLOATING_POINT */