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