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