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