u_snprintf.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1995 Patrick Powell.
00003  *
00004  * This code is based on code written by Patrick Powell <papowell@astart.com>.
00005  * It may be used for any purpose as long as this notice remains intact on all
00006  * source code distributions.
00007  */
00008 
00009 /*
00010  * Copyright (c) 2008 Holger Weiss.
00011  *
00012  * This version of the code is maintained by Holger Weiss <holger@jhweiss.de>.
00013  * My changes to the code may freely be used, modified and/or redistributed for
00014  * any purpose.  It would be nice if additions and fixes to this file (including
00015  * trivial code cleanups) would be sent back in order to let me include them in
00016  * the version available at <http://www.jhweiss.de/software/snprintf.html>.
00017  * However, this is not a requirement for using or redistributing (possibly
00018  * modified) versions of this file, nor is leaving this notice intact mandatory.
00019  */
00020 
00021 /*
00022  * History
00023  *
00024  * 2008-01-20 Holger Weiss <holger@jhweiss.de> for C99-snprintf 1.1:
00025  *
00026  *      Fixed the detection of infinite floating point values on IRIX (and
00027  *      possibly other systems) and applied another few minor cleanups.
00028  *
00029  * 2008-01-06 Holger Weiss <holger@jhweiss.de> for C99-snprintf 1.0:
00030  *
00031  *      Added a lot of new features, fixed many bugs, and incorporated various
00032  *      improvements done by Andrew Tridgell <tridge@samba.org>, Russ Allbery
00033  *      <rra@stanford.edu>, Hrvoje Niksic <hniksic@xemacs.org>, Damien Miller
00034  *      <djm@mindrot.org>, and others for the Samba, INN, Wget, and OpenSSH
00035  *      projects.  The additions include: support the "e", "E", "g", "G", and
00036  *      "F" conversion specifiers (and use conversion style "f" or "F" for the
00037  *      still unsupported "a" and "A" specifiers); support the "hh", "ll", "j",
00038  *      "t", and "z" length modifiers; support the "#" flag and the (non-C99)
00039  *      "'" flag; use localeconv(3) (if available) to get both the current
00040  *      locale's decimal point character and the separator between groups of
00041  *      digits; fix the handling of various corner cases of field width and
00042  *      precision specifications; fix various floating point conversion bugs;
00043  *      handle infinite and NaN floating point values; don't attempt to write to
00044  *      the output buffer (which may be NULL) if a size of zero was specified;
00045  *      check for integer overflow of the field width, precision, and return
00046  *      values and during the floating point conversion; use the OUTCHAR() macro
00047  *      instead of a function for better performance; provide asprintf(3) and
00048  *      vasprintf(3) functions; add new test cases.  The replacement functions
00049  *      have been renamed to use an "rpl_" prefix, the function calls in the
00050  *      main project (and in this file) must be redefined accordingly for each
00051  *      replacement function which is needed (by using Autoconf or other means).
00052  *      Various other minor improvements have been applied and the coding style
00053  *      was cleaned up for consistency.
00054  *
00055  * 2007-07-23 Holger Weiss <holger@jhweiss.de> for Mutt 1.5.13:
00056  *
00057  *      C99 compliant snprintf(3) and vsnprintf(3) functions return the number
00058  *      of characters that would have been written to a sufficiently sized
00059  *      buffer (excluding the '\0').  The original code simply returned the
00060  *      length of the resulting output string, so that's been fixed.
00061  *
00062  * 1998-03-05 Michael Elkins <me@mutt.org> for Mutt 0.90.8:
00063  *
00064  *      The original code assumed that both snprintf(3) and vsnprintf(3) were
00065  *      missing.  Some systems only have snprintf(3) but not vsnprintf(3), so
00066  *      the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
00067  *
00068  * 1998-01-27 Thomas Roessler <roessler@does-not-exist.org> for Mutt 0.89i:
00069  *
00070  *      The PGP code was using unsigned hexadecimal formats.  Unfortunately,
00071  *      unsigned formats simply didn't work.
00072  *
00073  * 1997-10-22 Brandon Long <blong@fiction.net> for Mutt 0.87.1:
00074  *
00075  *      Ok, added some minimal floating point support, which means this probably
00076  *      requires libm on most operating systems.  Don't yet support the exponent
00077  *      (e,E) and sigfig (g,G).  Also, fmtint() was pretty badly broken, it just
00078  *      wasn't being exercised in ways which showed it, so that's been fixed.
00079  *      Also, formatted the code to Mutt conventions, and removed dead code left
00080  *      over from the original.  Also, there is now a builtin-test, run with:
00081  *      gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm && ./snprintf
00082  *
00083  * 2996-09-15 Brandon Long <blong@fiction.net> for Mutt 0.43:
00084  *
00085  *      This was ugly.  It is still ugly.  I opted out of floating point
00086  *      numbers, but the formatter understands just about everything from the
00087  *      normal C string format, at least as far as I can tell from the Solaris
00088  *      2.5 printf(3S) man page.
00089  */
00090 
00091 /*
00092  * ToDo
00093  *
00094  * - Add wide character support.
00095  * - Add support for "%a" and "%A" conversions.
00096  * - Create test routines which predefine the expected results.  Our test cases
00097  *   usually expose bugs in system implementations rather than in ours :-)
00098  */
00099 
00100 /*
00101  * Usage
00102  *
00103  * 1) The following preprocessor macros should be defined to 1 if the feature or
00104  *    file in question is available on the target system (by using Autoconf or
00105  *    other means), though basic functionality should be available as long as
00106  *    HAVE_STDARG_H and HAVE_STDLIB_H are defined correctly:
00107  *
00108  *      HAVE_VSNPRINTF
00109  *      HAVE_SNPRINTF
00110  *      HAVE_VASPRINTF
00111  *      HAVE_ASPRINTF
00112  *      HAVE_STDARG_H
00113  *      HAVE_STDDEF_H
00114  *      HAVE_STDINT_H
00115  *      HAVE_STDLIB_H
00116  *      HAVE_INTTYPES_H
00117  *      HAVE_LOCALE_H
00118  *      HAVE_LOCALECONV
00119  *      HAVE_LCONV_DECIMAL_POINT
00120  *      HAVE_LCONV_THOUSANDS_SEP
00121  *      HAVE_LONG_DOUBLE
00122  *      HAVE_LONG_LONG_INT
00123  *      HAVE_UNSIGNED_LONG_LONG_INT
00124  *      HAVE_INTMAX_T
00125  *      HAVE_UINTMAX_T
00126  *      HAVE_UINTPTR_T
00127  *      HAVE_PTRDIFF_T
00128  *      HAVE_VA_COPY
00129  *      HAVE___VA_COPY
00130  *
00131  * 2) The calls to the functions which should be replaced must be redefined
00132  *    throughout the project files (by using Autoconf or other means):
00133  *
00134  *      #define vsnprintf rpl_vsnprintf
00135  *      #define snprintf rpl_snprintf
00136  *      #define vasprintf rpl_vasprintf
00137  *      #define asprintf rpl_asprintf
00138  *
00139  * 3) The required replacement functions should be declared in some header file
00140  *    included throughout the project files:
00141  *
00142  *      #if HAVE_CONFIG_H
00143  *      #include <config.h>
00144  *      #endif
00145  *      #if HAVE_STDARG_H
00146  *      #include <stdarg.h>
00147  *      #if !HAVE_VSNPRINTF
00148  *      int rpl_vsnprintf(char *, size_t, const char *, va_list);
00149  *      #endif
00150  *      #if !HAVE_SNPRINTF
00151  *      int rpl_snprintf(char *, size_t, const char *, ...);
00152  *      #endif
00153  *      #if !HAVE_VASPRINTF
00154  *      int rpl_vasprintf(char **, const char *, va_list);
00155  *      #endif
00156  *      #if !HAVE_ASPRINTF
00157  *      int rpl_asprintf(char **, const char *, ...);
00158  *      #endif
00159  *      #endif
00160  *
00161  * Autoconf macros for handling step 1 and step 2 are available at
00162  * <http://www.jhweiss.de/software/snprintf.html>.
00163  */
00164 
00165 #include "pipe/p_config.h"
00166 
00167 #if HAVE_CONFIG_H
00168 #include <config.h>
00169 #else
00170 #ifdef WIN32
00171 #define vsnprintf util_vsnprintf
00172 #define snprintf util_snprintf
00173 #define HAVE_VSNPRINTF 0
00174 #define HAVE_SNPRINTF 0
00175 #define HAVE_VASPRINTF 1 /* not needed */
00176 #define HAVE_ASPRINTF 1 /* not needed */
00177 #define HAVE_STDARG_H 1
00178 #define HAVE_STDDEF_H 1
00179 #define HAVE_STDINT_H 0
00180 #define HAVE_STDLIB_H 1
00181 #define HAVE_INTTYPES_H 0
00182 #define HAVE_LOCALE_H 0
00183 #define HAVE_LOCALECONV 0
00184 #define HAVE_LCONV_DECIMAL_POINT 0
00185 #define HAVE_LCONV_THOUSANDS_SEP 0
00186 #define HAVE_LONG_DOUBLE 0
00187 #define HAVE_LONG_LONG_INT 1
00188 #define HAVE_UNSIGNED_LONG_LONG_INT 1
00189 #define HAVE_INTMAX_T 0
00190 #define HAVE_UINTMAX_T 0
00191 #define HAVE_UINTPTR_T 1
00192 #define HAVE_PTRDIFF_T 1
00193 #define HAVE_VA_COPY 0
00194 #define HAVE___VA_COPY 0
00195 #else
00196 #define HAVE_VSNPRINTF 1
00197 #define HAVE_SNPRINTF 1
00198 #define HAVE_VASPRINTF 1
00199 #define HAVE_ASPRINTF 1
00200 #endif
00201 #endif  /* HAVE_CONFIG_H */
00202 
00203 #if !HAVE_SNPRINTF || !HAVE_VSNPRINTF || !HAVE_ASPRINTF || !HAVE_VASPRINTF
00204 #include <stdio.h>      /* For NULL, size_t, vsnprintf(3), and vasprintf(3). */
00205 #ifdef VA_START
00206 #undef VA_START
00207 #endif  /* defined(VA_START) */
00208 #ifdef VA_SHIFT
00209 #undef VA_SHIFT
00210 #endif  /* defined(VA_SHIFT) */
00211 #if HAVE_STDARG_H
00212 #include <stdarg.h>
00213 #define VA_START(ap, last) va_start(ap, last)
00214 #define VA_SHIFT(ap, value, type) /* No-op for ANSI C. */
00215 #else   /* Assume <varargs.h> is available. */
00216 #include <varargs.h>
00217 #define VA_START(ap, last) va_start(ap) /* "last" is ignored. */
00218 #define VA_SHIFT(ap, value, type) value = va_arg(ap, type)
00219 #endif  /* HAVE_STDARG_H */
00220 
00221 #if !HAVE_VASPRINTF
00222 #if HAVE_STDLIB_H
00223 #include <stdlib.h>     /* For malloc(3). */
00224 #endif  /* HAVE_STDLIB_H */
00225 #ifdef VA_COPY
00226 #undef VA_COPY
00227 #endif  /* defined(VA_COPY) */
00228 #ifdef VA_END_COPY
00229 #undef VA_END_COPY
00230 #endif  /* defined(VA_END_COPY) */
00231 #if HAVE_VA_COPY
00232 #define VA_COPY(dest, src) va_copy(dest, src)
00233 #define VA_END_COPY(ap) va_end(ap)
00234 #elif HAVE___VA_COPY
00235 #define VA_COPY(dest, src) __va_copy(dest, src)
00236 #define VA_END_COPY(ap) va_end(ap)
00237 #else
00238 #define VA_COPY(dest, src) (void)mymemcpy(&dest, &src, sizeof(va_list))
00239 #define VA_END_COPY(ap) /* No-op. */
00240 #define NEED_MYMEMCPY 1
00241 static void *mymemcpy(void *, void *, size_t);
00242 #endif  /* HAVE_VA_COPY */
00243 #endif  /* !HAVE_VASPRINTF */
00244 
00245 #if !HAVE_VSNPRINTF
00246 #include <limits.h>     /* For *_MAX. */
00247 #if HAVE_INTTYPES_H
00248 #include <inttypes.h>   /* For intmax_t (if not defined in <stdint.h>). */
00249 #endif  /* HAVE_INTTYPES_H */
00250 #if HAVE_LOCALE_H
00251 #include <locale.h>     /* For localeconv(3). */
00252 #endif  /* HAVE_LOCALE_H */
00253 #if HAVE_STDDEF_H
00254 #include <stddef.h>     /* For ptrdiff_t. */
00255 #endif  /* HAVE_STDDEF_H */
00256 #if HAVE_STDINT_H
00257 #include <stdint.h>     /* For intmax_t. */
00258 #endif  /* HAVE_STDINT_H */
00259 
00260 /* Support for unsigned long long int.  We may also need ULLONG_MAX. */
00261 #ifndef ULONG_MAX       /* We may need ULONG_MAX as a fallback. */
00262 #ifdef UINT_MAX
00263 #define ULONG_MAX UINT_MAX
00264 #else
00265 #define ULONG_MAX INT_MAX
00266 #endif  /* defined(UINT_MAX) */
00267 #endif  /* !defined(ULONG_MAX) */
00268 #ifdef ULLONG
00269 #undef ULLONG
00270 #endif  /* defined(ULLONG) */
00271 #if HAVE_UNSIGNED_LONG_LONG_INT
00272 #define ULLONG unsigned long long int
00273 #ifndef ULLONG_MAX
00274 #define ULLONG_MAX ULONG_MAX
00275 #endif  /* !defined(ULLONG_MAX) */
00276 #else
00277 #define ULLONG unsigned long int
00278 #ifdef ULLONG_MAX
00279 #undef ULLONG_MAX
00280 #endif  /* defined(ULLONG_MAX) */
00281 #define ULLONG_MAX ULONG_MAX
00282 #endif  /* HAVE_LONG_LONG_INT */
00283 
00284 /* Support for uintmax_t.  We also need UINTMAX_MAX. */
00285 #ifdef UINTMAX_T
00286 #undef UINTMAX_T
00287 #endif  /* defined(UINTMAX_T) */
00288 #if HAVE_UINTMAX_T || defined(uintmax_t)
00289 #define UINTMAX_T uintmax_t
00290 #ifndef UINTMAX_MAX
00291 #define UINTMAX_MAX ULLONG_MAX
00292 #endif  /* !defined(UINTMAX_MAX) */
00293 #else
00294 #define UINTMAX_T ULLONG
00295 #ifdef UINTMAX_MAX
00296 #undef UINTMAX_MAX
00297 #endif  /* defined(UINTMAX_MAX) */
00298 #define UINTMAX_MAX ULLONG_MAX
00299 #endif  /* HAVE_UINTMAX_T || defined(uintmax_t) */
00300 
00301 /* Support for long double. */
00302 #ifndef LDOUBLE
00303 #if HAVE_LONG_DOUBLE
00304 #define LDOUBLE long double
00305 #else
00306 #define LDOUBLE double
00307 #endif  /* HAVE_LONG_DOUBLE */
00308 #endif  /* !defined(LDOUBLE) */
00309 
00310 /* Support for long long int. */
00311 #ifndef LLONG
00312 #if HAVE_LONG_LONG_INT
00313 #define LLONG long long int
00314 #else
00315 #define LLONG long int
00316 #endif  /* HAVE_LONG_LONG_INT */
00317 #endif  /* !defined(LLONG) */
00318 
00319 /* Support for intmax_t. */
00320 #ifndef INTMAX_T
00321 #if HAVE_INTMAX_T || defined(intmax_t)
00322 #define INTMAX_T intmax_t
00323 #else
00324 #define INTMAX_T LLONG
00325 #endif  /* HAVE_INTMAX_T || defined(intmax_t) */
00326 #endif  /* !defined(INTMAX_T) */
00327 
00328 /* Support for uintptr_t. */
00329 #ifndef UINTPTR_T
00330 #if HAVE_UINTPTR_T || defined(uintptr_t)
00331 #define UINTPTR_T uintptr_t
00332 #else
00333 #define UINTPTR_T unsigned long int
00334 #endif  /* HAVE_UINTPTR_T || defined(uintptr_t) */
00335 #endif  /* !defined(UINTPTR_T) */
00336 
00337 /* WinCE5.0 does not have uintptr_t defined */ 
00338 #if (_WIN32_WCE < 600) 
00339 #ifdef UINTPTR_T 
00340 #undef UINTPTR_T 
00341 #endif 
00342 #define UINTPTR_T unsigned long int 
00343 #endif 
00344 
00345 
00346 /* Support for ptrdiff_t. */
00347 #ifndef PTRDIFF_T
00348 #if HAVE_PTRDIFF_T || defined(ptrdiff_t)
00349 #define PTRDIFF_T ptrdiff_t
00350 #else
00351 #define PTRDIFF_T long int
00352 #endif  /* HAVE_PTRDIFF_T || defined(ptrdiff_t) */
00353 #endif  /* !defined(PTRDIFF_T) */
00354 
00355 /*
00356  * We need an unsigned integer type corresponding to ptrdiff_t (cf. C99:
00357  * 7.19.6.1, 7).  However, we'll simply use PTRDIFF_T and convert it to an
00358  * unsigned type if necessary.  This should work just fine in practice.
00359  */
00360 #ifndef UPTRDIFF_T
00361 #define UPTRDIFF_T PTRDIFF_T
00362 #endif  /* !defined(UPTRDIFF_T) */
00363 
00364 /*
00365  * We need a signed integer type corresponding to size_t (cf. C99: 7.19.6.1, 7).
00366  * However, we'll simply use size_t and convert it to a signed type if
00367  * necessary.  This should work just fine in practice.
00368  */
00369 #ifndef SSIZE_T
00370 #define SSIZE_T size_t
00371 #endif  /* !defined(SSIZE_T) */
00372 
00373 /* Either ERANGE or E2BIG should be available everywhere. */
00374 #ifndef ERANGE
00375 #define ERANGE E2BIG
00376 #endif  /* !defined(ERANGE) */
00377 #ifndef EOVERFLOW
00378 #define EOVERFLOW ERANGE
00379 #endif  /* !defined(EOVERFLOW) */
00380 
00381 /*
00382  * Buffer size to hold the octal string representation of UINT128_MAX without
00383  * nul-termination ("3777777777777777777777777777777777777777777").
00384  */
00385 #ifdef MAX_CONVERT_LENGTH
00386 #undef MAX_CONVERT_LENGTH
00387 #endif  /* defined(MAX_CONVERT_LENGTH) */
00388 #define MAX_CONVERT_LENGTH      43
00389 
00390 /* Format read states. */
00391 #define PRINT_S_DEFAULT         0
00392 #define PRINT_S_FLAGS           1
00393 #define PRINT_S_WIDTH           2
00394 #define PRINT_S_DOT             3
00395 #define PRINT_S_PRECISION       4
00396 #define PRINT_S_MOD             5
00397 #define PRINT_S_CONV            6
00398 
00399 /* Format flags. */
00400 #define PRINT_F_MINUS           (1 << 0)
00401 #define PRINT_F_PLUS            (1 << 1)
00402 #define PRINT_F_SPACE           (1 << 2)
00403 #define PRINT_F_NUM             (1 << 3)
00404 #define PRINT_F_ZERO            (1 << 4)
00405 #define PRINT_F_QUOTE           (1 << 5)
00406 #define PRINT_F_UP              (1 << 6)
00407 #define PRINT_F_UNSIGNED        (1 << 7)
00408 #define PRINT_F_TYPE_G          (1 << 8)
00409 #define PRINT_F_TYPE_E          (1 << 9)
00410 
00411 /* Conversion flags. */
00412 #define PRINT_C_CHAR            1
00413 #define PRINT_C_SHORT           2
00414 #define PRINT_C_LONG            3
00415 #define PRINT_C_LLONG           4
00416 #define PRINT_C_LDOUBLE         5
00417 #define PRINT_C_SIZE            6
00418 #define PRINT_C_PTRDIFF         7
00419 #define PRINT_C_INTMAX          8
00420 
00421 #ifndef MAX
00422 #define MAX(x, y) ((x >= y) ? x : y)
00423 #endif  /* !defined(MAX) */
00424 #ifndef CHARTOINT
00425 #define CHARTOINT(ch) (ch - '0')
00426 #endif  /* !defined(CHARTOINT) */
00427 #ifndef ISDIGIT
00428 #define ISDIGIT(ch) ('0' <= (unsigned char)ch && (unsigned char)ch <= '9')
00429 #endif  /* !defined(ISDIGIT) */
00430 #ifndef ISNAN
00431 #define ISNAN(x) (x != x)
00432 #endif  /* !defined(ISNAN) */
00433 #ifndef ISINF
00434 #define ISINF(x) (x != 0.0 && x + x == x)
00435 #endif  /* !defined(ISINF) */
00436 
00437 #ifdef OUTCHAR
00438 #undef OUTCHAR
00439 #endif  /* defined(OUTCHAR) */
00440 #define OUTCHAR(str, len, size, ch)                                          \
00441 do {                                                                         \
00442         if (len + 1 < size)                                                  \
00443                 str[len] = ch;                                               \
00444         (len)++;                                                             \
00445 } while (/* CONSTCOND */ 0)
00446 
00447 static void fmtstr(char *, size_t *, size_t, const char *, int, int, int);
00448 static void fmtint(char *, size_t *, size_t, INTMAX_T, int, int, int, int);
00449 static void fmtflt(char *, size_t *, size_t, LDOUBLE, int, int, int, int *);
00450 static void printsep(char *, size_t *, size_t);
00451 static int getnumsep(int);
00452 static int getexponent(LDOUBLE);
00453 static int convert(UINTMAX_T, char *, size_t, int, int);
00454 static UINTMAX_T cast(LDOUBLE);
00455 static UINTMAX_T myround(LDOUBLE);
00456 static LDOUBLE mypow10(int);
00457 
00458 int
00459 util_vsnprintf(char *str, size_t size, const char *format, va_list args)
00460 {
00461         LDOUBLE fvalue;
00462         INTMAX_T value;
00463         unsigned char cvalue;
00464         const char *strvalue;
00465         INTMAX_T *intmaxptr;
00466         PTRDIFF_T *ptrdiffptr;
00467         SSIZE_T *sizeptr;
00468         LLONG *llongptr;
00469         long int *longptr;
00470         int *intptr;
00471         short int *shortptr;
00472         signed char *charptr;
00473         size_t len = 0;
00474         int overflow = 0;
00475         int base = 0;
00476         int cflags = 0;
00477         int flags = 0;
00478         int width = 0;
00479         int precision = -1;
00480         int state = PRINT_S_DEFAULT;
00481         char ch = *format++;
00482 
00483         /*
00484          * C99 says: "If `n' is zero, nothing is written, and `s' may be a null
00485          * pointer." (7.19.6.5, 2)  We're forgiving and allow a NULL pointer
00486          * even if a size larger than zero was specified.  At least NetBSD's
00487          * snprintf(3) does the same, as well as other versions of this file.
00488          * (Though some of these versions will write to a non-NULL buffer even
00489          * if a size of zero was specified, which violates the standard.)
00490          */
00491         if (str == NULL && size != 0)
00492                 size = 0;
00493 
00494         while (ch != '\0')
00495                 switch (state) {
00496                 case PRINT_S_DEFAULT:
00497                         if (ch == '%')
00498                                 state = PRINT_S_FLAGS;
00499                         else
00500                                 OUTCHAR(str, len, size, ch);
00501                         ch = *format++;
00502                         break;
00503                 case PRINT_S_FLAGS:
00504                         switch (ch) {
00505                         case '-':
00506                                 flags |= PRINT_F_MINUS;
00507                                 ch = *format++;
00508                                 break;
00509                         case '+':
00510                                 flags |= PRINT_F_PLUS;
00511                                 ch = *format++;
00512                                 break;
00513                         case ' ':
00514                                 flags |= PRINT_F_SPACE;
00515                                 ch = *format++;
00516                                 break;
00517                         case '#':
00518                                 flags |= PRINT_F_NUM;
00519                                 ch = *format++;
00520                                 break;
00521                         case '0':
00522                                 flags |= PRINT_F_ZERO;
00523                                 ch = *format++;
00524                                 break;
00525                         case '\'':      /* SUSv2 flag (not in C99). */
00526                                 flags |= PRINT_F_QUOTE;
00527                                 ch = *format++;
00528                                 break;
00529                         default:
00530                                 state = PRINT_S_WIDTH;
00531                                 break;
00532                         }
00533                         break;
00534                 case PRINT_S_WIDTH:
00535                         if (ISDIGIT(ch)) {
00536                                 ch = CHARTOINT(ch);
00537                                 if (width > (INT_MAX - ch) / 10) {
00538                                         overflow = 1;
00539                                         goto out;
00540                                 }
00541                                 width = 10 * width + ch;
00542                                 ch = *format++;
00543                         } else if (ch == '*') {
00544                                 /*
00545                                  * C99 says: "A negative field width argument is
00546                                  * taken as a `-' flag followed by a positive
00547                                  * field width." (7.19.6.1, 5)
00548                                  */
00549                                 if ((width = va_arg(args, int)) < 0) {
00550                                         flags |= PRINT_F_MINUS;
00551                                         width = -width;
00552                                 }
00553                                 ch = *format++;
00554                                 state = PRINT_S_DOT;
00555                         } else
00556                                 state = PRINT_S_DOT;
00557                         break;
00558                 case PRINT_S_DOT:
00559                         if (ch == '.') {
00560                                 state = PRINT_S_PRECISION;
00561                                 ch = *format++;
00562                         } else
00563                                 state = PRINT_S_MOD;
00564                         break;
00565                 case PRINT_S_PRECISION:
00566                         if (precision == -1)
00567                                 precision = 0;
00568                         if (ISDIGIT(ch)) {
00569                                 ch = CHARTOINT(ch);
00570                                 if (precision > (INT_MAX - ch) / 10) {
00571                                         overflow = 1;
00572                                         goto out;
00573                                 }
00574                                 precision = 10 * precision + ch;
00575                                 ch = *format++;
00576                         } else if (ch == '*') {
00577                                 /*
00578                                  * C99 says: "A negative precision argument is
00579                                  * taken as if the precision were omitted."
00580                                  * (7.19.6.1, 5)
00581                                  */
00582                                 if ((precision = va_arg(args, int)) < 0)
00583                                         precision = -1;
00584                                 ch = *format++;
00585                                 state = PRINT_S_MOD;
00586                         } else
00587                                 state = PRINT_S_MOD;
00588                         break;
00589                 case PRINT_S_MOD:
00590                         switch (ch) {
00591                         case 'h':
00592                                 ch = *format++;
00593                                 if (ch == 'h') {        /* It's a char. */
00594                                         ch = *format++;
00595                                         cflags = PRINT_C_CHAR;
00596                                 } else
00597                                         cflags = PRINT_C_SHORT;
00598                                 break;
00599                         case 'l':
00600                                 ch = *format++;
00601                                 if (ch == 'l') {        /* It's a long long. */
00602                                         ch = *format++;
00603                                         cflags = PRINT_C_LLONG;
00604                                 } else
00605                                         cflags = PRINT_C_LONG;
00606                                 break;
00607                         case 'L':
00608                                 cflags = PRINT_C_LDOUBLE;
00609                                 ch = *format++;
00610                                 break;
00611                         case 'j':
00612                                 cflags = PRINT_C_INTMAX;
00613                                 ch = *format++;
00614                                 break;
00615                         case 't':
00616                                 cflags = PRINT_C_PTRDIFF;
00617                                 ch = *format++;
00618                                 break;
00619                         case 'z':
00620                                 cflags = PRINT_C_SIZE;
00621                                 ch = *format++;
00622                                 break;
00623                         }
00624                         state = PRINT_S_CONV;
00625                         break;
00626                 case PRINT_S_CONV:
00627                         switch (ch) {
00628                         case 'd':
00629                                 /* FALLTHROUGH */
00630                         case 'i':
00631                                 switch (cflags) {
00632                                 case PRINT_C_CHAR:
00633                                         value = (signed char)va_arg(args, int);
00634                                         break;
00635                                 case PRINT_C_SHORT:
00636                                         value = (short int)va_arg(args, int);
00637                                         break;
00638                                 case PRINT_C_LONG:
00639                                         value = va_arg(args, long int);
00640                                         break;
00641                                 case PRINT_C_LLONG:
00642                                         value = va_arg(args, LLONG);
00643                                         break;
00644                                 case PRINT_C_SIZE:
00645                                         value = va_arg(args, SSIZE_T);
00646                                         break;
00647                                 case PRINT_C_INTMAX:
00648                                         value = va_arg(args, INTMAX_T);
00649                                         break;
00650                                 case PRINT_C_PTRDIFF:
00651                                         value = va_arg(args, PTRDIFF_T);
00652                                         break;
00653                                 default:
00654                                         value = va_arg(args, int);
00655                                         break;
00656                                 }
00657                                 fmtint(str, &len, size, value, 10, width,
00658                                     precision, flags);
00659                                 break;
00660                         case 'X':
00661                                 flags |= PRINT_F_UP;
00662                                 /* FALLTHROUGH */
00663                         case 'x':
00664                                 base = 16;
00665                                 /* FALLTHROUGH */
00666                         case 'o':
00667                                 if (base == 0)
00668                                         base = 8;
00669                                 /* FALLTHROUGH */
00670                         case 'u':
00671                                 if (base == 0)
00672                                         base = 10;
00673                                 flags |= PRINT_F_UNSIGNED;
00674                                 switch (cflags) {
00675                                 case PRINT_C_CHAR:
00676                                         value = (unsigned char)va_arg(args,
00677                                             unsigned int);
00678                                         break;
00679                                 case PRINT_C_SHORT:
00680                                         value = (unsigned short int)va_arg(args,
00681                                             unsigned int);
00682                                         break;
00683                                 case PRINT_C_LONG:
00684                                         value = va_arg(args, unsigned long int);
00685                                         break;
00686                                 case PRINT_C_LLONG:
00687                                         value = va_arg(args, ULLONG);
00688                                         break;
00689                                 case PRINT_C_SIZE:
00690                                         value = va_arg(args, size_t);
00691                                         break;
00692                                 case PRINT_C_INTMAX:
00693                                         value = va_arg(args, UINTMAX_T);
00694                                         break;
00695                                 case PRINT_C_PTRDIFF:
00696                                         value = va_arg(args, UPTRDIFF_T);
00697                                         break;
00698                                 default:
00699                                         value = va_arg(args, unsigned int);
00700                                         break;
00701                                 }
00702                                 fmtint(str, &len, size, value, base, width,
00703                                     precision, flags);
00704                                 break;
00705                         case 'A':
00706                                 /* Not yet supported, we'll use "%F". */
00707                                 /* FALLTHROUGH */
00708                         case 'F':
00709                                 flags |= PRINT_F_UP;
00710                         case 'a':
00711                                 /* Not yet supported, we'll use "%f". */
00712                                 /* FALLTHROUGH */
00713                         case 'f':
00714                                 if (cflags == PRINT_C_LDOUBLE)
00715                                         fvalue = va_arg(args, LDOUBLE);
00716                                 else
00717                                         fvalue = va_arg(args, double);
00718                                 fmtflt(str, &len, size, fvalue, width,
00719                                     precision, flags, &overflow);
00720                                 if (overflow)
00721                                         goto out;
00722                                 break;
00723                         case 'E':
00724                                 flags |= PRINT_F_UP;
00725                                 /* FALLTHROUGH */
00726                         case 'e':
00727                                 flags |= PRINT_F_TYPE_E;
00728                                 if (cflags == PRINT_C_LDOUBLE)
00729                                         fvalue = va_arg(args, LDOUBLE);
00730                                 else
00731                                         fvalue = va_arg(args, double);
00732                                 fmtflt(str, &len, size, fvalue, width,
00733                                     precision, flags, &overflow);
00734                                 if (overflow)
00735                                         goto out;
00736                                 break;
00737                         case 'G':
00738                                 flags |= PRINT_F_UP;
00739                                 /* FALLTHROUGH */
00740                         case 'g':
00741                                 flags |= PRINT_F_TYPE_G;
00742                                 if (cflags == PRINT_C_LDOUBLE)
00743                                         fvalue = va_arg(args, LDOUBLE);
00744                                 else
00745                                         fvalue = va_arg(args, double);
00746                                 /*
00747                                  * If the precision is zero, it is treated as
00748                                  * one (cf. C99: 7.19.6.1, 8).
00749                                  */
00750                                 if (precision == 0)
00751                                         precision = 1;
00752                                 fmtflt(str, &len, size, fvalue, width,
00753                                     precision, flags, &overflow);
00754                                 if (overflow)
00755                                         goto out;
00756                                 break;
00757                         case 'c':
00758                                 cvalue = (unsigned char)va_arg(args, int);
00759                                 OUTCHAR(str, len, size, cvalue);
00760                                 break;
00761                         case 's':
00762                                 strvalue = va_arg(args, char *);
00763                                 fmtstr(str, &len, size, strvalue, width,
00764                                     precision, flags);
00765                                 break;
00766                         case 'p':
00767                                 /*
00768                                  * C99 says: "The value of the pointer is
00769                                  * converted to a sequence of printing
00770                                  * characters, in an implementation-defined
00771                                  * manner." (C99: 7.19.6.1, 8)
00772                                  */
00773                                 if ((strvalue = va_arg(args, void *)) == NULL)
00774                                         /*
00775                                          * We use the glibc format.  BSD prints
00776                                          * "0x0", SysV "0".
00777                                          */
00778                                         fmtstr(str, &len, size, "(nil)", width,
00779                                             -1, flags);
00780                                 else {
00781                                         /*
00782                                          * We use the BSD/glibc format.  SysV
00783                                          * omits the "0x" prefix (which we emit
00784                                          * using the PRINT_F_NUM flag).
00785                                          */
00786                                         flags |= PRINT_F_NUM;
00787                                         flags |= PRINT_F_UNSIGNED;
00788                                         fmtint(str, &len, size,
00789                                             (UINTPTR_T)strvalue, 16, width,
00790                                             precision, flags);
00791                                 }
00792                                 break;
00793                         case 'n':
00794                                 switch (cflags) {
00795                                 case PRINT_C_CHAR:
00796                                         charptr = va_arg(args, signed char *);
00797                                         *charptr = (signed char)len;
00798                                         break;
00799                                 case PRINT_C_SHORT:
00800                                         shortptr = va_arg(args, short int *);
00801                                         *shortptr = (short int)len;
00802                                         break;
00803                                 case PRINT_C_LONG:
00804                                         longptr = va_arg(args, long int *);
00805                                         *longptr = (long int)len;
00806                                         break;
00807                                 case PRINT_C_LLONG:
00808                                         llongptr = va_arg(args, LLONG *);
00809                                         *llongptr = (LLONG)len;
00810                                         break;
00811                                 case PRINT_C_SIZE:
00812                                         /*
00813                                          * C99 says that with the "z" length
00814                                          * modifier, "a following `n' conversion
00815                                          * specifier applies to a pointer to a
00816                                          * signed integer type corresponding to
00817                                          * size_t argument." (7.19.6.1, 7)
00818                                          */
00819                                         sizeptr = va_arg(args, SSIZE_T *);
00820                                         *sizeptr = len;
00821                                         break;
00822                                 case PRINT_C_INTMAX:
00823                                         intmaxptr = va_arg(args, INTMAX_T *);
00824                                         *intmaxptr = len;
00825                                         break;
00826                                 case PRINT_C_PTRDIFF:
00827                                         ptrdiffptr = va_arg(args, PTRDIFF_T *);
00828                                         *ptrdiffptr = len;
00829                                         break;
00830                                 default:
00831                                         intptr = va_arg(args, int *);
00832                                         *intptr = len;
00833                                         break;
00834                                 }
00835                                 break;
00836                         case '%':       /* Print a "%" character verbatim. */
00837                                 OUTCHAR(str, len, size, ch);
00838                                 break;
00839                         default:        /* Skip other characters. */
00840                                 break;
00841                         }
00842                         ch = *format++;
00843                         state = PRINT_S_DEFAULT;
00844                         base = cflags = flags = width = 0;
00845                         precision = -1;
00846                         break;
00847                 }
00848 out:
00849         if (len < size)
00850                 str[len] = '\0';
00851         else if (size > 0)
00852                 str[size - 1] = '\0';
00853 
00854         if (overflow || len >= INT_MAX) {
00855                 return -1;
00856         }
00857         return (int)len;
00858 }
00859 
00860 static void
00861 fmtstr(char *str, size_t *len, size_t size, const char *value, int width,
00862        int precision, int flags)
00863 {
00864         int padlen, strln;      /* Amount to pad. */
00865         int noprecision = (precision == -1);
00866 
00867         if (value == NULL)      /* We're forgiving. */
00868                 value = "(null)";
00869 
00870         /* If a precision was specified, don't read the string past it. */
00871         for (strln = 0; value[strln] != '\0' &&
00872             (noprecision || strln < precision); strln++)
00873                 continue;
00874 
00875         if ((padlen = width - strln) < 0)
00876                 padlen = 0;
00877         if (flags & PRINT_F_MINUS)      /* Left justify. */
00878                 padlen = -padlen;
00879 
00880         while (padlen > 0) {    /* Leading spaces. */
00881                 OUTCHAR(str, *len, size, ' ');
00882                 padlen--;
00883         }
00884         while (*value != '\0' && (noprecision || precision-- > 0)) {
00885                 OUTCHAR(str, *len, size, *value);
00886                 value++;
00887         }
00888         while (padlen < 0) {    /* Trailing spaces. */
00889                 OUTCHAR(str, *len, size, ' ');
00890                 padlen++;
00891         }
00892 }
00893 
00894 static void
00895 fmtint(char *str, size_t *len, size_t size, INTMAX_T value, int base, int width,
00896        int precision, int flags)
00897 {
00898         UINTMAX_T uvalue;
00899         char iconvert[MAX_CONVERT_LENGTH];
00900         char sign = 0;
00901         char hexprefix = 0;
00902         int spadlen = 0;        /* Amount to space pad. */
00903         int zpadlen = 0;        /* Amount to zero pad. */
00904         int pos;
00905         int separators = (flags & PRINT_F_QUOTE);
00906         int noprecision = (precision == -1);
00907 
00908         if (flags & PRINT_F_UNSIGNED)
00909                 uvalue = value;
00910         else {
00911                 uvalue = (value >= 0) ? value : -value;
00912                 if (value < 0)
00913                         sign = '-';
00914                 else if (flags & PRINT_F_PLUS)  /* Do a sign. */
00915                         sign = '+';
00916                 else if (flags & PRINT_F_SPACE)
00917                         sign = ' ';
00918         }
00919 
00920         pos = convert(uvalue, iconvert, sizeof(iconvert), base,
00921             flags & PRINT_F_UP);
00922 
00923         if (flags & PRINT_F_NUM && uvalue != 0) {
00924                 /*
00925                  * C99 says: "The result is converted to an `alternative form'.
00926                  * For `o' conversion, it increases the precision, if and only
00927                  * if necessary, to force the first digit of the result to be a
00928                  * zero (if the value and precision are both 0, a single 0 is
00929                  * printed).  For `x' (or `X') conversion, a nonzero result has
00930                  * `0x' (or `0X') prefixed to it." (7.19.6.1, 6)
00931                  */
00932                 switch (base) {
00933                 case 8:
00934                         if (precision <= pos)
00935                                 precision = pos + 1;
00936                         break;
00937                 case 16:
00938                         hexprefix = (flags & PRINT_F_UP) ? 'X' : 'x';
00939                         break;
00940                 }
00941         }
00942 
00943         if (separators) /* Get the number of group separators we'll print. */
00944                 separators = getnumsep(pos);
00945 
00946         zpadlen = precision - pos - separators;
00947         spadlen = width                         /* Minimum field width. */
00948             - separators                        /* Number of separators. */
00949             - MAX(precision, pos)               /* Number of integer digits. */
00950             - ((sign != 0) ? 1 : 0)             /* Will we print a sign? */
00951             - ((hexprefix != 0) ? 2 : 0);       /* Will we print a prefix? */
00952 
00953         if (zpadlen < 0)
00954                 zpadlen = 0;
00955         if (spadlen < 0)
00956                 spadlen = 0;
00957 
00958         /*
00959          * C99 says: "If the `0' and `-' flags both appear, the `0' flag is
00960          * ignored.  For `d', `i', `o', `u', `x', and `X' conversions, if a
00961          * precision is specified, the `0' flag is ignored." (7.19.6.1, 6)
00962          */
00963         if (flags & PRINT_F_MINUS)      /* Left justify. */
00964                 spadlen = -spadlen;
00965         else if (flags & PRINT_F_ZERO && noprecision) {
00966                 zpadlen += spadlen;
00967                 spadlen = 0;
00968         }
00969         while (spadlen > 0) {   /* Leading spaces. */
00970                 OUTCHAR(str, *len, size, ' ');
00971                 spadlen--;
00972         }
00973         if (sign != 0)  /* Sign. */
00974                 OUTCHAR(str, *len, size, sign);
00975         if (hexprefix != 0) {   /* A "0x" or "0X" prefix. */
00976                 OUTCHAR(str, *len, size, '0');
00977                 OUTCHAR(str, *len, size, hexprefix);
00978         }
00979         while (zpadlen > 0) {   /* Leading zeros. */
00980                 OUTCHAR(str, *len, size, '0');
00981                 zpadlen--;
00982         }
00983         while (pos > 0) {       /* The actual digits. */
00984                 pos--;
00985                 OUTCHAR(str, *len, size, iconvert[pos]);
00986                 if (separators > 0 && pos > 0 && pos % 3 == 0)
00987                         printsep(str, len, size);
00988         }
00989         while (spadlen < 0) {   /* Trailing spaces. */
00990                 OUTCHAR(str, *len, size, ' ');
00991                 spadlen++;
00992         }
00993 }
00994 
00995 static void
00996 fmtflt(char *str, size_t *len, size_t size, LDOUBLE fvalue, int width,
00997        int precision, int flags, int *overflow)
00998 {
00999         LDOUBLE ufvalue;
01000         UINTMAX_T intpart;
01001         UINTMAX_T fracpart;
01002         UINTMAX_T mask;
01003         const char *infnan = NULL;
01004         char iconvert[MAX_CONVERT_LENGTH];
01005         char fconvert[MAX_CONVERT_LENGTH];
01006         char econvert[4];       /* "e-12" (without nul-termination). */
01007         char esign = 0;
01008         char sign = 0;
01009         int leadfraczeros = 0;
01010         int exponent = 0;
01011         int emitpoint = 0;
01012         int omitzeros = 0;
01013         int omitcount = 0;
01014         int padlen = 0;
01015         int epos = 0;
01016         int fpos = 0;
01017         int ipos = 0;
01018         int separators = (flags & PRINT_F_QUOTE);
01019         int estyle = (flags & PRINT_F_TYPE_E);
01020 #if HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT
01021         struct lconv *lc = localeconv();
01022 #endif  /* HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT */
01023 
01024         /*
01025          * AIX' man page says the default is 0, but C99 and at least Solaris'
01026          * and NetBSD's man pages say the default is 6, and sprintf(3) on AIX
01027          * defaults to 6.
01028          */
01029         if (precision == -1)
01030                 precision = 6;
01031 
01032         if (fvalue < 0.0)
01033                 sign = '-';
01034         else if (flags & PRINT_F_PLUS)  /* Do a sign. */
01035                 sign = '+';
01036         else if (flags & PRINT_F_SPACE)
01037                 sign = ' ';
01038 
01039         if (ISNAN(fvalue))
01040                 infnan = (flags & PRINT_F_UP) ? "NAN" : "nan";
01041         else if (ISINF(fvalue))
01042                 infnan = (flags & PRINT_F_UP) ? "INF" : "inf";
01043 
01044         if (infnan != NULL) {
01045                 if (sign != 0)
01046                         iconvert[ipos++] = sign;
01047                 while (*infnan != '\0')
01048                         iconvert[ipos++] = *infnan++;
01049                 fmtstr(str, len, size, iconvert, width, ipos, flags);
01050                 return;
01051         }
01052 
01053         /* "%e" (or "%E") or "%g" (or "%G") conversion. */
01054         if (flags & PRINT_F_TYPE_E || flags & PRINT_F_TYPE_G) {
01055                 if (flags & PRINT_F_TYPE_G) {
01056                         /*
01057                          * For "%g" (and "%G") conversions, the precision
01058                          * specifies the number of significant digits, which
01059                          * includes the digits in the integer part.  The
01060                          * conversion will or will not be using "e-style" (like
01061                          * "%e" or "%E" conversions) depending on the precision
01062                          * and on the exponent.  However, the exponent can be
01063                          * affected by rounding the converted value, so we'll
01064                          * leave this decision for later.  Until then, we'll
01065                          * assume that we're going to do an "e-style" conversion
01066                          * (in order to get the exponent calculated).  For
01067                          * "e-style", the precision must be decremented by one.
01068                          */
01069                         precision--;
01070                         /*
01071                          * For "%g" (and "%G") conversions, trailing zeros are
01072                          * removed from the fractional portion of the result
01073                          * unless the "#" flag was specified.
01074                          */
01075                         if (!(flags & PRINT_F_NUM))
01076                                 omitzeros = 1;
01077                 }
01078                 exponent = getexponent(fvalue);
01079                 estyle = 1;
01080         }
01081 
01082 again:
01083         /*
01084          * Sorry, we only support 9, 19, or 38 digits (that is, the number of
01085          * digits of the 32-bit, the 64-bit, or the 128-bit UINTMAX_MAX value
01086          * minus one) past the decimal point due to our conversion method.
01087          */
01088         switch (sizeof(UINTMAX_T)) {
01089         case 16:
01090                 if (precision > 38)
01091                         precision = 38;
01092                 break;
01093         case 8:
01094                 if (precision > 19)
01095                         precision = 19;
01096                 break;
01097         default:
01098                 if (precision > 9)
01099                         precision = 9;
01100                 break;
01101         }
01102 
01103         ufvalue = (fvalue >= 0.0) ? fvalue : -fvalue;
01104         if (estyle)     /* We want exactly one integer digit. */
01105                 ufvalue /= mypow10(exponent);
01106 
01107         if ((intpart = cast(ufvalue)) == UINTMAX_MAX) {
01108                 *overflow = 1;
01109                 return;
01110         }
01111 
01112         /*
01113          * Factor of ten with the number of digits needed for the fractional
01114          * part.  For example, if the precision is 3, the mask will be 1000.
01115          */
01116 #if defined(PIPE_SUBSYSTEM_WINDOWS_MINIPORT)
01117         mask = (unsigned long)mypow10(precision);
01118 #else
01119         mask = (UINTMAX_T)mypow10(precision);
01120 #endif
01121         /*
01122          * We "cheat" by converting the fractional part to integer by
01123          * multiplying by a factor of ten.
01124          */
01125         if ((fracpart = myround(mask * (ufvalue - intpart))) >= mask) {
01126                 /*
01127                  * For example, ufvalue = 2.99962, intpart = 2, and mask = 1000
01128                  * (because precision = 3).  Now, myround(1000 * 0.99962) will
01129                  * return 1000.  So, the integer part must be incremented by one
01130                  * and the fractional part must be set to zero.
01131                  */
01132                 intpart++;
01133                 fracpart = 0;
01134                 if (estyle && intpart == 10) {
01135                         /*
01136                          * The value was rounded up to ten, but we only want one
01137                          * integer digit if using "e-style".  So, the integer
01138                          * part must be set to one and the exponent must be
01139                          * incremented by one.
01140                          */
01141                         intpart = 1;
01142                         exponent++;
01143                 }
01144         }
01145 
01146         /*
01147          * Now that we know the real exponent, we can check whether or not to
01148          * use "e-style" for "%g" (and "%G") conversions.  If we don't need
01149          * "e-style", the precision must be adjusted and the integer and
01150          * fractional parts must be recalculated from the original value.
01151          *
01152          * C99 says: "Let P equal the precision if nonzero, 6 if the precision
01153          * is omitted, or 1 if the precision is zero.  Then, if a conversion
01154          * with style `E' would have an exponent of X:
01155          *
01156          * - if P > X >= -4, the conversion is with style `f' (or `F') and
01157          *   precision P - (X + 1).
01158          *
01159          * - otherwise, the conversion is with style `e' (or `E') and precision
01160          *   P - 1." (7.19.6.1, 8)
01161          *
01162          * Note that we had decremented the precision by one.
01163          */
01164         if (flags & PRINT_F_TYPE_G && estyle &&
01165             precision + 1 > exponent && exponent >= -4) {
01166                 precision -= exponent;
01167                 estyle = 0;
01168                 goto again;
01169         }
01170 
01171         if (estyle) {
01172                 if (exponent < 0) {
01173                         exponent = -exponent;
01174                         esign = '-';
01175                 } else
01176                         esign = '+';
01177 
01178                 /*
01179                  * Convert the exponent.  The sizeof(econvert) is 4.  So, the
01180                  * econvert buffer can hold e.g. "e+99" and "e-99".  We don't
01181                  * support an exponent which contains more than two digits.
01182                  * Therefore, the following stores are safe.
01183                  */
01184                 epos = convert(exponent, econvert, 2, 10, 0);
01185                 /*
01186                  * C99 says: "The exponent always contains at least two digits,
01187                  * and only as many more digits as necessary to represent the
01188                  * exponent." (7.19.6.1, 8)
01189                  */
01190                 if (epos == 1)
01191                         econvert[epos++] = '0';
01192                 econvert[epos++] = esign;
01193                 econvert[epos++] = (flags & PRINT_F_UP) ? 'E' : 'e';
01194         }
01195 
01196         /* Convert the integer part and the fractional part. */
01197         ipos = convert(intpart, iconvert, sizeof(iconvert), 10, 0);
01198         if (fracpart != 0)      /* convert() would return 1 if fracpart == 0. */
01199                 fpos = convert(fracpart, fconvert, sizeof(fconvert), 10, 0);
01200 
01201         leadfraczeros = precision - fpos;
01202 
01203         if (omitzeros) {
01204                 if (fpos > 0)   /* Omit trailing fractional part zeros. */
01205                         while (omitcount < fpos && fconvert[omitcount] == '0')
01206                                 omitcount++;
01207                 else {  /* The fractional part is zero, omit it completely. */
01208                         omitcount = precision;
01209                         leadfraczeros = 0;
01210                 }
01211                 precision -= omitcount;
01212         }
01213 
01214         /*
01215          * Print a decimal point if either the fractional part is non-zero
01216          * and/or the "#" flag was specified.
01217          */
01218         if (precision > 0 || flags & PRINT_F_NUM)
01219                 emitpoint = 1;
01220         if (separators) /* Get the number of group separators we'll print. */
01221                 separators = getnumsep(ipos);
01222 
01223         padlen = width                  /* Minimum field width. */
01224             - ipos                      /* Number of integer digits. */
01225             - epos                      /* Number of exponent characters. */
01226             - precision                 /* Number of fractional digits. */
01227             - separators                /* Number of group separators. */
01228             - (emitpoint ? 1 : 0)       /* Will we print a decimal point? */
01229             - ((sign != 0) ? 1 : 0);    /* Will we print a sign character? */
01230 
01231         if (padlen < 0)
01232                 padlen = 0;
01233 
01234         /*
01235          * C99 says: "If the `0' and `-' flags both appear, the `0' flag is
01236          * ignored." (7.19.6.1, 6)
01237          */
01238         if (flags & PRINT_F_MINUS)      /* Left justifty. */
01239                 padlen = -padlen;
01240         else if (flags & PRINT_F_ZERO && padlen > 0) {
01241                 if (sign != 0) {        /* Sign. */
01242                         OUTCHAR(str, *len, size, sign);
01243                         sign = 0;
01244                 }
01245                 while (padlen > 0) {    /* Leading zeros. */
01246                         OUTCHAR(str, *len, size, '0');
01247                         padlen--;
01248                 }
01249         }
01250         while (padlen > 0) {    /* Leading spaces. */
01251                 OUTCHAR(str, *len, size, ' ');
01252                 padlen--;
01253         }
01254         if (sign != 0)  /* Sign. */
01255                 OUTCHAR(str, *len, size, sign);
01256         while (ipos > 0) {      /* Integer part. */
01257                 ipos--;
01258                 OUTCHAR(str, *len, size, iconvert[ipos]);
01259                 if (separators > 0 && ipos > 0 && ipos % 3 == 0)
01260                         printsep(str, len, size);
01261         }
01262         if (emitpoint) {        /* Decimal point. */
01263 #if HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT
01264                 if (lc->decimal_point != NULL && *lc->decimal_point != '\0')
01265                         OUTCHAR(str, *len, size, *lc->decimal_point);
01266                 else    /* We'll always print some decimal point character. */
01267 #endif  /* HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT */
01268                         OUTCHAR(str, *len, size, '.');
01269         }
01270         while (leadfraczeros > 0) {     /* Leading fractional part zeros. */
01271                 OUTCHAR(str, *len, size, '0');
01272                 leadfraczeros--;
01273         }
01274         while (fpos > omitcount) {      /* The remaining fractional part. */
01275                 fpos--;
01276                 OUTCHAR(str, *len, size, fconvert[fpos]);
01277         }
01278         while (epos > 0) {      /* Exponent. */
01279                 epos--;
01280                 OUTCHAR(str, *len, size, econvert[epos]);
01281         }
01282         while (padlen < 0) {    /* Trailing spaces. */
01283                 OUTCHAR(str, *len, size, ' ');
01284                 padlen++;
01285         }
01286 }
01287 
01288 static void
01289 printsep(char *str, size_t *len, size_t size)
01290 {
01291 #if HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP
01292         struct lconv *lc = localeconv();
01293         int i;
01294 
01295         if (lc->thousands_sep != NULL)
01296                 for (i = 0; lc->thousands_sep[i] != '\0'; i++)
01297                         OUTCHAR(str, *len, size, lc->thousands_sep[i]);
01298         else
01299 #endif  /* HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP */
01300                 OUTCHAR(str, *len, size, ',');
01301 }
01302 
01303 static int
01304 getnumsep(int digits)
01305 {
01306         int separators = (digits - ((digits % 3 == 0) ? 1 : 0)) / 3;
01307 #if HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP
01308         int strln;
01309         struct lconv *lc = localeconv();
01310 
01311         /* We support an arbitrary separator length (including zero). */
01312         if (lc->thousands_sep != NULL) {
01313                 for (strln = 0; lc->thousands_sep[strln] != '\0'; strln++)
01314                         continue;
01315                 separators *= strln;
01316         }
01317 #endif  /* HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP */
01318         return separators;
01319 }
01320 
01321 static int
01322 getexponent(LDOUBLE value)
01323 {
01324         LDOUBLE tmp = (value >= 0.0) ? value : -value;
01325         int exponent = 0;
01326 
01327         /*
01328          * We check for 99 > exponent > -99 in order to work around possible
01329          * endless loops which could happen (at least) in the second loop (at
01330          * least) if we're called with an infinite value.  However, we checked
01331          * for infinity before calling this function using our ISINF() macro, so
01332          * this might be somewhat paranoid.
01333          */
01334         while (tmp < 1.0 && tmp > 0.0 && --exponent > -99)
01335                 tmp *= 10;
01336         while (tmp >= 10.0 && ++exponent < 99)
01337                 tmp /= 10;
01338 
01339         return exponent;
01340 }
01341 
01342 static int
01343 convert(UINTMAX_T value, char *buf, size_t size, int base, int caps)
01344 {
01345         const char *digits = caps ? "0123456789ABCDEF" : "0123456789abcdef";
01346         size_t pos = 0;
01347 
01348         /* We return an unterminated buffer with the digits in reverse order. */
01349         do {
01350                 buf[pos++] = digits[value % base];
01351                 value /= base;
01352         } while (value != 0 && pos < size);
01353 
01354         return (int)pos;
01355 }
01356 
01357 static UINTMAX_T
01358 cast(LDOUBLE value)
01359 {
01360         UINTMAX_T result;
01361 
01362         /*
01363          * We check for ">=" and not for ">" because if UINTMAX_MAX cannot be
01364          * represented exactly as an LDOUBLE value (but is less than LDBL_MAX),
01365          * it may be increased to the nearest higher representable value for the
01366          * comparison (cf. C99: 6.3.1.4, 2).  It might then equal the LDOUBLE
01367          * value although converting the latter to UINTMAX_T would overflow.
01368          */
01369         if (value >= UINTMAX_MAX)
01370                 return UINTMAX_MAX;
01371 
01372 #if defined(PIPE_SUBSYSTEM_WINDOWS_MINIPORT)
01373         result = (unsigned long)value;
01374 #else
01375         result = (UINTMAX_T)value;
01376 #endif
01377         /*
01378          * At least on NetBSD/sparc64 3.0.2 and 4.99.30, casting long double to
01379          * an integer type converts e.g. 1.9 to 2 instead of 1 (which violates
01380          * the standard).  Sigh.
01381          */
01382         return (result <= value) ? result : result - 1;
01383 }
01384 
01385 static UINTMAX_T
01386 myround(LDOUBLE value)
01387 {
01388         UINTMAX_T intpart = cast(value);
01389 
01390         return ((value -= intpart) < 0.5) ? intpart : intpart + 1;
01391 }
01392 
01393 static LDOUBLE
01394 mypow10(int exponent)
01395 {
01396         LDOUBLE result = 1;
01397 
01398         while (exponent > 0) {
01399                 result *= 10;
01400                 exponent--;
01401         }
01402         while (exponent < 0) {
01403                 result /= 10;
01404                 exponent++;
01405         }
01406         return result;
01407 }
01408 #endif  /* !HAVE_VSNPRINTF */
01409 
01410 #if !HAVE_VASPRINTF
01411 #if NEED_MYMEMCPY
01412 void *
01413 mymemcpy(void *dst, void *src, size_t len)
01414 {
01415         const char *from = src;
01416         char *to = dst;
01417 
01418         /* No need for optimization, we use this only to replace va_copy(3). */
01419         while (len-- > 0)
01420                 *to++ = *from++;
01421         return dst;
01422 }
01423 #endif  /* NEED_MYMEMCPY */
01424 
01425 int
01426 util_vasprintf(char **ret, const char *format, va_list ap)
01427 {
01428         size_t size;
01429         int len;
01430         va_list aq;
01431 
01432         VA_COPY(aq, ap);
01433         len = vsnprintf(NULL, 0, format, aq);
01434         VA_END_COPY(aq);
01435         if (len < 0 || (*ret = malloc(size = len + 1)) == NULL)
01436                 return -1;
01437         return vsnprintf(*ret, size, format, ap);
01438 }
01439 #endif  /* !HAVE_VASPRINTF */
01440 
01441 #if !HAVE_SNPRINTF
01442 #if HAVE_STDARG_H
01443 int
01444 util_snprintf(char *str, size_t size, const char *format, ...)
01445 #else
01446 int
01447 util_snprintf(va_alist) va_dcl
01448 #endif  /* HAVE_STDARG_H */
01449 {
01450 #if !HAVE_STDARG_H
01451         char *str;
01452         size_t size;
01453         char *format;
01454 #endif  /* HAVE_STDARG_H */
01455         va_list ap;
01456         int len;
01457 
01458         VA_START(ap, format);
01459         VA_SHIFT(ap, str, char *);
01460         VA_SHIFT(ap, size, size_t);
01461         VA_SHIFT(ap, format, const char *);
01462         len = vsnprintf(str, size, format, ap);
01463         va_end(ap);
01464         return len;
01465 }
01466 #endif  /* !HAVE_SNPRINTF */
01467 
01468 #if !HAVE_ASPRINTF
01469 #if HAVE_STDARG_H
01470 int
01471 util_asprintf(char **ret, const char *format, ...)
01472 #else
01473 int
01474 util_asprintf(va_alist) va_dcl
01475 #endif  /* HAVE_STDARG_H */
01476 {
01477 #if !HAVE_STDARG_H
01478         char **ret;
01479         char *format;
01480 #endif  /* HAVE_STDARG_H */
01481         va_list ap;
01482         int len;
01483 
01484         VA_START(ap, format);
01485         VA_SHIFT(ap, ret, char **);
01486         VA_SHIFT(ap, format, const char *);
01487         len = vasprintf(ret, format, ap);
01488         va_end(ap);
01489         return len;
01490 }
01491 #endif  /* !HAVE_ASPRINTF */
01492 #else   /* Dummy declaration to avoid empty translation unit warnings. */
01493 int main(void);
01494 #endif  /* !HAVE_SNPRINTF || !HAVE_VSNPRINTF || !HAVE_ASPRINTF || [...] */
01495 
01496 
01497 /* vim: set joinspaces textwidth=80: */

Generated on Tue Sep 29 06:25:15 2009 for Gallium3D by  doxygen 1.5.4