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