Home | History | Annotate | Download | only in Stdio
      1 /** @file
      2     Implementation of internals for printf and wprintf.
      3 
      4     Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
      5     This program and the accompanying materials are licensed and made available
      6     under the terms and conditions of the BSD License that accompanies this
      7     distribution.  The full text of the license may be found at
      8     http://opensource.org/licenses/bsd-license.
      9 
     10     THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11     WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13     Copyright (c) 1990, 1993
     14     The Regents of the University of California.  All rights reserved.
     15 
     16     This code is derived from software contributed to Berkeley by
     17     Chris Torek.
     18 
     19     Redistribution and use in source and binary forms, with or without
     20     modification, are permitted provided that the following conditions
     21     are met:
     22       - Redistributions of source code must retain the above copyright
     23         notice, this list of conditions and the following disclaimer.
     24       - Redistributions in binary form must reproduce the above copyright
     25         notice, this list of conditions and the following disclaimer in the
     26         documentation and/or other materials provided with the distribution.
     27       - Neither the name of the University nor the names of its contributors
     28         may be used to endorse or promote products derived from this software
     29         without specific prior written permission.
     30 
     31     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     32     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     33     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     34     ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
     35     LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     36     CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     37     SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     38     INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     39     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     40     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     41     POSSIBILITY OF SUCH DAMAGE.
     42 
     43     NetBSD: vfwprintf.c,v 1.9.2.1.4.1 2008/04/08 21:10:55 jdc Exp
     44     vfprintf.c  8.1 (Berkeley) 6/4/93
     45 **/
     46 #include  <LibConfig.h>
     47 
     48 #include "namespace.h"
     49 #include <sys/types.h>
     50 
     51 #include <assert.h>
     52 #include <ctype.h>
     53 #include <limits.h>
     54 #include <locale.h>
     55 #include <stdarg.h>
     56 #include <stddef.h>
     57 #include <stdint.h>
     58 #include <stdio.h>
     59 #include <stdlib.h>
     60 #include <string.h>
     61 #include <errno.h>
     62 #include <wchar.h>
     63 #include <wctype.h>
     64 
     65 #include "reentrant.h"
     66 #include "local.h"
     67 #include "extern.h"
     68 #include "fvwrite.h"
     69 
     70 #ifdef  _MSC_VER
     71   // Keep compiler quiet about conversions from larger to smaller types.
     72   #pragma warning ( disable : 4244 )
     73 #endif
     74 
     75 #ifndef NARROW
     76 #define MCHAR_T   char
     77 #define CHAR_T    wchar_t
     78 #define STRLEN(a) wcslen(a)
     79 #define MEMCHR(a, b, c) wmemchr(a, b, c)
     80 #define SCONV(a, b) __mbsconv(a, b)
     81 #define STRCONST(a) L ## a
     82 #define WDECL(a, b) a ## w ## b
     83 #define END_OF_FILE WEOF
     84 #define MULTI   0
     85 #else
     86 #define MCHAR_T   wchar_t
     87 #define CHAR_T    char
     88 #define STRLEN(a) strlen(a)
     89 #define MEMCHR(a, b, c) memchr(a, b, c)
     90 #define SCONV(a, b) __wcsconv(a, b)
     91 #define STRCONST(a) a
     92 #define WDECL(a, b) a ## b
     93 #define END_OF_FILE EOF
     94 #define MULTI   1
     95 #endif
     96 
     97 union arg {
     98   int                 intarg;
     99   u_int               uintarg;
    100   long                longarg;
    101   unsigned long       ulongarg;
    102   long long           longlongarg;
    103   unsigned long long  ulonglongarg;
    104   ptrdiff_t           ptrdiffarg;
    105   size_t              sizearg;
    106   intmax_t            intmaxarg;
    107   uintmax_t           uintmaxarg;
    108   void               *pvoidarg;
    109   char               *pchararg;
    110   signed char        *pschararg;
    111   short              *pshortarg;
    112   int                *pintarg;
    113   long               *plongarg;
    114   long long          *plonglongarg;
    115   ptrdiff_t          *pptrdiffarg;
    116   size_t             *psizearg;
    117   intmax_t           *pintmaxarg;
    118 #ifndef NO_FLOATING_POINT
    119   double              doublearg;
    120   long double         longdoublearg;
    121 #endif
    122   wint_t              wintarg;
    123   wchar_t            *pwchararg;
    124 };
    125 
    126 /*
    127  * Type ids for argument type table.
    128  */
    129 enum typeid {
    130   T_UNUSED,   TP_SHORT,     T_INT,          T_U_INT,  TP_INT,
    131   T_LONG,     T_U_LONG,     TP_LONG,        T_LLONG,  T_U_LLONG,
    132   TP_LLONG,   T_PTRDIFFT,   TP_PTRDIFFT,    T_SIZET,  TP_SIZET,
    133   T_INTMAXT,  T_UINTMAXT,   TP_INTMAXT,     TP_VOID,  TP_CHAR,
    134   TP_SCHAR,   T_DOUBLE,     T_LONG_DOUBLE,  T_WINT,   TP_WCHAR
    135 };
    136 
    137 static int      __sbprintf(FILE *, const CHAR_T *, va_list);
    138 static CHAR_T  *__ujtoa(uintmax_t, CHAR_T *, int, int, const char *, int,
    139                         char, const char *);
    140 static CHAR_T  *__ultoa(u_long, CHAR_T *, int, int, const char *, int,
    141                         char, const char *);
    142 #ifndef NARROW
    143 static CHAR_T  *__mbsconv(char *, int);
    144 static wint_t   __xfputwc(CHAR_T, FILE *);
    145 #else
    146 static char    *__wcsconv(wchar_t *, int);
    147 static int      __sprint(FILE *, struct __suio *);
    148 #endif
    149 static int      __find_arguments(const CHAR_T *, va_list, union arg **);
    150 static int      __grow_type_table(int, enum typeid **, int *);
    151 
    152 /*
    153  * Helper function for `fprintf to unbuffered unix file': creates a
    154  * temporary buffer.  We only work on write-only files; this avoids
    155  * worries about ungetc buffers and so forth.
    156  */
    157 static int
    158 __sbprintf(FILE *fp, const CHAR_T *fmt, va_list ap)
    159 {
    160   int ret;
    161   FILE fake;
    162   struct __sfileext fakeext;
    163   unsigned char buf[BUFSIZ];
    164 
    165   _DIAGASSERT(fp != NULL);
    166   _DIAGASSERT(fmt != NULL);
    167   if(fp == NULL) {
    168     errno = EINVAL;
    169     return (EOF);
    170   }
    171 
    172   _FILEEXT_SETUP(&fake, &fakeext);
    173 
    174   /* copy the important variables */
    175   fake._flags   = fp->_flags & ~__SNBF;
    176   fake._file    = fp->_file;
    177   fake._cookie  = fp->_cookie;
    178   fake._write   = fp->_write;
    179 
    180   /* set up the buffer */
    181   fake._bf._base  = fake._p = buf;
    182   fake._bf._size  = fake._w = sizeof(buf);
    183   fake._lbfsize   = 0;  /* not actually used, but Just In Case */
    184 
    185   /* do the work, then copy any error status */
    186   ret = WDECL(__vf,printf_unlocked)(&fake, fmt, ap);
    187   if (ret >= 0 && fflush(&fake))
    188     ret = END_OF_FILE;
    189   if (fake._flags & __SERR)
    190     fp->_flags |= __SERR;
    191   return (ret);
    192 }
    193 
    194 #ifndef NARROW
    195 /*
    196  * Like __fputwc, but handles fake string (__SSTR) files properly.
    197  * File must already be locked.
    198  */
    199 static wint_t
    200 __xfputwc(wchar_t wc, FILE *fp)
    201 {
    202   static const mbstate_t initial = { 0 };
    203   mbstate_t mbs;
    204   char buf[MB_LEN_MAX];
    205   struct __suio uio;
    206   struct __siov iov;
    207   size_t len;
    208 
    209   if ((fp->_flags & __SSTR) == 0)
    210     return (__fputwc_unlock(wc, fp));
    211 
    212   mbs = initial;
    213   if ((len = wcrtomb(buf, wc, &mbs)) == (size_t)-1) {
    214     fp->_flags |= __SERR;
    215     return (END_OF_FILE);
    216   }
    217   uio.uio_iov     = &iov;
    218   uio.uio_resid   = (int)len;
    219   uio.uio_iovcnt  = 1;
    220   iov.iov_base    = buf;
    221   iov.iov_len     = len;
    222   return (__sfvwrite(fp, &uio) != EOF ? (wint_t)wc : END_OF_FILE);
    223 }
    224 #else
    225 /*
    226  * Flush out all the vectors defined by the given uio,
    227  * then reset it so that it can be reused.
    228  */
    229 static int
    230 __sprint(FILE *fp, struct __suio *uio)
    231 {
    232   int err;
    233 
    234   _DIAGASSERT(fp != NULL);
    235   _DIAGASSERT(uio != NULL);
    236   if(fp == NULL) {
    237     errno = EINVAL;
    238     return (EOF);
    239   }
    240 
    241   if (uio->uio_resid == 0) {
    242     uio->uio_iovcnt = 0;
    243     return (0);
    244   }
    245   err = __sfvwrite(fp, uio);
    246   uio->uio_resid = 0;
    247   uio->uio_iovcnt = 0;
    248   return (err);
    249 }
    250 #endif
    251 
    252 /*
    253  * Macros for converting digits to letters and vice versa
    254  */
    255 #define to_digit(c) ((c) - '0')
    256 #define is_digit(c) ((unsigned)to_digit(c) <= 9)
    257 #define to_char(n)  (CHAR_T)((n) + '0')
    258 
    259 /*
    260  * Convert an unsigned long to ASCII for printf purposes, returning
    261  * a pointer to the first character of the string representation.
    262  * Octal numbers can be forced to have a leading zero; hex numbers
    263  * use the given digits.
    264  */
    265 static CHAR_T *
    266 __ultoa(u_long val, CHAR_T *endp, int base, int octzero, const char *xdigs,
    267         int needgrp, char thousep, const char *grp)
    268 {
    269   CHAR_T *cp = endp;
    270   LONGN sval;
    271   int ndig;
    272 
    273   /*
    274    * Handle the three cases separately, in the hope of getting
    275    * better/faster code.
    276    */
    277   switch (base) {
    278   case 10:
    279     if (val < 10) { /* many numbers are 1 digit */
    280       *--cp = to_char(val);
    281       return (cp);
    282     }
    283     ndig = 0;
    284     /*
    285      * On many machines, unsigned arithmetic is harder than
    286      * signed arithmetic, so we do at most one unsigned mod and
    287      * divide; this is sufficient to reduce the range of
    288      * the incoming value to where signed arithmetic works.
    289      */
    290     if (val > LONG_MAX) {
    291       *--cp = to_char(val % 10);
    292       ndig++;
    293       sval = (LONGN)(val / 10);
    294     } else
    295       sval = (LONGN)val;
    296     do {
    297       *--cp = to_char(sval % 10);
    298       ndig++;
    299       /*
    300        * If (*grp == CHAR_MAX) then no more grouping
    301        * should be performed.
    302        */
    303       if (needgrp && ndig == *grp && *grp != CHAR_MAX
    304           && sval > 9) {
    305         *--cp = thousep;
    306         ndig = 0;
    307         /*
    308          * If (*(grp+1) == '\0') then we have to
    309          * use *grp character (last grouping rule)
    310          * for all next cases
    311          */
    312         if (*(grp+1) != '\0')
    313           grp++;
    314       }
    315       sval /= 10;
    316     } while (sval != 0);
    317     break;
    318 
    319   case 8:
    320     do {
    321       *--cp = to_char(val & 7);
    322       val >>= 3;
    323     } while (val);
    324     if (octzero && *cp != '0')
    325       *--cp = '0';
    326     break;
    327 
    328   case 16:
    329     do {
    330       *--cp = xdigs[(size_t)val & 15];
    331       val >>= 4;
    332     } while (val);
    333     break;
    334 
    335   default:      /* oops */
    336     abort();
    337   }
    338   return (cp);
    339 }
    340 
    341 /* Identical to __ultoa, but for intmax_t. */
    342 static CHAR_T *
    343 __ujtoa(uintmax_t val, CHAR_T *endp, int base, int octzero,
    344         const char *xdigs, int needgrp, char thousep, const char *grp)
    345 {
    346   CHAR_T *cp = endp;
    347   intmax_t sval;
    348   int ndig;
    349 
    350   /* quick test for small values; __ultoa is typically much faster */
    351   /* (perhaps instead we should run until small, then call __ultoa?) */
    352   if (val <= ULONG_MAX)
    353     return (__ultoa((u_long)val, endp, base, octzero, xdigs,
    354         needgrp, thousep, grp));
    355   switch (base) {
    356   case 10:
    357     if (val < 10) {
    358       *--cp = to_char(val % 10);
    359       return (cp);
    360     }
    361     ndig = 0;
    362     if (val > INTMAX_MAX) {
    363       *--cp = to_char(val % 10);
    364       ndig++;
    365       sval = val / 10;
    366     } else
    367       sval = val;
    368     do {
    369       *--cp = to_char(sval % 10);
    370       ndig++;
    371       /*
    372        * If (*grp == CHAR_MAX) then no more grouping
    373        * should be performed.
    374        */
    375       if (needgrp && *grp != CHAR_MAX && ndig == *grp
    376           && sval > 9) {
    377         *--cp = thousep;
    378         ndig = 0;
    379         /*
    380          * If (*(grp+1) == '\0') then we have to
    381          * use *grp character (last grouping rule)
    382          * for all next cases
    383          */
    384         if (*(grp+1) != '\0')
    385           grp++;
    386       }
    387       sval /= 10;
    388     } while (sval != 0);
    389     break;
    390 
    391   case 8:
    392     do {
    393       *--cp = to_char(val & 7);
    394       val >>= 3;
    395     } while (val);
    396     if (octzero && *cp != '0')
    397       *--cp = '0';
    398     break;
    399 
    400   case 16:
    401     do {
    402       *--cp = xdigs[(size_t)val & 15];
    403       val >>= 4;
    404     } while (val);
    405     break;
    406 
    407   default:
    408     abort();
    409   }
    410   return (cp);
    411 }
    412 
    413 #ifndef NARROW
    414 /*
    415  * Convert a multibyte character string argument for the %s format to a wide
    416  * string representation. ``prec'' specifies the maximum number of bytes
    417  * to output. If ``prec'' is greater than or equal to zero, we can't assume
    418  * that the multibyte char. string ends in a null character.
    419  */
    420 static wchar_t *
    421 __mbsconv(char *mbsarg, int prec)
    422 {
    423   static const mbstate_t initial = { 0 };
    424   mbstate_t mbs;
    425   wchar_t *convbuf, *wcp;
    426   const char *p;
    427   size_t insize, nchars, nconv;
    428 
    429   if (mbsarg == NULL)
    430     return (NULL);
    431 
    432   /*
    433    * Supplied argument is a multibyte string; convert it to wide
    434    * characters first.
    435    */
    436   if (prec >= 0) {
    437     /*
    438      * String is not guaranteed to be NUL-terminated. Find the
    439      * number of characters to print.
    440      */
    441     p = mbsarg;
    442     insize = nchars = nconv = 0;
    443     mbs = initial;
    444     while (nchars != (size_t)prec) {
    445       nconv = mbrlen(p, MB_CUR_MAX, &mbs);
    446       if (nconv == 0 || nconv == (size_t)-1 ||
    447           nconv == (size_t)-2)
    448         break;
    449       p += nconv;
    450       nchars++;
    451       insize += nconv;
    452     }
    453     if (nconv == (size_t)-1 || nconv == (size_t)-2)
    454       return (NULL);
    455   } else
    456     insize = strlen(mbsarg);
    457 
    458   /*
    459    * Allocate buffer for the result and perform the conversion,
    460    * converting at most `size' bytes of the input multibyte string to
    461    * wide characters for printing.
    462    */
    463   convbuf = malloc((insize + 1) * sizeof(*convbuf));
    464   if (convbuf == NULL)
    465     return (NULL);
    466   wcp = convbuf;
    467   p = mbsarg;
    468   mbs = initial;
    469   nconv = 0;
    470   while (insize != 0) {
    471     nconv = mbrtowc(wcp, p, insize, &mbs);
    472     if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2)
    473       break;
    474     wcp++;
    475     p += nconv;
    476     insize -= nconv;
    477   }
    478   if (nconv == (size_t)-1 || nconv == (size_t)-2) {
    479     free(convbuf);
    480     return (NULL);
    481   }
    482   *wcp = L'\0';
    483 
    484   return (convbuf);
    485 }
    486 #else
    487 /*
    488  * Convert a wide character string argument for the %ls format to a multibyte
    489  * string representation. If not -1, prec specifies the maximum number of
    490  * bytes to output, and also means that we can't assume that the wide char.
    491  * string ends is null-terminated.
    492  */
    493 static char *
    494 __wcsconv(wchar_t *wcsarg, int prec)
    495 {
    496   static const mbstate_t initial = { 0 };
    497   mbstate_t mbs;
    498   char buf[MB_LEN_MAX];
    499   wchar_t *p;
    500   char *convbuf;
    501   size_t clen, nbytes;
    502 
    503   /* Allocate space for the maximum number of bytes we could output. */
    504   if (prec < 0) {
    505     p = wcsarg;
    506     mbs = initial;
    507     nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs);
    508     if (nbytes == (size_t)-1)
    509       return (NULL);
    510   } else {
    511     /*
    512      * Optimisation: if the output precision is small enough,
    513      * just allocate enough memory for the maximum instead of
    514      * scanning the string.
    515      */
    516     if (prec < 128)
    517       nbytes = prec;
    518     else {
    519       nbytes = 0;
    520       p = wcsarg;
    521       mbs = initial;
    522       for (;;) {
    523         clen = wcrtomb(buf, *p++, &mbs);
    524         if (clen == 0 || clen == (size_t)-1 ||
    525             nbytes + clen > (size_t)prec)
    526           break;
    527         nbytes += clen;
    528       }
    529     }
    530   }
    531   if ((convbuf = malloc(nbytes + 1)) == NULL)
    532     return (NULL);
    533 
    534   /* Fill the output buffer. */
    535   p = wcsarg;
    536   mbs = initial;
    537   if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p,
    538       nbytes, &mbs)) == (size_t)-1) {
    539     free(convbuf);
    540     return (NULL);
    541   }
    542   convbuf[nbytes] = '\0';
    543   return (convbuf);
    544 }
    545 #endif
    546 
    547 /*
    548  * MT-safe version
    549  */
    550 int
    551 WDECL(vf,printf)(FILE * __restrict fp, const CHAR_T * __restrict fmt0, va_list ap)
    552 {
    553   int ret;
    554 
    555   if(fp == NULL) {
    556     errno = EINVAL;
    557     return (EOF);
    558   }
    559   FLOCKFILE(fp);
    560   ret = WDECL(__vf,printf_unlocked)(fp, fmt0, ap);
    561   FUNLOCKFILE(fp);
    562   return (ret);
    563 }
    564 
    565 #ifndef NO_FLOATING_POINT
    566 
    567 #include <float.h>
    568 #include <math.h>
    569 #include "floatio.h"
    570 
    571 #define DEFPREC   6
    572 
    573 static int exponent(CHAR_T *, int, int);
    574 #ifndef WIDE_DOUBLE
    575 static char *cvt(double, int, int, char *, int *, int, int *);
    576 #endif
    577 
    578 #endif /* !NO_FLOATING_POINT */
    579 
    580 /*
    581  * The size of the buffer we use as scratch space for integer
    582  * conversions, among other things.  Technically, we would need the
    583  * most space for base 10 conversions with thousands' grouping
    584  * characters between each pair of digits.  100 bytes is a
    585  * conservative overestimate even for a 128-bit uintmax_t.
    586  */
    587 #define BUF 100
    588 
    589 #define STATIC_ARG_TBL_SIZE 8           /* Size of static argument table. */
    590 
    591 /*
    592  * Flags used during conversion.
    593  */
    594 #define ALT       0x001   /* alternate form */
    595 #define LADJUST   0x004   /* left adjustment */
    596 #define LONGDBL   0x008   /* long double */
    597 #define LONGINT   0x010   /* long integer */
    598 #define LLONGINT  0x020   /* long long integer */
    599 #define SHORTINT  0x040   /* short integer */
    600 #define ZEROPAD   0x080   /* zero (as opposed to blank) pad */
    601 #define FPT       0x100   /* Floating point number */
    602 #define GROUPING  0x200   /* use grouping ("'" flag) */
    603           /* C99 additional size modifiers: */
    604 #define SIZET     0x400   /* size_t */
    605 #define PTRDIFFT  0x800   /* ptrdiff_t */
    606 #define INTMAXT   0x1000    /* intmax_t */
    607 #define CHARINT   0x2000    /* print char using int format */
    608 
    609 /*
    610  * Non-MT-safe version
    611  */
    612 int
    613 WDECL(__vf,printf_unlocked)(FILE *fp, const CHAR_T *fmt0, va_list ap)
    614 {
    615   CHAR_T *fmt;    /* format string */
    616   int ch;     /* character from fmt */
    617   int n, n2;    /* handy integer (short term usage) */
    618   CHAR_T *cp;   /* handy char pointer (short term usage) */
    619   int flags;    /* flags as above */
    620   int ret;    /* return value accumulator (number of items converted)*/
    621   int width;    /* width from format (%8d), or 0 */
    622   int prec;   /* precision from format; <0 for N/A */
    623   CHAR_T sign;    /* sign prefix (' ', '+', '-', or \0) */
    624   char thousands_sep; /* locale specific thousands separator */
    625   const char *grouping; /* locale specific numeric grouping rules */
    626 #ifndef NO_FLOATING_POINT
    627   /*
    628    * We can decompose the printed representation of floating
    629    * point numbers into several parts, some of which may be empty:
    630    *
    631    * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
    632    *    A       B     ---C---      D       E   F
    633    *
    634    * A: 'sign' holds this value if present; '\0' otherwise
    635    * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
    636    * C: cp points to the string MMMNNN.  Leading and trailing
    637    *  zeros are not in the string and must be added.
    638    * D: expchar holds this character; '\0' if no exponent, e.g. %f
    639    * F: at least two digits for decimal, at least one digit for hex
    640    */
    641   char *decimal_point;  /* locale specific decimal point */
    642 #ifdef WIDE_DOUBLE
    643   int signflag;   /* true if float is negative */
    644   union {     /* floating point arguments %[aAeEfFgG] */
    645     double dbl;
    646     long double ldbl;
    647   } fparg;
    648   char *dtoaend;    /* pointer to end of converted digits */
    649 #else
    650   double _double;   /* double precision arguments %[eEfgG] */
    651   char softsign;    /* temporary negative sign for floats */
    652 #endif
    653   char *dtoaresult; /* buffer allocated by dtoa */
    654   int expt = 0;   /* integer value of exponent */
    655   char expchar;   /* exponent character: [eEpP\0] */
    656   int expsize;    /* character count for expstr */
    657   int lead;   /* sig figs before decimal or group sep */
    658   int ndig;   /* actual number of digits returned by dtoa */
    659   CHAR_T expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */
    660   int nseps;    /* number of group separators with ' */
    661   int nrepeats;   /* number of repeats of the last group */
    662 #endif
    663   u_long  ulval;    /* integer arguments %[diouxX] */
    664   uintmax_t ujval;  /* %j, %ll, %q, %t, %z integers */
    665   int base;   /* base for [diouxX] conversion */
    666   int dprec;    /* a copy of prec if [diouxX], 0 otherwise */
    667   int realsz;   /* field size expanded by dprec, sign, etc */
    668   int size;   /* size of converted field or string */
    669   int prsize;             /* max size of printed field */
    670   const char *xdigs;  /* digits for %[xX] conversion */
    671 #ifdef NARROW
    672 #define NIOV 8
    673   struct __siov *iovp;  /* for PRINT macro */
    674   struct __suio uio;  /* output information: summary */
    675   struct __siov iov[NIOV];/* ... and individual io vectors */
    676 #else
    677   int n3;
    678 #endif
    679   CHAR_T buf[BUF];  /* buffer with space for digits of uintmax_t */
    680   CHAR_T ox[2];   /* space for 0x hex-prefix */
    681   union arg *argtable;  /* args, built due to positional arg */
    682   union arg statargtable [STATIC_ARG_TBL_SIZE];
    683   int nextarg;    /* 1-based argument index */
    684   va_list orgap;    /* original argument pointer */
    685   CHAR_T *convbuf;  /* multibyte to wide conversion result */
    686 
    687   /*
    688    * Choose PADSIZE to trade efficiency vs. size.  If larger printf
    689    * fields occur frequently, increase PADSIZE and make the initialisers
    690    * below longer.
    691    */
    692 #define PADSIZE 16    /* pad chunk size */
    693   static CHAR_T blanks[PADSIZE] =
    694    {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
    695   static CHAR_T zeroes[PADSIZE] =
    696    {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
    697 
    698   static const char xdigs_lower[17] = "0123456789abcdef";
    699   static const char xdigs_upper[17] = "0123456789ABCDEF";
    700 
    701   /*
    702    * BEWARE, these `goto error' on error, PRINT uses `n2' and
    703    * PAD uses `n'.
    704    */
    705 #ifndef NARROW
    706 #define PRINT(ptr, len) do {      \
    707   for (n3 = 0; n3 < (len); n3++)    \
    708     __xfputwc((ptr)[n3], fp); \
    709 } while (/*CONSTCOND*/0)
    710 #define FLUSH()
    711 #else
    712 #define PRINT(ptr, len) do { \
    713   iovp->iov_base = __UNCONST(ptr); \
    714   iovp->iov_len = (len); \
    715   uio.uio_resid += (len); \
    716   iovp++; \
    717   if (++uio.uio_iovcnt >= NIOV) { \
    718     if (__sprint(fp, &uio)) \
    719       goto error; \
    720     iovp = iov; \
    721   } \
    722 } while (/*CONSTCOND*/0)
    723 #define FLUSH() do { \
    724   if (uio.uio_resid && __sprint(fp, &uio)) \
    725     goto error; \
    726   uio.uio_iovcnt = 0; \
    727   iovp = iov; \
    728 } while (/*CONSTCOND*/0)
    729 #endif /* NARROW */
    730 
    731 #define PAD(howmany, with)  do {    \
    732   if ((n = (howmany)) > 0) {    \
    733     while (n > PADSIZE) {   \
    734       PRINT(with, PADSIZE); \
    735       n -= PADSIZE;   \
    736     }       \
    737     PRINT(with, n);     \
    738   }         \
    739 } while (/*CONSTCOND*/0)
    740 #define PRINTANDPAD(p, ep, len, with) do {  \
    741   n2 = (ep) - (p);            \
    742   if (n2 > (len))       \
    743     n2 = (len);     \
    744   if (n2 > 0)       \
    745     PRINT((p), n2);     \
    746   PAD((len) - (n2 > 0 ? n2 : 0), (with)); \
    747 } while(/*CONSTCOND*/0)
    748 
    749   /*
    750    * Get the argument indexed by nextarg.   If the argument table is
    751    * built, use it to get the argument.  If its not, get the next
    752    * argument (and arguments must be gotten sequentially).
    753    */
    754 #define GETARG(type) \
    755   ((/*CONSTCOND*/argtable != NULL) ? *((type*)(void*)(&argtable[nextarg++])) : \
    756       (nextarg++, va_arg(ap, type)))
    757 
    758   /*
    759    * To extend shorts properly, we need both signed and unsigned
    760    * argument extraction methods.
    761    */
    762 #define SARG() \
    763   ((long)(flags&LONGINT ? GETARG(long) : \
    764       flags&SHORTINT ? (short)GETARG(int) : \
    765       flags&CHARINT ? (signed char)GETARG(int) : \
    766       GETARG(int)))
    767 
    768 #define UARG() \
    769   ((u_long)(flags&LONGINT ? GETARG(u_long) : \
    770       flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
    771       flags&CHARINT ? (u_long)(u_char)GETARG(int) : \
    772       (u_long)GETARG(u_int)))
    773 
    774 #define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT)
    775 
    776 #define SJARG() \
    777   (flags&INTMAXT ? GETARG(intmax_t) : \
    778       flags&SIZET ? (intmax_t)GETARG(size_t) : \
    779       flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \
    780       (intmax_t)GETARG(long long))
    781 
    782 #define UJARG() \
    783   (flags&INTMAXT ? GETARG(uintmax_t) : \
    784       flags&SIZET ? (uintmax_t)GETARG(size_t) : \
    785       flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \
    786       (uintmax_t)GETARG(unsigned long long))
    787 
    788   /*
    789    * Get * arguments, including the form *nn$.  Preserve the nextarg
    790    * that the argument can be gotten once the type is determined.
    791    */
    792 #define GETASTER(val) \
    793   n2 = 0; \
    794   cp = fmt; \
    795   while (is_digit(*cp)) { \
    796     n2 = 10 * n2 + to_digit(*cp); \
    797     cp++; \
    798   } \
    799   if (*cp == '$') { \
    800     int hold = nextarg; \
    801     if (argtable == NULL) { \
    802       argtable = statargtable; \
    803       if (__find_arguments(fmt0, orgap, &argtable) == -1) \
    804         goto oomem; \
    805     } \
    806     nextarg = n2; \
    807     val = GETARG (int); \
    808     nextarg = hold; \
    809     fmt = ++cp; \
    810   } else { \
    811     val = GETARG (int); \
    812   }
    813 
    814   _DIAGASSERT(fp != NULL);
    815   _DIAGASSERT(fmt0 != NULL);
    816   if(fp == NULL) {
    817     errno = EINVAL;
    818     return (EOF);
    819   }
    820 
    821   _SET_ORIENTATION(fp, -1);
    822 
    823   ndig = -1;  /* XXX gcc */
    824 
    825   thousands_sep = '\0';
    826   grouping = NULL;
    827 #ifndef NO_FLOATING_POINT
    828   decimal_point = localeconv()->decimal_point;
    829   expsize = 0;    /* XXXGCC -Wuninitialized [sh3,m68000] */
    830 #endif
    831   convbuf = NULL;
    832   /* sorry, f{w,}printf(read_only_file, L"") returns {W,}EOF, not 0 */
    833   if (cantwrite(fp)) {
    834     errno = EBADF;
    835     return (END_OF_FILE);
    836   }
    837 
    838   /* optimise fprintf(stderr) (and other unbuffered Unix files) */
    839   if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
    840       fp->_file >= 0)
    841     return (__sbprintf(fp, fmt0, ap));
    842 
    843   fmt = (CHAR_T *)__UNCONST(fmt0);
    844   argtable = NULL;
    845   nextarg = 1;
    846   va_copy(orgap, ap);
    847 #ifdef NARROW
    848   uio.uio_iov = iovp = iov;
    849   uio.uio_resid = 0;
    850   uio.uio_iovcnt = 0;
    851 #endif
    852   ret = 0;
    853 
    854   /*
    855    * Scan the format for conversions (`%' character).
    856    */
    857   for (;;)
    858   {
    859     const CHAR_T *result;
    860 
    861     for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
    862       continue;
    863     if ((n = (int)(fmt - cp)) != 0) {
    864       if ((unsigned)ret + n > INT_MAX) {
    865         ret = END_OF_FILE;
    866         goto error;
    867       }
    868       PRINT(cp, n);
    869       ret += n;
    870     }
    871     if (ch == '\0')
    872       goto done;
    873     fmt++;    /* skip over '%' */
    874 
    875     flags = 0;
    876     dprec = 0;
    877     width = 0;
    878     prec = -1;
    879     sign = '\0';
    880     ox[1] = '\0';
    881     expchar = '\0';
    882     lead = 0;
    883     nseps = nrepeats = 0;
    884     ulval = 0;
    885     ujval = 0;
    886     xdigs = NULL;
    887 
    888 rflag:    ch = *fmt++;
    889 reswitch: switch (ch) {
    890     case ' ':
    891       /*-
    892        * ``If the space and + flags both appear, the space
    893        * flag will be ignored.''
    894        *  -- ANSI X3J11
    895        */
    896       if (!sign)
    897         sign = ' ';
    898       goto rflag;
    899     case '#':
    900       flags |= ALT;
    901       goto rflag;
    902     case '*':
    903       /*-
    904        * ``A negative field width argument is taken as a
    905        * - flag followed by a positive field width.''
    906        *  -- ANSI X3J11
    907        * They don't exclude field widths read from args.
    908        */
    909       GETASTER (width);
    910       if (width >= 0)
    911         goto rflag;
    912       width = -width;
    913       /* FALLTHROUGH */
    914     case '-':
    915       flags |= LADJUST;
    916       goto rflag;
    917     case '+':
    918       sign = '+';
    919       goto rflag;
    920     case '\'':
    921       flags |= GROUPING;
    922       thousands_sep = *(localeconv()->thousands_sep);
    923       grouping = localeconv()->grouping;
    924       goto rflag;
    925     case '.':
    926       if ((ch = *fmt++) == '*') {
    927         GETASTER (prec);
    928         goto rflag;
    929       }
    930       prec = 0;
    931       while (is_digit(ch)) {
    932         prec = 10 * prec + to_digit(ch);
    933         ch = *fmt++;
    934       }
    935       goto reswitch;
    936     case '0':
    937       /*-
    938        * ``Note that 0 is taken as a flag, not as the
    939        * beginning of a field width.''
    940        *  -- ANSI X3J11
    941        */
    942       flags |= ZEROPAD;
    943       goto rflag;
    944     case '1': case '2': case '3': case '4':
    945     case '5': case '6': case '7': case '8': case '9':
    946       n = 0;
    947       do {
    948         n = 10 * n + to_digit(ch);
    949         ch = *fmt++;
    950       } while (is_digit(ch));
    951       if (ch == '$') {
    952         nextarg = n;
    953         if (argtable == NULL) {
    954           argtable = statargtable;
    955           if (__find_arguments(fmt0, orgap,
    956               &argtable) == -1)
    957             goto oomem;
    958         }
    959         goto rflag;
    960       }
    961       width = n;
    962       goto reswitch;
    963 #ifndef NO_FLOATING_POINT
    964     case 'L':
    965       flags |= LONGDBL;
    966       goto rflag;
    967 #endif
    968     case 'h':
    969       if (flags & SHORTINT) {
    970         flags &= ~SHORTINT;
    971         flags |= CHARINT;
    972       } else
    973         flags |= SHORTINT;
    974       goto rflag;
    975     case 'j':
    976       flags |= INTMAXT;
    977       goto rflag;
    978     case 'l':
    979       if (flags & LONGINT) {
    980         flags &= ~LONGINT;
    981         flags |= LLONGINT;
    982       } else
    983         flags |= LONGINT;
    984       goto rflag;
    985     case 'q':
    986       flags |= LLONGINT;  /* not necessarily */
    987       goto rflag;
    988     case 't':
    989       flags |= PTRDIFFT;
    990       goto rflag;
    991     case 'z':
    992       flags |= SIZET;
    993       goto rflag;
    994     case 'C':
    995       flags |= LONGINT;
    996       /*FALLTHROUGH*/
    997     case 'c':
    998 #ifdef NARROW
    999       if (flags & LONGINT) {
   1000         static const mbstate_t initial = { 0 };
   1001         mbstate_t mbs;
   1002         size_t mbseqlen;
   1003 
   1004         mbs = initial;
   1005         mbseqlen = wcrtomb(buf,
   1006             /* The compiler "knows" that wint_t may be smaller than an int so
   1007                it warns about it when used as the type argument to va_arg().
   1008                Since any type of parameter smaller than an int is promoted to an int on a
   1009                function call, we must call GETARG with type int instead of wint_t.
   1010             */
   1011             (wchar_t)GETARG(int), &mbs);
   1012         if (mbseqlen == (size_t)-1) {
   1013           fp->_flags |= __SERR;
   1014           goto error;
   1015         }
   1016         size = (int)mbseqlen;
   1017       } else {
   1018         *buf = (char)(GETARG(int));
   1019         size = 1;
   1020       }
   1021 #else
   1022       if (flags & LONGINT)
   1023         *buf = (wchar_t)GETARG(int);
   1024       else
   1025         *buf = (wchar_t)btowc(GETARG(int));
   1026       size = 1;
   1027 #endif
   1028       result = buf;
   1029       sign = '\0';
   1030       break;
   1031     case 'D':
   1032       flags |= LONGINT;
   1033       /*FALLTHROUGH*/
   1034     case 'd':
   1035     case 'i':
   1036       if (flags & INTMAX_SIZE) {
   1037         ujval = SJARG();
   1038         if ((intmax_t)ujval < 0) {
   1039           ujval = (uintmax_t)(-((intmax_t)ujval));
   1040           sign = '-';
   1041         }
   1042       } else {
   1043         ulval = SARG();
   1044         if ((long)ulval < 0) {
   1045           ulval = (u_long)(-((long)ulval));
   1046           sign = '-';
   1047         }
   1048       }
   1049       base = 10;
   1050       goto number;
   1051 #ifndef NO_FLOATING_POINT
   1052 #ifdef WIDE_DOUBLE
   1053     case 'a':
   1054     case 'A':
   1055       if (ch == 'a') {
   1056         ox[1] = 'x';
   1057         xdigs = xdigs_lower;
   1058         expchar = 'p';
   1059       } else {
   1060         ox[1] = 'X';
   1061         xdigs = xdigs_upper;
   1062         expchar = 'P';
   1063       }
   1064       if (flags & LONGDBL) {
   1065         fparg.ldbl = GETARG(long double);
   1066         dtoaresult =
   1067             __hldtoa(fparg.ldbl, xdigs, prec,
   1068                 &expt, &signflag, &dtoaend);
   1069       } else {
   1070         fparg.dbl = GETARG(double);
   1071         dtoaresult =
   1072             __hdtoa(fparg.dbl, xdigs, prec,
   1073                 &expt, &signflag, &dtoaend);
   1074       }
   1075       if (dtoaresult == NULL)
   1076         goto oomem;
   1077 
   1078       if (prec < 0)
   1079         prec = dtoaend - dtoaresult;
   1080       if (expt == INT_MAX)
   1081         ox[1] = '\0';
   1082       ndig = dtoaend - dtoaresult;
   1083       if (convbuf != NULL)
   1084         free(convbuf);
   1085 #ifndef NARROW
   1086       result = convbuf = __mbsconv(dtoaresult, -1);
   1087 #else
   1088       /*XXX inefficient*/
   1089       result = convbuf = strdup(dtoaresult);
   1090 #endif
   1091       if (result == NULL)
   1092         goto oomem;
   1093       __freedtoa(dtoaresult);
   1094       goto fp_common;
   1095     case 'e':
   1096     case 'E':
   1097       expchar = ch;
   1098       if (prec < 0)
   1099         prec = DEFPREC;
   1100       goto fp_begin;
   1101     case 'f':
   1102     case 'F':
   1103       expchar = '\0';
   1104       goto fp_begin;
   1105     case 'g':
   1106     case 'G':
   1107       expchar = ch - ('g' - 'e');
   1108       if (prec == 0)
   1109         prec = 1;
   1110 fp_begin:
   1111       if (prec < 0)
   1112         prec = DEFPREC;
   1113       if (flags & LONGDBL) {
   1114         fparg.ldbl = GETARG(long double);
   1115         dtoaresult =
   1116             __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec,
   1117             &expt, &signflag, &dtoaend);
   1118       } else {
   1119         fparg.dbl = GETARG(double);
   1120         dtoaresult =
   1121             __dtoa(fparg.dbl, expchar ? 2 : 3, prec,
   1122             &expt, &signflag, &dtoaend);
   1123         if (expt == 9999)
   1124           expt = INT_MAX;
   1125       }
   1126       if (dtoaresult == NULL)
   1127         goto oomem;
   1128       ndig = dtoaend - dtoaresult;
   1129       if (convbuf != NULL)
   1130         free(convbuf);
   1131 #ifndef NARROW
   1132       result = convbuf = __mbsconv(dtoaresult, -1);
   1133 #else
   1134       /*XXX inefficient*/
   1135       result = convbuf = strdup(dtoaresult);
   1136 #endif
   1137       if (result == NULL)
   1138         goto oomem;
   1139       __freedtoa(dtoaresult);
   1140 fp_common:
   1141       if (signflag)
   1142         sign = '-';
   1143       if (expt == INT_MAX) {  /* inf or nan */
   1144         if (*result == 'N') {
   1145           result = (ch >= 'a') ? STRCONST("nan") :
   1146               STRCONST("NAN");
   1147           sign = '\0';
   1148         } else
   1149           result = (ch >= 'a') ? STRCONST("inf") :
   1150               STRCONST("INF");
   1151         size = 3;
   1152         break;
   1153       }
   1154 #else
   1155     //case 'e':
   1156     //case 'E':
   1157     //case 'f':
   1158     //case 'F':
   1159     //case 'g':
   1160     //case 'G':
   1161     //  if (prec == -1) {
   1162     //    prec = DEFPREC;
   1163     //  } else if ((ch == 'g' || ch == 'G') && prec == 0) {
   1164     //    prec = 1;
   1165     //  }
   1166     case 'e':
   1167     case 'E':
   1168       expchar = ch;
   1169       if (prec < 0)
   1170         prec = DEFPREC;
   1171       goto fp_begin;
   1172     case 'f':
   1173     case 'F':
   1174       expchar = '\0';
   1175       goto fp_begin;
   1176     case 'g':
   1177     case 'G':
   1178       expchar = ch - ('g' - 'e');
   1179       if (prec == 0)
   1180         prec = 1;
   1181 fp_begin:
   1182       if (prec < 0)
   1183         prec = DEFPREC;
   1184 
   1185       if (flags & LONGDBL) {
   1186         _double = (double) GETARG(long double);
   1187       } else {
   1188         _double = GETARG(double);
   1189       }
   1190 
   1191       /* do this before tricky precision changes */
   1192       if (isinf(_double)) {
   1193         if (_double < 0)
   1194           sign = '-';
   1195         if (ch == 'E' || ch == 'F' || ch == 'G')
   1196           result = STRCONST("INF");
   1197         else
   1198           result = STRCONST("inf");
   1199         size = 3;
   1200         break;
   1201       }
   1202       if (isnan(_double)) {
   1203         if (ch == 'E' || ch == 'F' || ch == 'G')
   1204           result = STRCONST("NAN");
   1205         else
   1206           result = STRCONST("nan");
   1207         size = 3;
   1208         break;
   1209       }
   1210 
   1211       flags |= FPT;
   1212       dtoaresult = cvt(_double, prec, flags, &softsign, &expt, ch, &ndig);
   1213       if (dtoaresult == NULL)
   1214         goto oomem;
   1215       if (convbuf != NULL)
   1216         free(convbuf);
   1217 #ifndef NARROW
   1218       result = convbuf = __mbsconv(dtoaresult, -1);
   1219 #else
   1220       /*XXX inefficient*/
   1221       result = convbuf = strdup(dtoaresult);
   1222 #endif
   1223       if (result == NULL)
   1224         goto oomem;
   1225       __freedtoa(dtoaresult);
   1226       if (softsign)
   1227         sign = '-';
   1228 #endif
   1229       flags |= FPT;
   1230       if (ch == 'g' || ch == 'G') {
   1231         if (expt > -4 && expt <= prec) {
   1232           /* Make %[gG] smell like %[fF] */
   1233           expchar = '\0';
   1234           if (flags & ALT)
   1235             prec -= expt;
   1236           else
   1237             prec = ndig - expt;
   1238           if (prec < 0)
   1239             prec = 0;
   1240         } else {
   1241           /*
   1242            * Make %[gG] smell like %[eE], but
   1243            * trim trailing zeroes if no # flag.
   1244            *
   1245            * Note: The precision field used with [gG] is the number significant
   1246            * digits to print.  When converting to [eE] the digit before the
   1247            * decimal must not be included in the precision value.
   1248            */
   1249           if (!(flags & ALT))
   1250             prec = ndig - 1;
   1251         }
   1252       }
   1253       if (expchar) {
   1254         dprec = prec; /* In some cases dprec will not be set.  Make sure it is set now */
   1255         expsize = exponent(expstr, expt - 1, expchar);
   1256         size = expsize + prec + 1; /* Leading digit + exponent string + precision */
   1257         if (prec >= 1 || flags & ALT)
   1258           ++size; /* Decimal point is added to character count */
   1259       } else {
   1260         /* space for digits before decimal point */
   1261         if (expt > 0)
   1262           size = expt;
   1263         else  /* "0" */
   1264           size = 1;
   1265         /* space for decimal pt and following digits */
   1266         if (prec || flags & ALT)
   1267           size += prec + 1;
   1268         if (grouping && expt > 0) {
   1269           /* space for thousands' grouping */
   1270           nseps = nrepeats = 0;
   1271           lead = expt;
   1272           while (*grouping != CHAR_MAX) {
   1273             if (lead <= *grouping)
   1274               break;
   1275             lead -= *grouping;
   1276             if (*(grouping+1)) {
   1277               nseps++;
   1278               grouping++;
   1279             } else
   1280               nrepeats++;
   1281           }
   1282           size += nseps + nrepeats;
   1283         } else
   1284           lead = expt;
   1285       }
   1286       break;
   1287 #endif /* !NO_FLOATING_POINT */
   1288     case 'n':
   1289       /*
   1290        * Assignment-like behavior is specified if the
   1291        * value overflows or is otherwise unrepresentable.
   1292        * C99 says to use `signed char' for %hhn conversions.
   1293        */
   1294       if (flags & LLONGINT)
   1295         *GETARG(long long *) = ret;
   1296       else if (flags & SIZET)
   1297         *GETARG(ssize_t *) = (ssize_t)ret;
   1298       else if (flags & PTRDIFFT)
   1299         *GETARG(ptrdiff_t *) = ret;
   1300       else if (flags & INTMAXT)
   1301         *GETARG(intmax_t *) = ret;
   1302       else if (flags & LONGINT)
   1303         *GETARG(long *) = ret;
   1304       else if (flags & SHORTINT)
   1305         *GETARG(short *) = ret;
   1306       else if (flags & CHARINT)
   1307         *GETARG(signed char *) = ret;
   1308       else
   1309         *GETARG(int *) = ret;
   1310       continue; /* no output */
   1311     case 'O':
   1312       flags |= LONGINT;
   1313       /*FALLTHROUGH*/
   1314     case 'o':
   1315       if (flags & INTMAX_SIZE)
   1316         ujval = UJARG();
   1317       else
   1318         ulval = UARG();
   1319       base = 8;
   1320       goto nosign;
   1321     case 'p':
   1322       /*-
   1323        * ``The argument shall be a pointer to void.  The
   1324        * value of the pointer is converted to a sequence
   1325        * of printable characters, in an implementation-
   1326        * defined manner.''
   1327        *  -- ANSI X3J11
   1328        */
   1329       ujval = (uintmax_t) (UINTN) GETARG(void *);
   1330       base = 16;
   1331       xdigs = xdigs_lower;
   1332       flags = flags | INTMAXT;
   1333       ox[1] = 'x';
   1334       goto nosign;
   1335     case 'S':
   1336       flags |= LONGINT;
   1337       /*FALLTHROUGH*/
   1338     case 's':
   1339       if (((flags & LONGINT) ? 1:0) != MULTI) {
   1340         if ((result = GETARG(CHAR_T *)) == NULL)
   1341           result = STRCONST("(null)");
   1342       } else {
   1343         MCHAR_T *mc;
   1344 
   1345         if (convbuf != NULL)
   1346           free(convbuf);
   1347         if ((mc = GETARG(MCHAR_T *)) == NULL)
   1348           result = STRCONST("(null)");
   1349         else {
   1350           convbuf = SCONV(mc, prec);
   1351           if (convbuf == NULL) {
   1352             fp->_flags |= __SERR;
   1353             goto error;
   1354           }
   1355           result = convbuf;
   1356         }
   1357       }
   1358 
   1359       if (prec >= 0) {
   1360         /*
   1361          * can't use STRLEN; can only look for the
   1362          * NUL in the first `prec' characters, and
   1363          * STRLEN() will go further.
   1364          */
   1365         CHAR_T *p = MEMCHR(result, 0, (size_t)prec);
   1366 
   1367         if (p != NULL) {
   1368           size = p - result;
   1369           if (size > prec)
   1370             size = prec;
   1371         } else
   1372           size = prec;
   1373       } else
   1374         size = (int)STRLEN(result);
   1375       sign = '\0';
   1376       break;
   1377     case 'U':
   1378       flags |= LONGINT;
   1379       /*FALLTHROUGH*/
   1380     case 'u':
   1381       if (flags & INTMAX_SIZE)
   1382         ujval = UJARG();
   1383       else
   1384         ulval = UARG();
   1385       base = 10;
   1386       goto nosign;
   1387     case 'X':
   1388       xdigs = xdigs_upper;
   1389       goto hex;
   1390     case 'x':
   1391       xdigs = xdigs_lower;
   1392 hex:
   1393       if (flags & INTMAX_SIZE)
   1394         ujval = UJARG();
   1395       else
   1396         ulval = UARG();
   1397       base = 16;
   1398       /* leading 0x/X only if non-zero */
   1399       if (flags & ALT &&
   1400           (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
   1401         ox[1] = ch;
   1402 
   1403       flags &= ~GROUPING;
   1404       /* unsigned conversions */
   1405 nosign:     sign = '\0';
   1406       /*-
   1407        * ``... diouXx conversions ... if a precision is
   1408        * specified, the 0 flag will be ignored.''
   1409        *  -- ANSI X3J11
   1410        */
   1411 number:     if ((dprec = prec) >= 0)
   1412         flags &= ~ZEROPAD;
   1413 
   1414       /*-
   1415        * ``The result of converting a zero value with an
   1416        * explicit precision of zero is no characters.''
   1417        *  -- ANSI X3J11
   1418        *
   1419        * ``The C Standard is clear enough as is.  The call
   1420        * printf("%#.0o", 0) should print 0.''
   1421        *  -- Defect Report #151
   1422        */
   1423       result = cp = buf + BUF;
   1424       if (flags & INTMAX_SIZE) {
   1425         if (ujval != 0 || prec != 0 ||
   1426             (flags & ALT && base == 8))
   1427         {
   1428           result = __ujtoa(ujval, cp, base,
   1429               flags & ALT, xdigs,
   1430               flags & GROUPING, thousands_sep,
   1431               grouping);
   1432         }
   1433       } else {
   1434         if (ulval != 0 || prec != 0 ||
   1435             (flags & ALT && base == 8))
   1436           result = __ultoa(ulval, cp, base,
   1437               flags & ALT, xdigs,
   1438               flags & GROUPING, thousands_sep,
   1439               grouping);
   1440       }
   1441       size = buf + BUF - result;
   1442       if (size > BUF) /* should never happen */
   1443         abort();
   1444       break;
   1445     default:  /* "%?" prints ?, unless ? is NUL */
   1446       if (ch == '\0')
   1447         goto done;
   1448       /* pretend it was %c with argument ch */
   1449       *buf = ch;
   1450       result = buf;
   1451       size = 1;
   1452       sign = '\0';
   1453       break;
   1454     }
   1455 
   1456     /*
   1457      * All reasonable formats wind up here.  At this point, `result'
   1458      * points to a string which (if not flags&LADJUST) should be
   1459      * padded out to `width' places.  If flags&ZEROPAD, it should
   1460      * first be prefixed by any sign or other prefix; otherwise,
   1461      * it should be blank padded before the prefix is emitted.
   1462      * After any left-hand padding and prefixing, emit zeroes
   1463      * required by a decimal [diouxX] precision, then print the
   1464      * string proper, then emit zeroes required by any leftover
   1465      * floating precision; finally, if LADJUST, pad with blanks.
   1466      *
   1467      * Compute actual size, so we know how much to pad.
   1468      * size excludes decimal prec; realsz includes it.
   1469      */
   1470     realsz = dprec > size ? dprec : size;
   1471     if (sign)
   1472       realsz++;
   1473     if (ox[1])
   1474       realsz += 2;
   1475 
   1476     prsize = width > realsz ? width : realsz;
   1477     if ((unsigned)ret + prsize > INT_MAX) {
   1478       ret = END_OF_FILE;
   1479       goto error;
   1480     }
   1481 
   1482     /* right-adjusting blank padding */
   1483     if ((flags & (LADJUST|ZEROPAD)) == 0)
   1484       PAD(width - realsz, blanks);
   1485 
   1486     /* prefix */
   1487     if (sign)
   1488       PRINT(&sign, 1);
   1489 
   1490     if (ox[1]) {  /* ox[1] is either x, X, or \0 */
   1491       ox[0] = '0';
   1492       PRINT(ox, 2);
   1493     }
   1494 
   1495     /* right-adjusting zero padding */
   1496     if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
   1497       PAD(width - realsz, zeroes);
   1498 
   1499     /* leading zeroes from decimal precision */
   1500     PAD(dprec - size, zeroes);
   1501 
   1502     /* the string or number proper */
   1503 #ifndef NO_FLOATING_POINT
   1504     if ((flags & FPT) == 0) {
   1505       PRINT(result, size);
   1506     } else {  /* glue together f_p fragments */
   1507       if (!expchar) { /* %[fF] or sufficiently short %[gG] */
   1508         if (expt <= 0) {
   1509           PRINT(zeroes, 1);
   1510           if (prec || flags & ALT)
   1511             PRINT(decimal_point, 1);
   1512           PAD(-expt, zeroes);
   1513           /* already handled initial 0's */
   1514           prec += expt;
   1515         } else {
   1516           PRINTANDPAD(result, convbuf + ndig,
   1517               lead, zeroes);
   1518           result += lead;
   1519           if (grouping) {
   1520             while (nseps>0 || nrepeats>0) {
   1521               if (nrepeats > 0)
   1522                 nrepeats--;
   1523               else {
   1524                 grouping--;
   1525                 nseps--;
   1526               }
   1527               PRINT(&thousands_sep,
   1528                   1);
   1529               PRINTANDPAD(result,
   1530                   convbuf + ndig,
   1531                   *grouping, zeroes);
   1532               result += *grouping;
   1533             }
   1534             if (result > convbuf + ndig)
   1535               result = convbuf + ndig;
   1536           }
   1537           if (prec || flags & ALT) {
   1538             buf[0] = *decimal_point;
   1539             PRINT(buf, 1);
   1540           }
   1541         }
   1542         PRINTANDPAD(result, convbuf + ndig, prec,
   1543             zeroes);
   1544       } else {  /* %[eE] or sufficiently long %[gG] */
   1545         if (prec >= 1 || flags & ALT) {
   1546           buf[0] = *result++;
   1547           buf[1] = *decimal_point;
   1548           PRINT(buf, 2);
   1549           PRINT(result, ndig-1);
   1550           PAD(prec - ndig, zeroes);
   1551         } else  /* XeYYY */
   1552           PRINT(result, 1);
   1553         PRINT(expstr, expsize);
   1554       }
   1555     }
   1556 #else
   1557     PRINT(result, size);
   1558 #endif
   1559     /* left-adjusting padding (always blank) */
   1560     if (flags & LADJUST)
   1561       PAD(width - realsz, blanks);
   1562 
   1563     /* finally, adjust ret */
   1564     ret += prsize;
   1565     FLUSH();
   1566   }
   1567 done:
   1568   FLUSH();
   1569 error:
   1570   va_end(orgap);
   1571   if (convbuf != NULL)
   1572     free(convbuf);
   1573   if (__sferror(fp))
   1574     ret = END_OF_FILE;
   1575   if ((argtable != NULL) && (argtable != statargtable))
   1576     free (argtable);
   1577   return (ret);
   1578   /* NOTREACHED */
   1579 oomem:
   1580   errno = ENOMEM;
   1581   ret = END_OF_FILE;
   1582   goto error;
   1583 }
   1584 
   1585 /*
   1586  * Find all arguments when a positional parameter is encountered.  Returns a
   1587  * table, indexed by argument number, of pointers to each arguments.  The
   1588  * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
   1589  * It will be replaces with a malloc-ed one if it overflows.
   1590  */
   1591 static int
   1592 __find_arguments(const CHAR_T *fmt0, va_list ap, union arg **argtable)
   1593 {
   1594   CHAR_T *fmt;    /* format string */
   1595   int ch;     /* character from fmt */
   1596   int n, n2;    /* handy integer (short term usage) */
   1597   CHAR_T *cp;   /* handy char pointer (short term usage) */
   1598   int flags;    /* flags as above */
   1599   enum typeid *typetable; /* table of types */
   1600   enum typeid stattypetable [STATIC_ARG_TBL_SIZE];
   1601   int tablesize;    /* current size of type table */
   1602   int tablemax;   /* largest used index in table */
   1603   int nextarg;    /* 1-based argument index */
   1604 
   1605   /*
   1606    * Add an argument type to the table, expanding if necessary.
   1607    */
   1608 #define ADDTYPE(type) \
   1609   do { \
   1610     if (nextarg >= tablesize) \
   1611       if (__grow_type_table(nextarg, &typetable, \
   1612           &tablesize) == -1) \
   1613         return -1; \
   1614     if (nextarg > tablemax) \
   1615       tablemax = nextarg; \
   1616     typetable[nextarg++] = type; \
   1617   } while (/*CONSTCOND*/0)
   1618 
   1619 #define ADDSARG() \
   1620   do { \
   1621     if (flags & INTMAXT)  \
   1622       ADDTYPE(T_INTMAXT); \
   1623     else if (flags & SIZET)  \
   1624       ADDTYPE(T_SIZET); \
   1625     else if (flags & PTRDIFFT) \
   1626       ADDTYPE(T_PTRDIFFT); \
   1627     else if (flags & LLONGINT) \
   1628       ADDTYPE(T_LLONG); \
   1629     else if (flags & LONGINT) \
   1630       ADDTYPE(T_LONG); \
   1631     else \
   1632       ADDTYPE(T_INT); \
   1633   } while (/*CONSTCOND*/0)
   1634 
   1635 #define ADDUARG() \
   1636   do { \
   1637     if (flags & INTMAXT)  \
   1638       ADDTYPE(T_UINTMAXT); \
   1639     else if (flags & SIZET)  \
   1640       ADDTYPE(T_SIZET); \
   1641     else if (flags & PTRDIFFT) \
   1642       ADDTYPE(T_PTRDIFFT); \
   1643     else if (flags & LLONGINT) \
   1644       ADDTYPE(T_U_LLONG); \
   1645     else if (flags & LONGINT) \
   1646       ADDTYPE(T_U_LONG); \
   1647     else \
   1648       ADDTYPE(T_U_INT); \
   1649   } while (/*CONSTCOND*/0)
   1650   /*
   1651    * Add * arguments to the type array.
   1652    */
   1653 #define ADDASTER() \
   1654   n2 = 0; \
   1655   cp = fmt; \
   1656   while (is_digit(*cp)) { \
   1657     n2 = 10 * n2 + to_digit(*cp); \
   1658     cp++; \
   1659   } \
   1660   if (*cp == '$') { \
   1661     int hold = nextarg; \
   1662     nextarg = n2; \
   1663     ADDTYPE(T_INT); \
   1664     nextarg = hold; \
   1665     fmt = ++cp; \
   1666   } else { \
   1667     ADDTYPE(T_INT); \
   1668   }
   1669   fmt = (CHAR_T *)__UNCONST(fmt0);
   1670   typetable = stattypetable;
   1671   tablesize = STATIC_ARG_TBL_SIZE;
   1672   tablemax = 0;
   1673   nextarg = 1;
   1674   for (n = 0; n < STATIC_ARG_TBL_SIZE; n++)
   1675     typetable[n] = T_UNUSED;
   1676 
   1677   /*
   1678    * Scan the format for conversions (`%' character).
   1679    */
   1680   for (;;) {
   1681     for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
   1682       /* void */;
   1683     if (ch == '\0')
   1684       goto done;
   1685     fmt++;    /* skip over '%' */
   1686 
   1687     flags = 0;
   1688 
   1689 rflag:    ch = *fmt++;
   1690 reswitch: switch (ch) {
   1691     case ' ':
   1692     case '#':
   1693       goto rflag;
   1694     case '*':
   1695       ADDASTER ();
   1696       goto rflag;
   1697     case '-':
   1698     case '+':
   1699     case '\'':
   1700       goto rflag;
   1701     case '.':
   1702       if ((ch = *fmt++) == '*') {
   1703         ADDASTER ();
   1704         goto rflag;
   1705       }
   1706       while (is_digit(ch)) {
   1707         ch = *fmt++;
   1708       }
   1709       goto reswitch;
   1710     case '0':
   1711       goto rflag;
   1712     case '1': case '2': case '3': case '4':
   1713     case '5': case '6': case '7': case '8': case '9':
   1714       n = 0;
   1715       do {
   1716         n = 10 * n + to_digit(ch);
   1717         ch = *fmt++;
   1718       } while (is_digit(ch));
   1719       if (ch == '$') {
   1720         nextarg = n;
   1721         goto rflag;
   1722       }
   1723       goto reswitch;
   1724 #ifndef NO_FLOATING_POINT
   1725     case 'L':
   1726       flags |= LONGDBL;
   1727       goto rflag;
   1728 #endif
   1729     case 'h':
   1730       if (flags & SHORTINT) {
   1731         flags &= ~SHORTINT;
   1732         flags |= CHARINT;
   1733       } else
   1734         flags |= SHORTINT;
   1735       goto rflag;
   1736     case 'j':
   1737       flags |= INTMAXT;
   1738       goto rflag;
   1739     case 'l':
   1740       if (flags & LONGINT) {
   1741         flags &= ~LONGINT;
   1742         flags |= LLONGINT;
   1743       } else
   1744         flags |= LONGINT;
   1745       goto rflag;
   1746     case 'q':
   1747       flags |= LLONGINT;  /* not necessarily */
   1748       goto rflag;
   1749     case 't':
   1750       flags |= PTRDIFFT;
   1751       goto rflag;
   1752     case 'z':
   1753       flags |= SIZET;
   1754       goto rflag;
   1755     case 'C':
   1756       flags |= LONGINT;
   1757       /*FALLTHROUGH*/
   1758     case 'c':
   1759       if (flags & LONGINT)
   1760         ADDTYPE(T_WINT);
   1761       else
   1762         ADDTYPE(T_INT);
   1763       break;
   1764     case 'D':
   1765       flags |= LONGINT;
   1766       /*FALLTHROUGH*/
   1767     case 'd':
   1768     case 'i':
   1769       ADDSARG();
   1770       break;
   1771 #ifndef NO_FLOATING_POINT
   1772     case 'a':
   1773     case 'A':
   1774     case 'e':
   1775     case 'E':
   1776     case 'f':
   1777     case 'g':
   1778     case 'G':
   1779       if (flags & LONGDBL)
   1780         ADDTYPE(T_LONG_DOUBLE);
   1781       else
   1782         ADDTYPE(T_DOUBLE);
   1783       break;
   1784 #endif /* !NO_FLOATING_POINT */
   1785     case 'n':
   1786       if (flags & INTMAXT)
   1787         ADDTYPE(TP_INTMAXT);
   1788       else if (flags & PTRDIFFT)
   1789         ADDTYPE(TP_PTRDIFFT);
   1790       else if (flags & SIZET)
   1791         ADDTYPE(TP_SIZET);
   1792       else if (flags & LLONGINT)
   1793         ADDTYPE(TP_LLONG);
   1794       else if (flags & LONGINT)
   1795         ADDTYPE(TP_LONG);
   1796       else if (flags & SHORTINT)
   1797         ADDTYPE(TP_SHORT);
   1798       else if (flags & CHARINT)
   1799         ADDTYPE(TP_SCHAR);
   1800       else
   1801         ADDTYPE(TP_INT);
   1802       continue; /* no output */
   1803     case 'O':
   1804       flags |= LONGINT;
   1805       /*FALLTHROUGH*/
   1806     case 'o':
   1807       ADDUARG();
   1808       break;
   1809     case 'p':
   1810       ADDTYPE(TP_VOID);
   1811       break;
   1812     case 'S':
   1813       flags |= LONGINT;
   1814       /*FALLTHROUGH*/
   1815     case 's':
   1816       if (flags & LONGINT)
   1817         ADDTYPE(TP_WCHAR);
   1818       else
   1819         ADDTYPE(TP_CHAR);
   1820       break;
   1821     case 'U':
   1822       flags |= LONGINT;
   1823       /*FALLTHROUGH*/
   1824     case 'u':
   1825     case 'X':
   1826     case 'x':
   1827       ADDUARG();
   1828       break;
   1829     default:  /* "%?" prints ?, unless ? is NUL */
   1830       if (ch == '\0')
   1831         goto done;
   1832       break;
   1833     }
   1834   }
   1835 done:
   1836   /*
   1837    * Build the argument table.
   1838    */
   1839   if (tablemax >= STATIC_ARG_TBL_SIZE) {
   1840     *argtable = (union arg *)
   1841         malloc (sizeof (union arg) * (tablemax + 1));
   1842     if (*argtable == NULL)
   1843       return -1;
   1844   }
   1845 
   1846   (*argtable) [0].intarg = 0;
   1847   for (n = 1; n <= tablemax; n++) {
   1848     switch (typetable [n]) {
   1849         case T_UNUSED: /* whoops! */
   1850       (*argtable) [n].intarg = va_arg (ap, int);
   1851       break;
   1852         case TP_SCHAR:
   1853       (*argtable) [n].pschararg = va_arg (ap, signed char *);
   1854       break;
   1855         case TP_SHORT:
   1856       (*argtable) [n].pshortarg = va_arg (ap, short *);
   1857       break;
   1858         case T_INT:
   1859       (*argtable) [n].intarg = va_arg (ap, int);
   1860       break;
   1861         case T_U_INT:
   1862       (*argtable) [n].uintarg = va_arg (ap, unsigned int);
   1863       break;
   1864         case TP_INT:
   1865       (*argtable) [n].pintarg = va_arg (ap, int *);
   1866       break;
   1867         case T_LONG:
   1868       (*argtable) [n].longarg = va_arg (ap, long);
   1869       break;
   1870         case T_U_LONG:
   1871       (*argtable) [n].ulongarg = va_arg (ap, unsigned long);
   1872       break;
   1873         case TP_LONG:
   1874       (*argtable) [n].plongarg = va_arg (ap, long *);
   1875       break;
   1876         case T_LLONG:
   1877       (*argtable) [n].longlongarg = va_arg (ap, long long);
   1878       break;
   1879         case T_U_LLONG:
   1880       (*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long);
   1881       break;
   1882         case TP_LLONG:
   1883       (*argtable) [n].plonglongarg = va_arg (ap, long long *);
   1884       break;
   1885         case T_PTRDIFFT:
   1886       (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t);
   1887       break;
   1888         case TP_PTRDIFFT:
   1889       (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *);
   1890       break;
   1891         case T_SIZET:
   1892       (*argtable) [n].sizearg = va_arg (ap, size_t);
   1893       break;
   1894         case TP_SIZET:
   1895       (*argtable) [n].psizearg = va_arg (ap, size_t *);
   1896       break;
   1897         case T_INTMAXT:
   1898       (*argtable) [n].intmaxarg = va_arg (ap, intmax_t);
   1899       break;
   1900         case T_UINTMAXT:
   1901       (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t);
   1902       break;
   1903         case TP_INTMAXT:
   1904       (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *);
   1905       break;
   1906         case T_DOUBLE:
   1907 #ifndef NO_FLOATING_POINT
   1908       (*argtable) [n].doublearg = va_arg (ap, double);
   1909 #endif
   1910       break;
   1911         case T_LONG_DOUBLE:
   1912 #ifndef NO_FLOATING_POINT
   1913       (*argtable) [n].longdoublearg = va_arg (ap, long double);
   1914 #endif
   1915       break;
   1916         case TP_CHAR:
   1917       (*argtable) [n].pchararg = va_arg (ap, char *);
   1918       break;
   1919         case TP_VOID:
   1920       (*argtable) [n].pvoidarg = va_arg (ap, void *);
   1921       break;
   1922         case T_WINT:
   1923       (*argtable) [n].wintarg = va_arg (ap, int);
   1924       break;
   1925         case TP_WCHAR:
   1926       (*argtable) [n].pwchararg = va_arg (ap, wchar_t *);
   1927       break;
   1928     }
   1929   }
   1930 
   1931   if ((typetable != NULL) && (typetable != stattypetable))
   1932     free (typetable);
   1933   return 0;
   1934 }
   1935 
   1936 /*
   1937  * Increase the size of the type table.
   1938  */
   1939 static int
   1940 __grow_type_table (int nextarg, enum typeid **typetable, int *tablesize)
   1941 {
   1942   enum typeid *const oldtable = *typetable;
   1943   const int oldsize = *tablesize;
   1944   enum typeid *newtable;
   1945   int n, newsize = oldsize * 2;
   1946 
   1947   if (newsize < nextarg + 1)
   1948     newsize = nextarg + 1;
   1949   if (oldsize == STATIC_ARG_TBL_SIZE) {
   1950     if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL)
   1951       return -1;
   1952     memcpy(newtable, oldtable, oldsize * sizeof(enum typeid));
   1953   } else {
   1954     newtable = realloc(oldtable, newsize * sizeof(enum typeid));
   1955     if (newtable == NULL) {
   1956       free(oldtable);
   1957       return -1;
   1958     }
   1959   }
   1960   for (n = oldsize; n < newsize; n++)
   1961     newtable[n] = T_UNUSED;
   1962 
   1963   *typetable = newtable;
   1964   *tablesize = newsize;
   1965   return 0;
   1966 }
   1967 
   1968 
   1969 #ifndef NO_FLOATING_POINT
   1970 #ifndef WIDE_DOUBLE
   1971 static char *
   1972 cvt(double value, int ndigits, int flags, char *sign, int *decpt, int ch,
   1973     int *length)
   1974 {
   1975   int mode, dsgn;
   1976   char *digits, *bp, *rve;
   1977 
   1978   _DIAGASSERT(decpt != NULL);
   1979   _DIAGASSERT(length != NULL);
   1980   _DIAGASSERT(sign != NULL);
   1981 
   1982   if (ch == 'f') {
   1983     mode = 3;   /* ndigits after the decimal point */
   1984   } else {
   1985     /* To obtain ndigits after the decimal point for the 'e'
   1986      * and 'E' formats, round to ndigits + 1 significant
   1987      * figures.
   1988      */
   1989     if (ch == 'e' || ch == 'E') {
   1990       ndigits++;
   1991     }
   1992     mode = 2;   /* ndigits significant digits */
   1993   }
   1994 
   1995   digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
   1996   if (digits == NULL)
   1997     return NULL;
   1998   if (dsgn) {
   1999     value = -value;
   2000     *sign = '-';
   2001   } else
   2002     *sign = '\000';
   2003   if ((ch != 'g' && ch != 'G') || flags & ALT) {  /* Print trailing zeros */
   2004     bp = digits + ndigits;
   2005     if (ch == 'f') {
   2006       if (*digits == '0' && value)
   2007         *decpt = -ndigits + 1;
   2008       bp += *decpt;
   2009     }
   2010     while (rve < bp)
   2011       *rve++ = '0';
   2012   }
   2013   *length = rve - digits;
   2014   return digits;
   2015 }
   2016 #endif
   2017 
   2018 static int
   2019 exponent(CHAR_T *p0, int expo, int fmtch)
   2020 {
   2021   CHAR_T *p, *t;
   2022   CHAR_T expbuf[MAXEXPDIG];
   2023 
   2024   p = p0;
   2025   *p++ = fmtch;
   2026   if (expo < 0) {
   2027     expo = -expo;
   2028     *p++ = '-';
   2029   }
   2030   else
   2031     *p++ = '+';
   2032   t = expbuf + MAXEXPDIG;
   2033   if (expo > 9) {
   2034     do {
   2035       *--t = to_char(expo % 10);
   2036     } while ((expo /= 10) > 9);
   2037     *--t = to_char(expo);
   2038     for (; t < expbuf + MAXEXPDIG; *p++ = *t++);
   2039   }
   2040   else {
   2041     /*
   2042      * Exponents for decimal floating point conversions
   2043      * (%[eEgG]) must be at least two characters long,
   2044      * whereas exponents for hexadecimal conversions can
   2045      * be only one character long.
   2046      */
   2047     if (fmtch == 'e' || fmtch == 'E')
   2048       *p++ = '0';
   2049     *p++ = to_char(expo);
   2050   }
   2051   return (p - p0);
   2052 }
   2053 #endif /* !NO_FLOATING_POINT */
   2054