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