vfprintf.c

Go to the documentation of this file.
00001 
00016 #define __FORMATTER__
00017 /*
00018  *    Copyright 2004-2006 Intel Corporation
00019  * 
00020  *    Licensed under the Apache License, Version 2.0 (the "License");
00021  *    you may not use this file except in compliance with the License.
00022  *    You may obtain a copy of the License at
00023  * 
00024  *        http://www.apache.org/licenses/LICENSE-2.0
00025  * 
00026  *    Unless required by applicable law or agreed to in writing, software
00027  *    distributed under the License is distributed on an "AS IS" BASIS,
00028  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00029  *    See the License for the specific language governing permissions and
00030  *    limitations under the License.
00031  */
00032 
00033 /*-
00034  * Copyright (c) 1990, 1993
00035  *      The Regents of the University of California.  All rights reserved.
00036  *
00037  * This code is derived from software contributed to Berkeley by
00038  * Chris Torek.
00039  *
00040  * Redistribution and use in source and binary forms, with or without
00041  * modification, are permitted provided that the following conditions
00042  * are met:
00043  * 1. Redistributions of source code must retain the above copyright
00044  *    notice, this list of conditions and the following disclaimer.
00045  * 2. Redistributions in binary form must reproduce the above copyright
00046  *    notice, this list of conditions and the following disclaimer in the
00047  *    documentation and/or other materials provided with the distribution.
00048  * 3. All advertising materials mentioning features or use of this software
00049  *    must display the following acknowledgement:
00050  *      This product includes software developed by the University of
00051  *      California, Berkeley and its contributors.
00052  * 4. Neither the name of the University nor the names of its contributors
00053  *    may be used to endorse or promote products derived from this software
00054  *    without specific prior written permission.
00055  *
00056  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00057  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00058  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00059  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00060  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00061  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00062  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00063  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00064  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00065  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00066  * SUCH DAMAGE.
00067  */
00068 
00069 
00070 #include <stdarg.h>
00071 #include <memory.h>
00072 
00073 #include "config.h"
00074 #include "compat/fpclassify.h"
00075 
00076 
00077 #if defined(LIBC_SCCS) && !defined(lint)
00078 static char sccsid[] = "@(#)vfprintf.c  8.1 (Berkeley) 6/4/93";
00079 #endif /* LIBC_SCCS and not lint */
00080 
00081 #ifdef HAVE_SYS_CDEFS_H
00082 #include <sys/cdefs.h>
00083 #endif
00084 
00085 #define __FBSDID(x)
00086 __FBSDID("$FreeBSD: src/lib/libc/stdio/vfprintf.c,v 1.69 2005/04/16 22:36:51 das Exp $");
00087 
00088 /*
00089  * Actual printf innards.
00090  *
00091  * This code is large and complicated...
00092  */
00093 
00094 #ifndef __FORMATTER__
00095 #include "namespace.h"
00096 #endif
00097 #include <sys/types.h>
00098 
00099 #include <ctype.h>
00100 #include <limits.h>
00101 #include <locale.h>
00102 #include <stddef.h>
00103 #ifdef HAVE_STDINT_H
00104 #include <stdint.h>
00105 #endif
00106 #include <stdio.h>
00107 #include <stdlib.h>
00108 #include <string.h>
00109 #include <wchar.h>
00110 
00111 #include <stdarg.h>
00112 
00113 #ifndef __FORMATTER__
00114 #include "un-namespace.h"
00115 
00116 #include "libc_private.h"
00117 #include "local.h"
00118 #include "fvwrite.h"
00119 
00120 #else
00121 
00122 extern size_t formatter_format(void* fmtobj, char* str, size_t strsz);
00123 
00124 /*
00125  * Formatter I/O descriptors for __sfvwrite().
00126  */
00127 struct __siov {
00128         void    *iov_base;
00129         size_t  iov_len;
00130 };
00131 struct __suio {
00132         struct  __siov *uio_iov;
00133         int     uio_iovcnt;
00134         int     uio_resid;
00135 
00136 };
00137 #endif  // __FORMATTER__
00138 
00139 #ifndef INTMAX_MAX
00140 
00141 #include <limits.h>
00142 
00143 #if   defined(LLONG_MAX)
00144 #define INTMAX_MAX LLONG_MAX
00145 #elif defined(LONG_LONG_MAX)
00146 #define INTMAX_MAX LONG_LONG_MAX
00147 #else
00148 #define INTMAX_MAX INT_MAX
00149 #endif 
00150 
00151 #endif // INTMAX_MAX
00152 
00153 #ifdef __FORMATTER__
00154 #define reallocf realloc
00155 #endif
00156 
00157 #ifndef __THROW
00158 #define __THROW
00159 #endif
00160 
00161 union arg {
00162         int     intarg;
00163         u_int   uintarg;
00164         long    longarg;
00165         u_long  ulongarg;
00166         long long longlongarg;
00167         unsigned long long ulonglongarg;
00168         ptrdiff_t ptrdiffarg;
00169         size_t  sizearg;
00170         intmax_t intmaxarg;
00171         uintmax_t uintmaxarg;
00172         void    *pvoidarg;
00173         char    *pchararg;
00174         signed char *pschararg;
00175         short   *pshortarg;
00176         int     *pintarg;
00177         long    *plongarg;
00178         long long *plonglongarg;
00179         ptrdiff_t *pptrdiffarg;
00180         size_t  *psizearg;
00181         intmax_t *pintmaxarg;
00182 #ifndef NO_FLOATING_POINT
00183         double  doublearg;
00184         long double longdoublearg;
00185 #endif
00186         wint_t  wintarg;
00187         wchar_t *pwchararg;
00188 };
00189 
00190 /*
00191  * Type ids for argument type table.
00192  */
00193 enum typeid {
00194         T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT,
00195         T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG,
00196         T_PTRDIFFT, TP_PTRDIFFT, T_SIZET, TP_SIZET,
00197         T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR,
00198         T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR
00199 };
00200 
00201 #ifndef __FORMATTER__
00202 static int      __sprint(FILE *, struct __suio *);
00203 static int      __sbprintf(FILE *, const char *, va_list) __printflike(2, 0);
00204 #endif // __FORMATTER__
00205 static char     *__ujtoa(uintmax_t, char *, int, int, const char *, int, char,
00206                     const char *);
00207 static char     *__ultoa(u_long, char *, int, int, const char *, int, char,
00208                     const char *);
00209 static char     *__wcsconv(wchar_t *, int);
00210 static void     __find_arguments(const char *, va_list, union arg **);
00211 static void     __grow_type_table(int, enum typeid **, int *);
00212 
00213 /*
00214  * Flush out all the vectors defined by the given uio,
00215  * then reset it so that it can be reused.
00216  */
00217 #ifndef __FORMATTER__
00218 static int
00219 __sprint(FILE *fp, struct __suio *uio)
00220 {
00221         int err;
00222 
00223         if (uio->uio_resid == 0) {
00224                 uio->uio_iovcnt = 0;
00225                 return (0);
00226         }
00227         err = __sfvwrite(fp, uio);
00228         uio->uio_resid = 0;
00229         uio->uio_iovcnt = 0;
00230         return (err);
00231 }
00232 #endif // __FORMATTER__
00233 
00234 /*
00235  * Helper function for `fprintf to unbuffered unix file': creates a
00236  * temporary buffer.  We only work on write-only files; this avoids
00237  * worries about ungetc buffers and so forth.
00238  */
00239 #ifndef __FORMATTER__
00240 static int
00241 __sbprintf(FILE *fp, const char *fmt, va_list ap)
00242 {
00243         int ret;
00244         FILE fake;
00245         unsigned char buf[BUFSIZ];
00246 
00247         /* copy the important variables */
00248         fake._flags = fp->_flags & ~__SNBF;
00249         fake._file = fp->_file;
00250         fake._cookie = fp->_cookie;
00251         fake._write = fp->_write;
00252         fake._extra = fp->_extra;
00253 
00254         /* set up the buffer */
00255         fake._bf._base = fake._p = buf;
00256         fake._bf._size = fake._w = sizeof(buf);
00257         fake._lbfsize = 0;      /* not actually used, but Just In Case */
00258 
00259         /* do the work, then copy any error status */
00260         ret = __vfprintf(&fake, fmt, ap);
00261         if (ret >= 0 && __fflush(&fake))
00262                 ret = EOF;
00263         if (fake._flags & __SERR)
00264                 fp->_flags |= __SERR;
00265         return (ret);
00266 }
00267 #endif // __FORMATTER__
00268 
00269 /*
00270  * Macros for converting digits to letters and vice versa
00271  */
00272 #define to_digit(c)     ((c) - '0')
00273 #define is_digit(c)     ((unsigned)to_digit(c) <= 9)
00274 #define to_char(n)      ((n) + '0')
00275 
00276 /*
00277  * Convert an unsigned long to ASCII for printf purposes, returning
00278  * a pointer to the first character of the string representation.
00279  * Octal numbers can be forced to have a leading zero; hex numbers
00280  * use the given digits.
00281  */
00282 static char *
00283 __ultoa(u_long val, char *endp, int base, int octzero, const char *xdigs,
00284         int needgrp, char thousep, const char *grp)
00285 {
00286         char *cp = endp;
00287         long sval;
00288         int ndig;
00289 
00290         /*
00291          * Handle the three cases separately, in the hope of getting
00292          * better/faster code.
00293          */
00294         switch (base) {
00295         case 10:
00296                 if (val < 10) { /* many numbers are 1 digit */
00297                         *--cp = to_char(val);
00298                         return (cp);
00299                 }
00300                 ndig = 0;
00301                 /*
00302                  * On many machines, unsigned arithmetic is harder than
00303                  * signed arithmetic, so we do at most one unsigned mod and
00304                  * divide; this is sufficient to reduce the range of
00305                  * the incoming value to where signed arithmetic works.
00306                  */
00307                 if (val > LONG_MAX) {
00308                         *--cp = to_char(val % 10);
00309                         ndig++;
00310                         sval = val / 10;
00311                 } else
00312                         sval = val;
00313                 do {
00314                         *--cp = to_char(sval % 10);
00315                         ndig++;
00316                         /*
00317                          * If (*grp == CHAR_MAX) then no more grouping
00318                          * should be performed.
00319                          */
00320                         if (needgrp && ndig == *grp && *grp != CHAR_MAX
00321                                         && sval > 9) {
00322                                 *--cp = thousep;
00323                                 ndig = 0;
00324                                 /*
00325                                  * If (*(grp+1) == '\0') then we have to
00326                                  * use *grp character (last grouping rule)
00327                                  * for all next cases
00328                                  */
00329                                 if (*(grp+1) != '\0')
00330                                         grp++;
00331                         }
00332                         sval /= 10;
00333                 } while (sval != 0);
00334                 break;
00335 
00336         case 8:
00337                 do {
00338                         *--cp = to_char(val & 7);
00339                         val >>= 3;
00340                 } while (val);
00341                 if (octzero && *cp != '0')
00342                         *--cp = '0';
00343                 break;
00344 
00345         case 16:
00346                 do {
00347                         *--cp = xdigs[val & 15];
00348                         val >>= 4;
00349                 } while (val);
00350                 break;
00351 
00352         default:                        /* oops */
00353                 abort();
00354         }
00355         return (cp);
00356 }
00357 
00358 /* Identical to __ultoa, but for intmax_t. */
00359 static char *
00360 __ujtoa(uintmax_t val, char *endp, int base, int octzero, const char *xdigs, 
00361         int needgrp, char thousep, const char *grp)
00362 {
00363         char *cp = endp;
00364         intmax_t sval;
00365         int ndig;
00366 
00367         /* quick test for small values; __ultoa is typically much faster */
00368         /* (perhaps instead we should run until small, then call __ultoa?) */
00369         if (val <= ULONG_MAX)
00370                 return (__ultoa((u_long)val, endp, base, octzero, xdigs,
00371                     needgrp, thousep, grp));
00372         switch (base) {
00373         case 10:
00374                 if (val < 10) {
00375                         *--cp = to_char(val % 10);
00376                         return (cp);
00377                 }
00378                 ndig = 0;
00379                 if (val > INTMAX_MAX) {
00380                         *--cp = to_char(val % 10);
00381                         ndig++;
00382                         sval = val / 10;
00383                 } else
00384                         sval = val;
00385                 do {
00386                         *--cp = to_char(sval % 10);
00387                         ndig++;
00388                         /*
00389                          * If (*grp == CHAR_MAX) then no more grouping
00390                          * should be performed.
00391                          */
00392                         if (needgrp && *grp != CHAR_MAX && ndig == *grp
00393                                         && sval > 9) {
00394                                 *--cp = thousep;
00395                                 ndig = 0;
00396                                 /*
00397                                  * If (*(grp+1) == '\0') then we have to
00398                                  * use *grp character (last grouping rule)
00399                                  * for all next cases
00400                                  */
00401                                 if (*(grp+1) != '\0')
00402                                         grp++;
00403                         }
00404                         sval /= 10;
00405                 } while (sval != 0);
00406                 break;
00407 
00408         case 8:
00409                 do {
00410                         *--cp = to_char(val & 7);
00411                         val >>= 3;
00412                 } while (val);
00413                 if (octzero && *cp != '0')
00414                         *--cp = '0';
00415                 break;
00416 
00417         case 16:
00418                 do {
00419                         *--cp = xdigs[val & 15];
00420                         val >>= 4;
00421                 } while (val);
00422                 break;
00423 
00424         default:
00425                 abort();
00426         }
00427         return (cp);
00428 }
00429 
00430 /*
00431  * Convert a wide character string argument for the %ls format to a multibyte
00432  * string representation. ``prec'' specifies the maximum number of bytes
00433  * to output. If ``prec'' is greater than or equal to zero, we can't assume
00434  * that the wide char. string ends in a null character.
00435  */
00436 static char *
00437 __wcsconv(wchar_t *wcsarg, int prec)
00438 {
00439         static const mbstate_t initial;
00440         mbstate_t mbs;
00441         char buf[MB_LEN_MAX];
00442         wchar_t *p;
00443         char *convbuf, *mbp;
00444         size_t clen, nbytes;
00445 
00446         /*
00447          * Determine the number of bytes to output and allocate space for
00448          * the output.
00449          */
00450         if (prec >= 0) {
00451                 nbytes = 0;
00452                 p = wcsarg;
00453                 mbs = initial;
00454                 for (;;) {
00455                         clen = wcrtomb(buf, *p++, &mbs);
00456                         if (clen == 0 || clen == (size_t)-1 ||
00457                             nbytes + clen > prec)
00458                                 break;
00459                         nbytes += clen;
00460                 }
00461         } else {
00462                 p = wcsarg;
00463                 mbs = initial;
00464                 nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs);
00465                 if (nbytes == (size_t)-1)
00466                         return (NULL);
00467         }
00468         if ((convbuf = malloc(nbytes + 1)) == NULL)
00469                 return (NULL);
00470 
00471         /*
00472          * Fill the output buffer with the multibyte representations of as
00473          * many wide characters as will fit.
00474          */
00475         mbp = convbuf;
00476         p = wcsarg;
00477         mbs = initial;
00478         while (mbp - convbuf < nbytes) {
00479                 clen = wcrtomb(mbp, *p++, &mbs);
00480                 if (clen == 0 || clen == (size_t)-1)
00481                         break;
00482                 mbp += clen;
00483         }
00484         if (clen == (size_t)-1) {
00485                 free(convbuf);
00486                 return (NULL);
00487         }
00488         *mbp = '\0';
00489 
00490         return (convbuf);
00491 }
00492 
00493 /*
00494  * MT-safe version
00495  */
00496 #ifndef __FORMATTER__
00497 int
00498 vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap)
00499 
00500 {
00501         int ret;
00502 
00503         FLOCKFILE(fp);
00504         ret = __vfprintf(fp, fmt0, ap);
00505         FUNLOCKFILE(fp);
00506         return (ret);
00507 }
00508 #endif // __FORMATTER__
00509 
00510 #ifndef NO_FLOATING_POINT
00511 
00512 #ifndef __FORMATTER__
00513 #define dtoa            __dtoa
00514 #define freedtoa        __freedtoa
00515 #endif // __FORMATTER__
00516 
00517 #include <float.h>
00518 #include <math.h>
00519 
00520 #include "floatio.h"
00521 
00522 // // /*
00523 // //  * (copied from floatio.h)
00524 // //  */
00525 // // /*
00526 // //  * MAXEXPDIG is the maximum number of decimal digits needed to store a
00527 // //  * floating point exponent in the largest supported format.  It should
00528 // //  * be ceil(log10(LDBL_MAX_10_EXP)) or, if hexadecimal floating point
00529 // //  * conversions are supported, ceil(log10(LDBL_MAX_EXP)).  But since it
00530 // //  * is presently never greater than 5 in practice, we fudge it.
00531 // //  */
00532 // // #define   MAXEXPDIG       6
00533 // // #if LDBL_MAX_EXP > 999999
00534 // // #error "floating point buffers too small"
00535 // #endif /* __FORMATTER__ */
00536 
00537 // static char *__ldtoa(long double *, int, int, int *, int *, char **);
00538 // #endif
00539 
00540 #include "gdtoa.h"
00541 
00542 #define DEFPREC         6
00543 
00544 static int exponent(char *, int, int);
00545 
00546 #endif /* !NO_FLOATING_POINT */
00547 
00548 /*
00549  * The size of the buffer we use as scratch space for integer
00550  * conversions, among other things.  Technically, we would need the
00551  * most space for base 10 conversions with thousands' grouping
00552  * characters between each pair of digits.  100 bytes is a
00553  * conservative overestimate even for a 128-bit uintmax_t.
00554  */
00555 #define BUF     100
00556 
00557 #define STATIC_ARG_TBL_SIZE 8           /* Size of static argument table. */
00558 
00559 /*
00560  * Flags used during conversion.
00561  */
00562 #define ALT             0x001           /* alternate form */
00563 #define LADJUST         0x004           /* left adjustment */
00564 #define LONGDBL         0x008           /* long double */
00565 #define LONGINT         0x010           /* long integer */
00566 #define LLONGINT        0x020           /* long long integer */
00567 #define SHORTINT        0x040           /* short integer */
00568 #define ZEROPAD         0x080           /* zero (as opposed to blank) pad */
00569 #define FPT             0x100           /* Floating point number */
00570 #define GROUPING        0x200           /* use grouping ("'" flag) */
00571                                         /* C99 additional size modifiers: */
00572 #define SIZET           0x400           /* size_t */
00573 #define PTRDIFFT        0x800           /* ptrdiff_t */
00574 #define INTMAXT         0x1000          /* intmax_t */
00575 #define CHARINT         0x2000          /* print char using int format */
00576 
00577 /*
00578  * Non-MT-safe version
00579  */
00580 int
00581 //__vfprintf(FILE *fp, const char *fmt0, va_list ap)
00582 vsnprintf(char *str, size_t strsz, const char *fmt0, va_list ap)
00583 {
00584         char *fmt;              /* format string */
00585         int ch;                 /* character from fmt */
00586         int n, n2;              /* handy integer (short term usage) */
00587         char *cp;               /* handy char pointer (short term usage) */
00588 #ifndef __FORMATTER__
00589         struct __siov *iovp;    /* for PRINT macro */
00590 #endif // __FORMATTER__
00591         int flags;              /* flags as above */
00592         int ret;                /* return value accumulator */
00593         int width;              /* width from format (%8d), or 0 */
00594         int prec;               /* precision from format; <0 for N/A */
00595         char sign;              /* sign prefix (' ', '+', '-', or \0) */
00596         char thousands_sep;     /* locale specific thousands separator */
00597         const char *grouping;   /* locale specific numeric grouping rules */
00598 #ifndef NO_FLOATING_POINT
00599         /*
00600          * We can decompose the printed representation of floating
00601          * point numbers into several parts, some of which may be empty:
00602          *
00603          * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
00604          *    A       B     ---C---      D       E   F
00605          *
00606          * A:   'sign' holds this value if present; '\0' otherwise
00607          * B:   ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
00608          * C:   cp points to the string MMMNNN.  Leading and trailing
00609          *      zeros are not in the string and must be added.
00610          * D:   expchar holds this character; '\0' if no exponent, e.g. %f
00611          * F:   at least two digits for decimal, at least one digit for hex
00612          */
00613         char *decimal_point;    /* locale specific decimal point */
00614         int signflag;           /* true if float is negative */
00615         union {                 /* floating point arguments %[aAeEfFgG] */
00616                 double dbl;
00617                 long double ldbl;
00618         } fparg;
00619         int expt;               /* integer value of exponent */
00620         char expchar;           /* exponent character: [eEpP\0] */
00621         char *dtoaend;          /* pointer to end of converted digits */
00622         int expsize;            /* character count for expstr */
00623         int lead;               /* sig figs before decimal or group sep */
00624         int ndig;               /* actual number of digits returned by dtoa */
00625         char expstr[MAXEXPDIG+2];       /* buffer for exponent string: e+ZZZ */
00626         char *dtoaresult;       /* buffer allocated by dtoa */
00627         int nseps;              /* number of group separators with ' */
00628         int nrepeats;           /* number of repeats of the last group */
00629 #endif
00630         u_long  ulval;          /* integer arguments %[diouxX] */
00631         uintmax_t ujval;        /* %j, %ll, %q, %t, %z integers */
00632         int base;               /* base for [diouxX] conversion */
00633         int dprec;              /* a copy of prec if [diouxX], 0 otherwise */
00634         int realsz;             /* field size expanded by dprec, sign, etc */
00635         int size;               /* size of converted field or string */
00636         int prsize;             /* max size of printed field */
00637         const char *xdigs;      /* digits for %[xX] conversion */
00638 #ifndef __FORMATTER__
00639 #define NIOV 8
00640         struct __suio uio;      /* output information: summary */
00641         struct __siov iov[NIOV];/* ... and individual io vectors */
00642 #endif // __FORMATTER__
00643         char buf[BUF];          /* buffer with space for digits of uintmax_t */
00644         char ox[2];             /* space for 0x; ox[1] is either x, X, or \0 */
00645         union arg *argtable;    /* args, built due to positional arg */
00646         union arg statargtable [STATIC_ARG_TBL_SIZE];
00647         int nextarg;            /* 1-based argument index */
00648         va_list orgap;          /* original argument pointer */
00649         char *convbuf;          /* wide to multibyte conversion result */
00650 #ifdef __FORMATTER__
00651         size_t sz;              /* local size variable for PRINT() macro */
00652         void* fmtobj;           /* pointer to object of type Formatter */
00653 #endif
00654 
00655         /*
00656          * Choose PADSIZE to trade efficiency vs. size.  If larger printf
00657          * fields occur frequently, increase PADSIZE and make the initialisers
00658          * below longer.
00659          */
00660 #define PADSIZE 16              /* pad chunk size */
00661         static char blanks[PADSIZE] =
00662          {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
00663         static char zeroes[PADSIZE] =
00664          {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
00665 
00666         static const char xdigs_lower[16] = "0123456789abcdef";
00667         static const char xdigs_upper[16] = "0123456789ABCDEF";
00668 
00669         /*
00670          * BEWARE, these `goto error' on error, and PAD uses `n'.
00671          */
00672 #ifndef __FORMATTER__
00673 #define PRINT(ptr, len) { \
00674         iovp->iov_base = (ptr); \
00675         iovp->iov_len = (len); \
00676         uio.uio_resid += (len); \
00677         iovp++; \
00678         if (++uio.uio_iovcnt >= NIOV) { \
00679                 if (__sprint(fp, &uio)) \
00680                         goto error; \
00681                 iovp = iov; \
00682         } \
00683 }
00684 #else
00685 #define PRINT(ptr, len) {                               \
00686         sz = (((size_t)len) <= strsz) ? len : strsz;    \
00687         memcpy(str, ptr, sz);                           \
00688         str += sz;                                      \
00689         strsz -= sz;                                    \
00690 }
00691 #endif
00692                                           
00693 #define PAD(howmany, with) { \
00694         if ((n = (howmany)) > 0) { \
00695                 while (n > PADSIZE) { \
00696                         PRINT(with, PADSIZE); \
00697                         n -= PADSIZE; \
00698                 } \
00699                 PRINT(with, n); \
00700         } \
00701 }
00702 #define PRINTANDPAD(p, ep, len, with) do {      \
00703         n2 = (ep) - (p);                        \
00704         if (n2 > (len))                         \
00705                 n2 = (len);                     \
00706         if (n2 > 0)                             \
00707                 PRINT((p), n2);                 \
00708         PAD((len) - (n2 > 0 ? n2 : 0), (with)); \
00709 } while(0)
00710 #ifndef __FORMATTER__
00711 #define FLUSH() { \
00712         if (uio.uio_resid && __sprint(fp, &uio)) \
00713                 goto error; \
00714         uio.uio_iovcnt = 0; \
00715         iovp = iov; \
00716 }
00717 #else
00718 #define FLUSH() {}
00719 #endif
00720         /*
00721          * Get the argument indexed by nextarg.   If the argument table is
00722          * built, use it to get the argument.  If its not, get the next
00723          * argument (and arguments must be gotten sequentially).
00724          */
00725 #define GETARG(type) \
00726         ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
00727             (nextarg++, va_arg(ap, type)))
00728 
00729         /*
00730          * To extend shorts properly, we need both signed and unsigned
00731          * argument extraction methods.
00732          */
00733 #define SARG() \
00734         (flags&LONGINT ? GETARG(long) : \
00735             flags&SHORTINT ? (long)(short)GETARG(int) : \
00736             flags&CHARINT ? (long)(signed char)GETARG(int) : \
00737             (long)GETARG(int))
00738 #define UARG() \
00739         (flags&LONGINT ? GETARG(u_long) : \
00740             flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
00741             flags&CHARINT ? (u_long)(u_char)GETARG(int) : \
00742             (u_long)GETARG(u_int))
00743 #define INTMAX_SIZE     (INTMAXT|SIZET|PTRDIFFT|LLONGINT)
00744 #define SJARG() \
00745         (flags&INTMAXT ? GETARG(intmax_t) : \
00746             flags&SIZET ? (intmax_t)GETARG(size_t) : \
00747             flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \
00748             (intmax_t)GETARG(long long))
00749 #define UJARG() \
00750         (flags&INTMAXT ? GETARG(uintmax_t) : \
00751             flags&SIZET ? (uintmax_t)GETARG(size_t) : \
00752             flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \
00753             (uintmax_t)GETARG(unsigned long long))
00754 
00755         /*
00756          * Get * arguments, including the form *nn$.  Preserve the nextarg
00757          * that the argument can be gotten once the type is determined.
00758          */
00759 #define GETASTER(val) \
00760         n2 = 0; \
00761         cp = fmt; \
00762         while (is_digit(*cp)) { \
00763                 n2 = 10 * n2 + to_digit(*cp); \
00764                 cp++; \
00765         } \
00766         if (*cp == '$') { \
00767                 int hold = nextarg; \
00768                 if (argtable == NULL) { \
00769                         argtable = statargtable; \
00770                         __find_arguments (fmt0, orgap, &argtable); \
00771                 } \
00772                 nextarg = n2; \
00773                 val = GETARG (int); \
00774                 nextarg = hold; \
00775                 fmt = ++cp; \
00776         } else { \
00777                 val = GETARG (int); \
00778         }
00779 
00780 
00781         thousands_sep = '\0';
00782         grouping = NULL;
00783         convbuf = NULL;
00784 #ifndef NO_FLOATING_POINT
00785         dtoaresult = NULL;
00786         decimal_point = localeconv()->decimal_point;
00787 #endif
00788 #ifndef __FORMATTER__
00789         /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
00790         if (prepwrite(fp) != 0)
00791                 return (EOF);
00792 
00793         /* optimise fprintf(stderr) (and other unbuffered Unix files) */
00794         if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
00795             fp->_file >= 0)
00796                 return (__sbprintf(fp, fmt0, ap));
00797 #endif // __FORMATTER__
00798 
00799         fmt = (char *)fmt0;
00800         argtable = NULL;
00801         nextarg = 1;
00802         va_copy(orgap, ap);
00803 #ifndef __FORMATTER__
00804         uio.uio_iov = iovp = iov;
00805         uio.uio_resid = 0;
00806         uio.uio_iovcnt = 0;
00807 #endif
00808         ret = 0;
00809 
00810         if (strsz == 0) {
00811                 return -1;
00812         }
00813 
00814         /*
00815          * demmer: this leaves space for the trailing null -- we need
00816          * to be careful in the Formatter call below to adjust
00817          * accordingly.
00818         */
00819         strsz -= 1;
00820 
00821         /*
00822          * Scan the format for conversions (`%' character).
00823          */
00824         for (;;) {
00825                 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
00826                         /* void */;
00827                 if ((n = fmt - cp) != 0) {
00828                         if ((unsigned)ret + n > INT_MAX) {
00829                                 ret = EOF;
00830                                 goto error;
00831                         }
00832                         PRINT(cp, n);
00833                         ret += n;
00834                 }
00835                 if (ch == '\0')
00836                         goto done;
00837                 fmt++;          /* skip over '%' */
00838 
00839                 flags = 0;
00840                 dprec = 0;
00841                 width = 0;
00842                 prec = -1;
00843                 sign = '\0';
00844                 ox[1] = '\0';
00845 
00846 rflag:          ch = *fmt++;
00847 reswitch:       switch (ch) {
00848                 case ' ':
00849                         /*-
00850                          * ``If the space and + flags both appear, the space
00851                          * flag will be ignored.''
00852                          *      -- ANSI X3J11
00853                          */
00854                         if (!sign)
00855                                 sign = ' ';
00856                         goto rflag;
00857                 case '#':
00858                         flags |= ALT;
00859                         goto rflag;
00860                 case '*':
00861                         /*-
00862                          * ``A negative field width argument is taken as a
00863                          * - flag followed by a positive field width.''
00864                          *      -- ANSI X3J11
00865                          * They don't exclude field widths read from args.
00866                          */
00867                         GETASTER (width);
00868                         if (width >= 0)
00869                                 goto rflag;
00870                         width = -width;
00871                         /* FALLTHROUGH */
00872                 case '-':
00873                         flags |= LADJUST;
00874                         goto rflag;
00875                 case '+':
00876                         sign = '+';
00877                         goto rflag;
00878                 case '\'':
00879                         flags |= GROUPING;
00880                         thousands_sep = *(localeconv()->thousands_sep);
00881                         grouping = localeconv()->grouping;
00882                         goto rflag;
00883                 case '.':
00884                         if ((ch = *fmt++) == '*') {
00885                                 GETASTER (prec);
00886                                 goto rflag;
00887                         }
00888                         prec = 0;
00889                         while (is_digit(ch)) {
00890                                 prec = 10 * prec + to_digit(ch);
00891                                 ch = *fmt++;
00892                         }
00893                         goto reswitch;
00894                 case '0':
00895                         /*-
00896                          * ``Note that 0 is taken as a flag, not as the
00897                          * beginning of a field width.''
00898                          *      -- ANSI X3J11
00899                          */
00900                         flags |= ZEROPAD;
00901                         goto rflag;
00902                 case '1': case '2': case '3': case '4':
00903                 case '5': case '6': case '7': case '8': case '9':
00904                         n = 0;
00905                         do {
00906                                 n = 10 * n + to_digit(ch);
00907                                 ch = *fmt++;
00908                         } while (is_digit(ch));
00909                         if (ch == '$') {
00910                                 nextarg = n;
00911                                 if (argtable == NULL) {
00912                                         argtable = statargtable;
00913                                         __find_arguments (fmt0, orgap,
00914                                             &argtable);
00915                                 }
00916                                 goto rflag;
00917                         }
00918                         width = n;
00919                         goto reswitch;
00920 #ifndef NO_FLOATING_POINT
00921                 case 'L':
00922                         flags |= LONGDBL;
00923                         goto rflag;
00924 #endif
00925                 case 'h':
00926                         if (flags & SHORTINT) {
00927                                 flags &= ~SHORTINT;
00928                                 flags |= CHARINT;
00929                         } else
00930                                 flags |= SHORTINT;
00931                         goto rflag;
00932                 case 'j':
00933                         flags |= INTMAXT;
00934                         goto rflag;
00935                 case 'l':
00936                         if (flags & LONGINT) {
00937                                 flags &= ~LONGINT;
00938                                 flags |= LLONGINT;
00939                         } else
00940                                 flags |= LONGINT;
00941                         goto rflag;
00942                 case 'q':
00943                         flags |= LLONGINT;      /* not necessarily */
00944                         goto rflag;
00945                 case 't':
00946                         flags |= PTRDIFFT;
00947                         goto rflag;
00948                 case 'z':
00949                         flags |= SIZET;
00950                         goto rflag;
00951                 case 'C':
00952                         flags |= LONGINT;
00953                         /*FALLTHROUGH*/
00954                 case 'c':
00955                         if (flags & LONGINT) {
00956                                 static const mbstate_t initial;
00957                                 mbstate_t mbs;
00958                                 size_t mbseqlen;
00959 
00960                                 mbs = initial;
00961                                 mbseqlen = wcrtomb(cp = buf,
00962                                     (wchar_t)GETARG(wint_t), &mbs);
00963                                 if (mbseqlen == (size_t)-1) {
00964 #ifndef __FORMATTER__
00965                                         fp->_flags |= __SERR;
00966 #endif
00967                                         goto error;
00968                                 }
00969                                 size = (int)mbseqlen;
00970                         } else {
00971                                 *(cp = buf) = GETARG(int);
00972                                 size = 1;
00973                         }
00974                         sign = '\0';
00975                         break;
00976                 case 'D':
00977                         flags |= LONGINT;
00978                         /*FALLTHROUGH*/
00979                 case 'd':
00980                 case 'i':
00981                         if (flags & INTMAX_SIZE) {
00982                                 ujval = SJARG();
00983                                 if ((intmax_t)ujval < 0) {
00984                                         ujval = -ujval;
00985                                         sign = '-';
00986                                 }
00987                         } else {
00988                                 ulval = SARG();
00989                                 if ((long)ulval < 0) {
00990                                         ulval = -ulval;
00991                                         sign = '-';
00992                                 }
00993                         }
00994                         base = 10;
00995                         goto number;
00996 #ifndef NO_FLOATING_POINT
00997                 case 'a':
00998                 case 'A':
00999                         if (ch == 'a') {
01000                                 ox[1] = 'x';
01001                                 xdigs = xdigs_lower;
01002                                 expchar = 'p';
01003                         } else {
01004                                 ox[1] = 'X';
01005                                 xdigs = xdigs_upper;
01006                                 expchar = 'P';
01007                         }
01008                         if (prec >= 0)
01009                                 prec++;
01010                         if (dtoaresult != NULL)
01011                                 freedtoa(dtoaresult);
01012                         if (flags & LONGDBL) {
01013                                 fparg.ldbl = GETARG(long double);
01014                                 dtoaresult = cp =
01015                                     __hldtoa(fparg.ldbl, xdigs, prec,
01016                                     &expt, &signflag, &dtoaend);
01017                         } else {
01018                                 fparg.dbl = GETARG(double);
01019                                 dtoaresult = cp =
01020                                     __hdtoa(fparg.dbl, xdigs, prec,
01021                                     &expt, &signflag, &dtoaend);
01022                         }
01023                         if (prec < 0)
01024                                 prec = dtoaend - cp;
01025                         if (expt == INT_MAX)
01026                                 ox[1] = '\0';
01027                         goto fp_common;
01028                 case 'e':
01029                 case 'E':
01030                         expchar = ch;
01031                         if (prec < 0)   /* account for digit before decpt */
01032                                 prec = DEFPREC + 1;
01033                         else
01034                                 prec++;
01035                         goto fp_begin;
01036                 case 'f':
01037                 case 'F':
01038                         expchar = '\0';
01039                         goto fp_begin;
01040                 case 'g':
01041                 case 'G':
01042                         expchar = ch - ('g' - 'e');
01043                         if (prec == 0)
01044                                 prec = 1;
01045 fp_begin:
01046                         if (prec < 0)
01047                                 prec = DEFPREC;
01048                         if (dtoaresult != NULL)
01049                                 freedtoa(dtoaresult);
01050                         if (flags & LONGDBL) {
01051                                 fparg.ldbl = GETARG(long double);
01052                                 dtoaresult = cp =
01053                                     __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec,
01054                                     &expt, &signflag, &dtoaend);
01055                         } else {
01056                                 fparg.dbl = GETARG(double);
01057                                 dtoaresult = cp =
01058                                     dtoa(fparg.dbl, expchar ? 2 : 3, prec,
01059                                     &expt, &signflag, &dtoaend);
01060                                 if (expt == 9999)
01061                                         expt = INT_MAX;
01062                         }
01063 fp_common:
01064                         if (signflag)
01065                                 sign = '-';
01066                         if (expt == INT_MAX) {  /* inf or nan */
01067                                 if (*cp == 'N') {
01068                                         cp = (ch >= 'a') ? "nan" : "NAN";
01069                                         sign = '\0';
01070                                 } else
01071                                         cp = (ch >= 'a') ? "inf" : "INF";
01072                                 size = 3;
01073                                 break;
01074                         }
01075                         flags |= FPT;
01076                         ndig = dtoaend - cp;
01077                         if (ch == 'g' || ch == 'G') {
01078                                 if (expt > -4 && expt <= prec) {
01079                                         /* Make %[gG] smell like %[fF] */
01080                                         expchar = '\0';
01081                                         if (flags & ALT)
01082                                                 prec -= expt;
01083                                         else
01084                                                 prec = ndig - expt;
01085                                         if (prec < 0)
01086                                                 prec = 0;
01087                                 } else {
01088                                         /*
01089                                          * Make %[gG] smell like %[eE], but
01090                                          * trim trailing zeroes if no # flag.
01091                                          */
01092                                         if (!(flags & ALT))
01093                                                 prec = ndig;
01094                                 }
01095                         }
01096                         if (expchar) {
01097                                 expsize = exponent(expstr, expt - 1, expchar);
01098                                 size = expsize + prec;
01099                                 if (prec > 1 || flags & ALT)
01100                                         ++size;
01101                         } else {
01102                                 /* space for digits before decimal point */
01103                                 if (expt > 0)
01104                                         size = expt;
01105                                 else    /* "0" */
01106                                         size = 1;
01107                                 /* space for decimal pt and following digits */
01108                                 if (prec || flags & ALT)
01109                                         size += prec + 1;
01110                                 if (grouping && expt > 0) {
01111                                         /* space for thousands' grouping */
01112                                         nseps = nrepeats = 0;
01113                                         lead = expt;
01114                                         while (*grouping != CHAR_MAX) {
01115                                                 if (lead <= *grouping)
01116                                                         break;
01117                                                 lead -= *grouping;
01118                                                 if (*(grouping+1)) {
01119                                                         nseps++;
01120                                                         grouping++;
01121                                                 } else
01122                                                         nrepeats++;
01123                                         }
01124                                         size += nseps + nrepeats;
01125                                 } else
01126                                         lead = expt;
01127                         }
01128                         break;
01129 #endif /* !NO_FLOATING_POINT */
01130                 case 'n':
01131                         /*
01132                          * Assignment-like behavior is specified if the
01133                          * value overflows or is otherwise unrepresentable.
01134                          * C99 says to use `signed char' for %hhn conversions.
01135                          */
01136                         if (flags & LLONGINT)
01137                                 *GETARG(long long *) = ret;
01138                         else if (flags & SIZET)
01139                                 *GETARG(ssize_t *) = (ssize_t)ret;
01140                         else if (flags & PTRDIFFT)
01141                                 *GETARG(ptrdiff_t *) = ret;
01142                         else if (flags & INTMAXT)
01143                                 *GETARG(intmax_t *) = ret;
01144                         else if (flags & LONGINT)
01145                                 *GETARG(long *) = ret;
01146                         else if (flags & SHORTINT)
01147                                 *GETARG(short *) = ret;
01148                         else if (flags & CHARINT)
01149                                 *GETARG(signed char *) = ret;
01150                         else
01151                                 *GETARG(int *) = ret;
01152                         continue;       /* no output */
01153                 case 'O':
01154                         flags |= LONGINT;
01155                         /*FALLTHROUGH*/
01156                 case 'o':
01157                         if (flags & INTMAX_SIZE)
01158                                 ujval = UJARG();
01159                         else
01160                                 ulval = UARG();
01161                         base = 8;
01162                         goto nosign;
01163                 case 'p':
01164                         /*-
01165                          * If the format string is *%p, then treat
01166                          * the pointer as one of type Formatter* and
01167                          * call formatter_format(fmtobj).
01168                          *      -- NOT ANSI
01169                          */
01170 
01171                     // XXX/bowei - FIXME: this could cause a buffer
01172                     // underflow if someone does vsnprintf("%p").
01173                         if (ret > 0 && str[-1] == '*') {
01174                                 str--;
01175                                 strsz++;
01176                                 ret--;
01177 
01178                                 fmtobj = GETARG(void*);
01179                                 sz = formatter_format(fmtobj, str, strsz);
01180                                 
01181                                 if (sz < strsz) {
01182                                         str += sz;
01183                                         strsz -= sz;
01184                                 } else {
01185                                         str += strsz;
01186                                         strsz = 0;
01187                                 }
01188                                 ret += sz;
01189                                 continue;
01190                         }
01191                         /*-
01192                          * ``The argument shall be a pointer to void.  The
01193                          * value of the pointer is converted to a sequence
01194                          * of printable characters, in an implementation-
01195                          * defined manner.''
01196                          *      -- ANSI X3J11
01197                          */
01198                         ujval = (uintmax_t)(uintptr_t)GETARG(void *);
01199                         base = 16;
01200                         xdigs = xdigs_lower;
01201                         flags = flags | INTMAXT;
01202                         ox[1] = 'x';
01203                         goto nosign;
01204                 case 'S':
01205                         flags |= LONGINT;
01206                         /*FALLTHROUGH*/
01207                 case 's':
01208                         if (flags & LONGINT) {
01209                                 wchar_t *wcp;
01210 
01211                                 if (convbuf != NULL)
01212                                         free(convbuf);
01213                                 if ((wcp = GETARG(wchar_t *)) == NULL)
01214                                         cp = "(null)";
01215                                 else {
01216                                         convbuf = __wcsconv(wcp, prec);
01217                                         if (convbuf == NULL) {
01218 #ifndef __FORMATTER__
01219                                                 fp->_flags |= __SERR;
01220 #endif
01221                                                 goto error;
01222                                         }
01223                                         cp = convbuf;
01224                                 }
01225                         } else if ((cp = GETARG(char *)) == NULL)
01226                                 cp = "(null)";
01227                         if (prec >= 0) {
01228                                 /*
01229                                  * can't use strlen; can only look for the
01230                                  * NUL in the first `prec' characters, and
01231                                  * strlen() will go further.
01232                                  */
01233                                 char *p = memchr(cp, 0, (size_t)prec);
01234 
01235                                 if (p != NULL) {
01236                                         size = p - cp;
01237                                         if (size > prec)
01238                                                 size = prec;
01239                                 } else
01240                                         size = prec;
01241                         } else
01242                                 size = strlen(cp);
01243                         sign = '\0';
01244                         break;
01245                 case 'U':
01246                         flags |= LONGINT;
01247                         /*FALLTHROUGH*/
01248                 case 'u':
01249                         if (flags & INTMAX_SIZE)
01250                                 ujval = UJARG();
01251                         else
01252                                 ulval = UARG();
01253                         base = 10;
01254                         goto nosign;
01255                 case 'X':
01256                         xdigs = xdigs_upper;
01257                         goto hex;
01258                 case 'x':
01259                         xdigs = xdigs_lower;
01260 hex:
01261                         if (flags & INTMAX_SIZE)
01262                                 ujval = UJARG();
01263                         else
01264                                 ulval = UARG();
01265                         base = 16;
01266                         /* leading 0x/X only if non-zero */
01267                         if (flags & ALT &&
01268                             (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
01269                                 ox[1] = ch;
01270 
01271                         flags &= ~GROUPING;
01272                         /* unsigned conversions */
01273 nosign:                 sign = '\0';
01274                         /*-
01275                          * ``... diouXx conversions ... if a precision is
01276                          * specified, the 0 flag will be ignored.''
01277                          *      -- ANSI X3J11
01278                          */
01279 number:                 if ((dprec = prec) >= 0)
01280                                 flags &= ~ZEROPAD;
01281 
01282                         /*-
01283                          * ``The result of converting a zero value with an
01284                          * explicit precision of zero is no characters.''
01285                          *      -- ANSI X3J11
01286                          *
01287                          * ``The C Standard is clear enough as is.  The call
01288                          * printf("%#.0o", 0) should print 0.''
01289                          *      -- Defect Report #151
01290                          */
01291                         cp = buf + BUF;
01292                         if (flags & INTMAX_SIZE) {
01293                                 if (ujval != 0 || prec != 0 ||
01294                                     (flags & ALT && base == 8))
01295                                         cp = __ujtoa(ujval, cp, base,
01296                                             flags & ALT, xdigs,
01297                                             flags & GROUPING, thousands_sep,
01298                                             grouping);
01299                         } else {
01300                                 if (ulval != 0 || prec != 0 ||
01301                                     (flags & ALT && base == 8))
01302                                         cp = __ultoa(ulval, cp, base,
01303                                             flags & ALT, xdigs,
01304                                             flags & GROUPING, thousands_sep,
01305                                             grouping);
01306                         }
01307                         size = buf + BUF - cp;
01308                         if (size > BUF) /* should never happen */
01309                                 abort();
01310                         break;
01311                 default:        /* "%?" prints ?, unless ? is NUL */
01312                         if (ch == '\0')
01313                                 goto done;
01314                         /* pretend it was %c with argument ch */
01315                         cp = buf;
01316                         *cp = ch;
01317                         size = 1;
01318                         sign = '\0';
01319                         break;
01320                 }
01321 
01322                 /*
01323                  * All reasonable formats wind up here.  At this point, `cp'
01324                  * points to a string which (if not flags&LADJUST) should be
01325                  * padded out to `width' places.  If flags&ZEROPAD, it should
01326                  * first be prefixed by any sign or other prefix; otherwise,
01327                  * it should be blank padded before the prefix is emitted.
01328                  * After any left-hand padding and prefixing, emit zeroes
01329                  * required by a decimal [diouxX] precision, then print the
01330                  * string proper, then emit zeroes required by any leftover
01331                  * floating precision; finally, if LADJUST, pad with blanks.
01332                  *
01333                  * Compute actual size, so we know how much to pad.
01334                  * size excludes decimal prec; realsz includes it.
01335                  */
01336                 realsz = dprec > size ? dprec : size;
01337                 if (sign)
01338                         realsz++;
01339                 if (ox[1])
01340                         realsz += 2;
01341 
01342                 prsize = width > realsz ? width : realsz;
01343                 if ((unsigned)ret + prsize > INT_MAX) {
01344                         ret = EOF;
01345                         goto error;
01346                 }
01347 
01348                 /* right-adjusting blank padding */
01349                 if ((flags & (LADJUST|ZEROPAD)) == 0)
01350                         PAD(width - realsz, blanks);
01351 
01352                 /* prefix */
01353                 if (sign)
01354                         PRINT(&sign, 1);
01355 
01356                 if (ox[1]) {    /* ox[1] is either x, X, or \0 */
01357                         ox[0] = '0';
01358                         PRINT(ox, 2);
01359                 }
01360 
01361                 /* right-adjusting zero padding */
01362                 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
01363                         PAD(width - realsz, zeroes);
01364 
01365                 /* leading zeroes from decimal precision */
01366                 PAD(dprec - size, zeroes);
01367 
01368                 /* the string or number proper */
01369 #ifndef NO_FLOATING_POINT
01370                 if ((flags & FPT) == 0) {
01371                         PRINT(cp, size);
01372                 } else {        /* glue together f_p fragments */
01373                         if (!expchar) { /* %[fF] or sufficiently short %[gG] */
01374                                 if (expt <= 0) {
01375                                         PRINT(zeroes, 1);
01376                                         if (prec || flags & ALT)
01377                                                 PRINT(decimal_point, 1);
01378                                         PAD(-expt, zeroes);
01379                                         /* already handled initial 0's */
01380                                         prec += expt;
01381                                 } else {
01382                                         PRINTANDPAD(cp, dtoaend, lead, zeroes);
01383                                         cp += lead;
01384                                         if (grouping) {
01385                                                 while (nseps>0 || nrepeats>0) {
01386                                                         if (nrepeats > 0)
01387                                                                 nrepeats--;
01388                                                         else {
01389                                                                 grouping--;
01390                                                                 nseps--;
01391                                                         }
01392                                                         PRINT(&thousands_sep,
01393                                                             1);
01394                                                         PRINTANDPAD(cp,dtoaend,
01395                                                             *grouping, zeroes);
01396                                                         cp += *grouping;
01397                                                 }
01398                                                 if (cp > dtoaend)
01399                                                         cp = dtoaend;
01400                                         }
01401                                         if (prec || flags & ALT)
01402                                                 PRINT(decimal_point,1);
01403                                 }
01404                                 PRINTANDPAD(cp, dtoaend, prec, zeroes);
01405                         } else {        /* %[eE] or sufficiently long %[gG] */
01406                                 if (prec > 1 || flags & ALT) {
01407                                         buf[0] = *cp++;
01408                                         buf[1] = *decimal_point;
01409                                         PRINT(buf, 2);
01410                                         PRINT(cp, ndig-1);
01411                                         PAD(prec - ndig, zeroes);
01412                                 } else  /* XeYYY */
01413                                         PRINT(cp, 1);
01414                                 PRINT(expstr, expsize);
01415                         }
01416                 }
01417 #else
01418                 PRINT(cp, size);
01419 #endif
01420                 /* left-adjusting padding (always blank) */
01421                 if (flags & LADJUST)
01422                         PAD(width - realsz, blanks);
01423 
01424                 /* finally, adjust ret */
01425                 ret += prsize;
01426 
01427                 FLUSH();        /* copy out the I/O vectors */
01428         }
01429 done:
01430         FLUSH();
01431 error:
01432         va_end(orgap);
01433 #ifndef NO_FLOATING_POINT
01434         if (dtoaresult != NULL)
01435                 freedtoa(dtoaresult);
01436 #endif
01437         if (convbuf != NULL)
01438                 free(convbuf);
01439 #ifndef __FORMATTER__
01440         if (__sferror(fp))
01441                 ret = EOF;
01442 #endif
01443         if ((argtable != NULL) && (argtable != statargtable))
01444                 free (argtable);
01445 
01446 #ifdef __FORMATTER__
01447         // demmer: we make sure to null terminate the string
01448         *str = '\0';
01449 #endif
01450         
01451         return (ret);
01452         /* NOTREACHED */
01453 }
01454 
01455 /*
01456  * demmer: add an implementation of snprintf as well.
01457  */
01458 int
01459 snprintf(char *str, size_t strsz, const char *fmt, ...)
01460 {
01461         va_list ap;
01462         int ret;
01463 
01464         va_start(ap, fmt);
01465         ret = vsnprintf(str, strsz, fmt, ap);
01466         va_end(ap);
01467 
01468         return ret;
01469 }
01470 
01471 /*
01472  * Find all arguments when a positional parameter is encountered.  Returns a
01473  * table, indexed by argument number, of pointers to each arguments.  The
01474  * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
01475  * It will be replaces with a malloc-ed one if it overflows.
01476  */ 
01477 static void
01478 __find_arguments (const char *fmt0, va_list ap, union arg **argtable)
01479 {
01480         char *fmt;              /* format string */
01481         int ch;                 /* character from fmt */
01482         int n, n2;              /* handy integer (short term usage) */
01483         char *cp;               /* handy char pointer (short term usage) */
01484         int flags;              /* flags as above */
01485         int width;              /* width from format (%8d), or 0 */
01486         enum typeid *typetable; /* table of types */
01487         enum typeid stattypetable [STATIC_ARG_TBL_SIZE];
01488         int tablesize;          /* current size of type table */
01489         int tablemax;           /* largest used index in table */
01490         int nextarg;            /* 1-based argument index */
01491 
01492         /*
01493          * Add an argument type to the table, expanding if necessary.
01494          */
01495 #define ADDTYPE(type) \
01496         ((nextarg >= tablesize) ? \
01497                 __grow_type_table(nextarg, &typetable, &tablesize) : (void)0, \
01498         (nextarg > tablemax) ? tablemax = nextarg : 0, \
01499         typetable[nextarg++] = type)
01500 
01501 #define ADDSARG() \
01502         ((flags&INTMAXT) ? ADDTYPE(T_INTMAXT) : \
01503                 ((flags&SIZET) ? ADDTYPE(T_SIZET) : \
01504                 ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \
01505                 ((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \
01506                 ((flags&LONGINT) ? ADDTYPE(T_LONG) : ADDTYPE(T_INT))))))
01507 
01508 #define ADDUARG() \
01509         ((flags&INTMAXT) ? ADDTYPE(T_UINTMAXT) : \
01510                 ((flags&SIZET) ? ADDTYPE(T_SIZET) : \
01511                 ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \
01512                 ((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \
01513                 ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : ADDTYPE(T_U_INT))))))
01514 
01515         /*
01516          * Add * arguments to the type array.
01517          */
01518 #define ADDASTER() \
01519         n2 = 0; \
01520         cp = fmt; \
01521         while (is_digit(*cp)) { \
01522                 n2 = 10 * n2 + to_digit(*cp); \
01523                 cp++; \
01524         } \
01525         if (*cp == '$') { \
01526                 int hold = nextarg; \
01527                 nextarg = n2; \
01528                 ADDTYPE (T_INT); \
01529                 nextarg = hold; \
01530                 fmt = ++cp; \
01531         } else { \
01532                 ADDTYPE (T_INT); \
01533         }
01534         fmt = (char *)fmt0;
01535         typetable = stattypetable;
01536         tablesize = STATIC_ARG_TBL_SIZE;
01537         tablemax = 0; 
01538         nextarg = 1;
01539         for (n = 0; n < STATIC_ARG_TBL_SIZE; n++)
01540                 typetable[n] = T_UNUSED;
01541 
01542         /*
01543          * Scan the format for conversions (`%' character).
01544          */
01545         for (;;) {
01546                 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
01547                         /* void */;
01548                 if (ch == '\0')
01549                         goto done;
01550                 fmt++;          /* skip over '%' */
01551 
01552                 flags = 0;
01553                 width = 0;
01554 
01555 rflag:          ch = *fmt++;
01556 reswitch:       switch (ch) {
01557                 case ' ':
01558                 case '#':
01559                         goto rflag;
01560                 case '*':
01561                         ADDASTER ();
01562                         goto rflag;
01563                 case '-':
01564                 case '+':
01565                 case '\'':
01566                         goto rflag;
01567                 case '.':
01568                         if ((ch = *fmt++) == '*') {
01569                                 ADDASTER ();
01570                                 goto rflag;
01571                         }
01572                         while (is_digit(ch)) {
01573                                 ch = *fmt++;
01574                         }
01575                         goto reswitch;
01576                 case '0':
01577                         goto rflag;
01578                 case '1': case '2': case '3': case '4':
01579                 case '5': case '6': case '7': case '8': case '9':
01580                         n = 0;
01581                         do {
01582                                 n = 10 * n + to_digit(ch);
01583                                 ch = *fmt++;
01584                         } while (is_digit(ch));
01585                         if (ch == '$') {
01586                                 nextarg = n;
01587                                 goto rflag;
01588                         }
01589                         width = n;
01590                         goto reswitch;
01591 #ifndef NO_FLOATING_POINT
01592                 case 'L':
01593                         flags |= LONGDBL;
01594                         goto rflag;
01595 #endif
01596                 case 'h':
01597                         if (flags & SHORTINT) {
01598                                 flags &= ~SHORTINT;
01599                                 flags |= CHARINT;
01600                         } else
01601                                 flags |= SHORTINT;
01602                         goto rflag;
01603                 case 'j':
01604                         flags |= INTMAXT;
01605                         goto rflag;
01606                 case 'l':
01607                         if (flags & LONGINT) {
01608                                 flags &= ~LONGINT;
01609                                 flags |= LLONGINT;
01610                         } else
01611                                 flags |= LONGINT;
01612                         goto rflag;
01613                 case 'q':
01614                         flags |= LLONGINT;      /* not necessarily */
01615                         goto rflag;
01616                 case 't':
01617                         flags |= PTRDIFFT;
01618                         goto rflag;
01619                 case 'z':
01620                         flags |= SIZET;
01621                         goto rflag;
01622                 case 'C':
01623                         flags |= LONGINT;
01624                         /*FALLTHROUGH*/
01625                 case 'c':
01626                         if (flags & LONGINT)
01627                                 ADDTYPE(T_WINT);
01628                         else
01629                                 ADDTYPE(T_INT);
01630                         break;
01631                 case 'D':
01632                         flags |= LONGINT;
01633                         /*FALLTHROUGH*/
01634                 case 'd':
01635                 case 'i':
01636                         ADDSARG();
01637                         break;
01638 #ifndef NO_FLOATING_POINT
01639                 case 'a':
01640                 case 'A':
01641                 case 'e':
01642                 case 'E':
01643                 case 'f':
01644                 case 'g':
01645                 case 'G':
01646                         if (flags & LONGDBL)
01647                                 ADDTYPE(T_LONG_DOUBLE);
01648                         else
01649                                 ADDTYPE(T_DOUBLE);
01650                         break;
01651 #endif /* !NO_FLOATING_POINT */
01652                 case 'n':
01653                         if (flags & INTMAXT)
01654                                 ADDTYPE(TP_INTMAXT);
01655                         else if (flags & PTRDIFFT)
01656                                 ADDTYPE(TP_PTRDIFFT);
01657                         else if (flags & SIZET)
01658                                 ADDTYPE(TP_SIZET);
01659                         else if (flags & LLONGINT)
01660                                 ADDTYPE(TP_LLONG);
01661                         else if (flags & LONGINT)
01662                                 ADDTYPE(TP_LONG);
01663                         else if (flags & SHORTINT)
01664                                 ADDTYPE(TP_SHORT);
01665                         else if (flags & CHARINT)
01666                                 ADDTYPE(TP_SCHAR);
01667                         else
01668                                 ADDTYPE(TP_INT);
01669                         continue;       /* no output */
01670                 case 'O':
01671                         flags |= LONGINT;
01672                         /*FALLTHROUGH*/
01673                 case 'o':
01674                         ADDUARG();
01675                         break;
01676                 case 'p':
01677                         ADDTYPE(TP_VOID);
01678                         break;
01679                 case 'S':
01680                         flags |= LONGINT;
01681                         /*FALLTHROUGH*/
01682                 case 's':
01683                         if (flags & LONGINT)
01684                                 ADDTYPE(TP_WCHAR);
01685                         else
01686                                 ADDTYPE(TP_CHAR);
01687                         break;
01688                 case 'U':
01689                         flags |= LONGINT;
01690                         /*FALLTHROUGH*/
01691                 case 'u':
01692                 case 'X':
01693                 case 'x':
01694                         ADDUARG();
01695                         break;
01696                 default:        /* "%?" prints ?, unless ? is NUL */
01697                         if (ch == '\0')
01698                                 goto done;
01699                         break;
01700                 }
01701         }
01702 done:
01703         /*
01704          * Build the argument table.
01705          */
01706         if (tablemax >= STATIC_ARG_TBL_SIZE) {
01707                 *argtable = (union arg *)
01708                     malloc (sizeof (union arg) * (tablemax + 1));
01709         }
01710 
01711         (*argtable) [0].intarg = 0;
01712         for (n = 1; n <= tablemax; n++) {
01713                 switch (typetable [n]) {
01714                     case T_UNUSED: /* whoops! */
01715                         (*argtable) [n].intarg = va_arg (ap, int);
01716                         break;
01717                     case TP_SCHAR:
01718                         (*argtable) [n].pschararg = va_arg (ap, signed char *);
01719                         break;
01720                     case TP_SHORT:
01721                         (*argtable) [n].pshortarg = va_arg (ap, short *);
01722                         break;
01723                     case T_INT:
01724                         (*argtable) [n].intarg = va_arg (ap, int);
01725                         break;
01726                     case T_U_INT:
01727                         (*argtable) [n].uintarg = va_arg (ap, unsigned int);
01728                         break;
01729                     case TP_INT:
01730                         (*argtable) [n].pintarg = va_arg (ap, int *);
01731                         break;
01732                     case T_LONG:
01733                         (*argtable) [n].longarg = va_arg (ap, long);
01734                         break;
01735                     case T_U_LONG:
01736                         (*argtable) [n].ulongarg = va_arg (ap, unsigned long);
01737                         break;
01738                     case TP_LONG:
01739                         (*argtable) [n].plongarg = va_arg (ap, long *);
01740                         break;
01741                     case T_LLONG:
01742                         (*argtable) [n].longlongarg = va_arg (ap, long long);
01743                         break;
01744                     case T_U_LLONG:
01745                         (*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long);
01746                         break;
01747                     case TP_LLONG:
01748                         (*argtable) [n].plonglongarg = va_arg (ap, long long *);
01749                         break;
01750                     case T_PTRDIFFT:
01751                         (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t);
01752                         break;
01753                     case TP_PTRDIFFT:
01754                         (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *);
01755                         break;
01756                     case T_SIZET:
01757                         (*argtable) [n].sizearg = va_arg (ap, size_t);
01758                         break;
01759 #ifndef __FORMATTER__
01760                     case TP_SIZET:
01761                         (*argtable) [n].psizearg = va_arg (ap, ssize_t *);
01762                         break;
01763 #endif
01764                     case T_INTMAXT:
01765                         (*argtable) [n].intmaxarg = va_arg (ap, intmax_t);
01766                         break;
01767                     case T_UINTMAXT:
01768                         (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t);
01769                         break;
01770                     case TP_INTMAXT:
01771                         (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *);
01772                         break;
01773 #ifndef NO_FLOATING_POINT
01774                     case T_DOUBLE:
01775                         (*argtable) [n].doublearg = va_arg (ap, double);
01776                         break;
01777                     case T_LONG_DOUBLE:
01778                         (*argtable) [n].longdoublearg = va_arg (ap, long double);
01779                         break;
01780 #endif
01781                     case TP_CHAR:
01782                         (*argtable) [n].pchararg = va_arg (ap, char *);
01783                         break;
01784                     case TP_VOID:
01785                         (*argtable) [n].pvoidarg = va_arg (ap, void *);
01786                         break;
01787                     case T_WINT:
01788                         (*argtable) [n].wintarg = va_arg (ap, wint_t);
01789                         break;
01790                     case TP_WCHAR:
01791                         (*argtable) [n].pwchararg = va_arg (ap, wchar_t *);
01792                         break;
01793                 }
01794         }
01795 
01796         if ((typetable != NULL) && (typetable != stattypetable))
01797                 free (typetable);
01798 }
01799 
01800 /*
01801  * Increase the size of the type table.
01802  */
01803 static void
01804 __grow_type_table (int nextarg, enum typeid **typetable, int *tablesize)
01805 {
01806         enum typeid *const oldtable = *typetable;
01807         const int oldsize = *tablesize;
01808         enum typeid *newtable;
01809         int n, newsize = oldsize * 2;
01810 
01811         if (newsize < nextarg + 1)
01812                 newsize = nextarg + 1;
01813         if (oldsize == STATIC_ARG_TBL_SIZE) {
01814                 if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL)
01815                         abort();                        /* XXX handle better */
01816                 bcopy(oldtable, newtable, oldsize * sizeof(enum typeid));
01817         } else {
01818                 newtable = reallocf(oldtable, newsize * sizeof(enum typeid));
01819                 if (newtable == NULL)
01820                         abort();                        /* XXX handle better */
01821         }
01822         for (n = oldsize; n < newsize; n++)
01823                 newtable[n] = T_UNUSED;
01824 
01825         *typetable = newtable;
01826         *tablesize = newsize;
01827 }
01828 
01829 
01830 #ifndef NO_FLOATING_POINT
01831 
01832 static int
01833 exponent(char *p0, int exp, int fmtch)
01834 {
01835         char *p, *t;
01836         char expbuf[MAXEXPDIG];
01837 
01838         p = p0;
01839         *p++ = fmtch;
01840         if (exp < 0) {
01841                 exp = -exp;
01842                 *p++ = '-';
01843         }
01844         else
01845                 *p++ = '+';
01846         t = expbuf + MAXEXPDIG;
01847         if (exp > 9) {
01848                 do {
01849                         *--t = to_char(exp % 10);
01850                 } while ((exp /= 10) > 9);
01851                 *--t = to_char(exp);
01852                 for (; t < expbuf + MAXEXPDIG; *p++ = *t++);
01853         }
01854         else {
01855                 /*
01856                  * Exponents for decimal floating point conversions
01857                  * (%[eEgG]) must be at least two characters long,
01858                  * whereas exponents for hexadecimal conversions can
01859                  * be only one character long.
01860                  */
01861                 if (fmtch == 'e' || fmtch == 'E')
01862                         *p++ = '0';
01863                 *p++ = to_char(exp);
01864         }
01865         return (p - p0);
01866 }
01867 #endif /* !NO_FLOATING_POINT */

Generated on Thu Jun 7 12:54:30 2007 for DTN Reference Implementation by  doxygen 1.5.1