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