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