sgdk
stb_sprintf.h
00001 // stb_sprintf - v1.06 - public domain snprintf() implementation
00002 // originally by Jeff Roberts / RAD Game Tools, 2015/10/20
00003 // http://github.com/nothings/stb
00004 //
00005 // allowed types:  sc uidBboXx p AaGgEef n
00006 // lengths      :  h ll j z t I64 I32 I
00007 //
00008 // Contributors:
00009 //    Fabian "ryg" Giesen (reformatting)
00010 //
00011 // Contributors (bugfixes):
00012 //    github:d26435
00013 //    github:trex78
00014 //    github:account-login
00015 //    Jari Komppa (SI suffixes)
00016 //    Rohit Nirmal
00017 //    Marcin Wojdyr
00018 //    Leonard Ritter
00019 //    Stefano Zanotti
00020 //    Adam Allison
00021 //
00022 // LICENSE:
00023 //
00024 //   See end of file for license information.
00025 
00026 #ifndef STB_SPRINTF_H_INCLUDE
00027 #define STB_SPRINTF_H_INCLUDE
00028 
00029 /*
00030 Single file sprintf replacement.
00031 
00032 Originally written by Jeff Roberts at RAD Game Tools - 2015/10/20.
00033 Hereby placed in public domain.
00034 
00035 This is a full sprintf replacement that supports everything that
00036 the C runtime sprintfs support, including float/double, 64-bit integers,
00037 hex floats, field parameters (%*.*d stuff), length reads backs, etc.
00038 
00039 Why would you need this if sprintf already exists?  Well, first off,
00040 it's *much* faster (see below). It's also much smaller than the CRT
00041 versions code-space-wise. We've also added some simple improvements
00042 that are super handy (commas in thousands, callbacks at buffer full,
00043 for example). Finally, the format strings for MSVC and GCC differ
00044 for 64-bit integers (among other small things), so this lets you use
00045 the same format strings in cross platform code.
00046 
00047 It uses the standard single file trick of being both the header file
00048 and the source itself. If you just include it normally, you just get
00049 the header file function definitions. To get the code, you include
00050 it from a C or C++ file and define STB_SPRINTF_IMPLEMENTATION first.
00051 
00052 It only uses va_args macros from the C runtime to do it's work. It
00053 does cast doubles to S64s and shifts and divides U64s, which does
00054 drag in CRT code on most platforms.
00055 
00056 It compiles to roughly 8K with float support, and 4K without.
00057 As a comparison, when using MSVC static libs, calling sprintf drags
00058 in 16K.
00059 
00060 API:
00061 ====
00062 int stbsp_sprintf( char * buf, char const * fmt, ... )
00063 int stbsp_snprintf( char * buf, int count, char const * fmt, ... )
00064   Convert an arg list into a buffer.  stbsp_snprintf always returns
00065   a zero-terminated string (unlike regular snprintf).
00066 
00067 int stbsp_vsprintf( char * buf, char const * fmt, va_list va )
00068 int stbsp_vsnprintf( char * buf, int count, char const * fmt, va_list va )
00069   Convert a va_list arg list into a buffer.  stbsp_vsnprintf always returns
00070   a zero-terminated string (unlike regular snprintf).
00071 
00072 int stbsp_vsprintfcb( STBSP_SPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va )
00073     typedef char * STBSP_SPRINTFCB( char const * buf, void * user, int len );
00074   Convert into a buffer, calling back every STB_SPRINTF_MIN chars.
00075   Your callback can then copy the chars out, print them or whatever.
00076   This function is actually the workhorse for everything else.
00077   The buffer you pass in must hold at least STB_SPRINTF_MIN characters.
00078     // you return the next buffer to use or 0 to stop converting
00079 
00080 void stbsp_set_separators( char comma, char period )
00081   Set the comma and period characters to use.
00082 
00083 FLOATS/DOUBLES:
00084 ===============
00085 This code uses a internal float->ascii conversion method that uses
00086 doubles with error correction (double-doubles, for ~105 bits of
00087 precision).  This conversion is round-trip perfect - that is, an atof
00088 of the values output here will give you the bit-exact double back.
00089 
00090 One difference is that our insignificant digits will be different than
00091 with MSVC or GCC (but they don't match each other either).  We also
00092 don't attempt to find the minimum length matching float (pre-MSVC15
00093 doesn't either).
00094 
00095 If you don't need float or doubles at all, define STB_SPRINTF_NOFLOAT
00096 and you'll save 4K of code space.
00097 
00098 64-BIT INTS:
00099 ============
00100 This library also supports 64-bit integers and you can use MSVC style or
00101 GCC style indicators (%I64d or %lld).  It supports the C99 specifiers
00102 for size_t and ptr_diff_t (%jd %zd) as well.
00103 
00104 EXTRAS:
00105 =======
00106 Like some GCCs, for integers and floats, you can use a ' (single quote)
00107 specifier and commas will be inserted on the thousands: "%'d" on 12345
00108 would print 12,345.
00109 
00110 For integers and floats, you can use a "$" specifier and the number
00111 will be converted to float and then divided to get kilo, mega, giga or
00112 tera and then printed, so "%$d" 1000 is "1.0 k", "%$.2d" 2536000 is
00113 "2.53 M", etc. For byte values, use two $:s, like "%$$d" to turn
00114 2536000 to "2.42 Mi". If you prefer JEDEC suffixes to SI ones, use three
00115 $:s: "%$$$d" -> "2.42 M". To remove the space between the number and the
00116 suffix, add "_" specifier: "%_$d" -> "2.53M".
00117 
00118 In addition to octal and hexadecimal conversions, you can print
00119 integers in binary: "%b" for 256 would print 100.
00120 
00121 PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC):
00122 ===================================================================
00123 "%d" across all 32-bit ints (4.8x/4.0x faster than 32-/64-bit MSVC)
00124 "%24d" across all 32-bit ints (4.5x/4.2x faster)
00125 "%x" across all 32-bit ints (4.5x/3.8x faster)
00126 "%08x" across all 32-bit ints (4.3x/3.8x faster)
00127 "%f" across e-10 to e+10 floats (7.3x/6.0x faster)
00128 "%e" across e-10 to e+10 floats (8.1x/6.0x faster)
00129 "%g" across e-10 to e+10 floats (10.0x/7.1x faster)
00130 "%f" for values near e-300 (7.9x/6.5x faster)
00131 "%f" for values near e+300 (10.0x/9.1x faster)
00132 "%e" for values near e-300 (10.1x/7.0x faster)
00133 "%e" for values near e+300 (9.2x/6.0x faster)
00134 "%.320f" for values near e-300 (12.6x/11.2x faster)
00135 "%a" for random values (8.6x/4.3x faster)
00136 "%I64d" for 64-bits with 32-bit values (4.8x/3.4x faster)
00137 "%I64d" for 64-bits > 32-bit values (4.9x/5.5x faster)
00138 "%s%s%s" for 64 char strings (7.1x/7.3x faster)
00139 "...512 char string..." ( 35.0x/32.5x faster!)
00140 */
00141 
00142 #if defined(__has_feature)
00143    #if __has_feature(address_sanitizer)
00144       #define STBI__ASAN __attribute__((no_sanitize("address")))
00145    #endif
00146 #endif
00147 #ifndef STBI__ASAN
00148 #define STBI__ASAN
00149 #endif
00150 
00151 #ifdef STB_SPRINTF_STATIC
00152 #define STBSP__PUBLICDEC static
00153 #define STBSP__PUBLICDEF static STBI__ASAN
00154 #else
00155 #ifdef __cplusplus
00156 #define STBSP__PUBLICDEC extern "C"
00157 #define STBSP__PUBLICDEF extern "C" STBI__ASAN
00158 #else
00159 #define STBSP__PUBLICDEC extern
00160 #define STBSP__PUBLICDEF STBI__ASAN
00161 #endif
00162 #endif
00163 
00164 #ifndef STB_SPRINTF_NOSTD
00165 #include <stdarg.h> // for va_list()
00166 #include <stddef.h> // size_t, ptrdiff_t
00167 #endif
00168 
00169 #ifndef STB_SPRINTF_MIN
00170 #define STB_SPRINTF_MIN 512 // how many characters per callback
00171 #endif
00172 typedef char *STBSP_SPRINTFCB(char *buf, void *user, int len);
00173 
00174 #ifndef STB_SPRINTF_DECORATE
00175 #define STB_SPRINTF_DECORATE(name) stbsp_##name // define this before including if you want to change the names
00176 #endif
00177 
00178 STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va);
00179 STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, int count, char const *fmt, va_list va);
00180 STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...);
00181 STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...);
00182 
00183 STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va);
00184 STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char comma, char period);
00185 
00186 #endif // STB_SPRINTF_H_INCLUDE
00187 
00188 #ifdef STB_SPRINTF_IMPLEMENTATION
00189 
00190 #ifndef STB_SPRINTF_NOSTD
00191 #include <stdlib.h> // for va_arg()
00192 #endif
00193 
00194 #define stbsp__uint32 unsigned int
00195 #define stbsp__int32 signed int
00196 
00197 #ifdef _MSC_VER
00198 #define stbsp__uint64 unsigned __int64
00199 #define stbsp__int64 signed __int64
00200 #else
00201 #define stbsp__uint64 unsigned long long
00202 #define stbsp__int64 signed long long
00203 #endif
00204 #define stbsp__uint16 unsigned short
00205 
00206 #ifndef stbsp__uintptr
00207 #if defined(__ppc64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64)
00208 #define stbsp__uintptr stbsp__uint64
00209 #else
00210 #define stbsp__uintptr stbsp__uint32
00211 #endif
00212 #endif
00213 
00214 #ifndef STB_SPRINTF_MSVC_MODE // used for MSVC2013 and earlier (MSVC2015 matches GCC)
00215 #if defined(_MSC_VER) && (_MSC_VER < 1900)
00216 #define STB_SPRINTF_MSVC_MODE
00217 #endif
00218 #endif
00219 
00220 #ifdef STB_SPRINTF_NOUNALIGNED // define this before inclusion to force stbsp_sprintf to always use aligned accesses
00221 #define STBSP__UNALIGNED(code)
00222 #else
00223 #define STBSP__UNALIGNED(code) code
00224 #endif
00225 
00226 #ifndef STB_SPRINTF_NOFLOAT
00227 // internal float utility functions
00228 static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits);
00229 static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value);
00230 #define STBSP__SPECIAL 0x7000
00231 #endif
00232 
00233 static char stbsp__period = '.';
00234 static char stbsp__comma = ',';
00235 static struct
00236 {
00237    short temp; // force next field to be 2-byte aligned
00238    char pair[201];
00239 } stbsp__digitpair =
00240 {
00241   0,
00242    "00010203040506070809101112131415161718192021222324"
00243    "25262728293031323334353637383940414243444546474849"
00244    "50515253545556575859606162636465666768697071727374"
00245    "75767778798081828384858687888990919293949596979899"
00246 };
00247 
00248 STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char pcomma, char pperiod)
00249 {
00250    stbsp__period = pperiod;
00251    stbsp__comma = pcomma;
00252 }
00253 
00254 #define STBSP__LEFTJUST 1
00255 #define STBSP__LEADINGPLUS 2
00256 #define STBSP__LEADINGSPACE 4
00257 #define STBSP__LEADING_0X 8
00258 #define STBSP__LEADINGZERO 16
00259 #define STBSP__INTMAX 32
00260 #define STBSP__TRIPLET_COMMA 64
00261 #define STBSP__NEGATIVE 128
00262 #define STBSP__METRIC_SUFFIX 256
00263 #define STBSP__HALFWIDTH 512
00264 #define STBSP__METRIC_NOSPACE 1024
00265 #define STBSP__METRIC_1024 2048
00266 #define STBSP__METRIC_JEDEC 4096
00267 
00268 static void stbsp__lead_sign(stbsp__uint32 fl, char *sign)
00269 {
00270    sign[0] = 0;
00271    if (fl & STBSP__NEGATIVE) {
00272       sign[0] = 1;
00273       sign[1] = '-';
00274    } else if (fl & STBSP__LEADINGSPACE) {
00275       sign[0] = 1;
00276       sign[1] = ' ';
00277    } else if (fl & STBSP__LEADINGPLUS) {
00278       sign[0] = 1;
00279       sign[1] = '+';
00280    }
00281 }
00282 
00283 STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va)
00284 {
00285    static char hex[] = "0123456789abcdefxp";
00286    static char hexu[] = "0123456789ABCDEFXP";
00287    char *bf;
00288    char const *f;
00289    int tlen = 0;
00290 
00291    bf = buf;
00292    f = fmt;
00293    for (;;) {
00294       stbsp__int32 fw, pr, tz;
00295       stbsp__uint32 fl;
00296 
00297       // macros for the callback buffer stuff
00298       #define stbsp__chk_cb_bufL(bytes)                        \
00299          {                                                     \
00300             int len = (int)(bf - buf);                         \
00301             if ((len + (bytes)) >= STB_SPRINTF_MIN) {          \
00302                tlen += len;                                    \
00303                if (0 == (bf = buf = callback(buf, user, len))) \
00304                   goto done;                                   \
00305             }                                                  \
00306          }
00307       #define stbsp__chk_cb_buf(bytes)    \
00308          {                                \
00309             if (callback) {               \
00310                stbsp__chk_cb_bufL(bytes); \
00311             }                             \
00312          }
00313       #define stbsp__flush_cb()                      \
00314          {                                           \
00315             stbsp__chk_cb_bufL(STB_SPRINTF_MIN - 1); \
00316          } // flush if there is even one byte in the buffer
00317       #define stbsp__cb_buf_clamp(cl, v)                \
00318          cl = v;                                        \
00319          if (callback) {                                \
00320             int lg = STB_SPRINTF_MIN - (int)(bf - buf); \
00321             if (cl > lg)                                \
00322                cl = lg;                                 \
00323          }
00324 
00325       // fast copy everything up to the next % (or end of string)
00326       for (;;) {
00327          while (((stbsp__uintptr)f) & 3) {
00328          schk1:
00329             if (f[0] == '%')
00330                goto scandd;
00331          schk2:
00332             if (f[0] == 0)
00333                goto endfmt;
00334             stbsp__chk_cb_buf(1);
00335             *bf++ = f[0];
00336             ++f;
00337          }
00338          for (;;) {
00339             // Check if the next 4 bytes contain %(0x25) or end of string.
00340             // Using the 'hasless' trick:
00341             // https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord
00342             stbsp__uint32 v, c;
00343             v = *(stbsp__uint32 *)f;
00344             c = (~v) & 0x80808080;
00345             if (((v ^ 0x25252525) - 0x01010101) & c)
00346                goto schk1;
00347             if ((v - 0x01010101) & c)
00348                goto schk2;
00349             if (callback)
00350                if ((STB_SPRINTF_MIN - (int)(bf - buf)) < 4)
00351                   goto schk1;
00352             #ifdef STB_SPRINTF_NOUNALIGNED
00353                 if(((stbsp__uintptr)bf) & 3) {
00354                     bf[0] = f[0];
00355                     bf[1] = f[1];
00356                     bf[2] = f[2];
00357                     bf[3] = f[3];
00358                 } else
00359             #endif
00360             {
00361                 *(stbsp__uint32 *)bf = v;
00362             }
00363             bf += 4;
00364             f += 4;
00365          }
00366       }
00367    scandd:
00368 
00369       ++f;
00370 
00371       // ok, we have a percent, read the modifiers first
00372       fw = 0;
00373       pr = -1;
00374       fl = 0;
00375       tz = 0;
00376 
00377       // flags
00378       for (;;) {
00379          switch (f[0]) {
00380          // if we have left justify
00381          case '-':
00382             fl |= STBSP__LEFTJUST;
00383             ++f;
00384             continue;
00385          // if we have leading plus
00386          case '+':
00387             fl |= STBSP__LEADINGPLUS;
00388             ++f;
00389             continue;
00390          // if we have leading space
00391          case ' ':
00392             fl |= STBSP__LEADINGSPACE;
00393             ++f;
00394             continue;
00395          // if we have leading 0x
00396          case '#':
00397             fl |= STBSP__LEADING_0X;
00398             ++f;
00399             continue;
00400          // if we have thousand commas
00401          case '\'':
00402             fl |= STBSP__TRIPLET_COMMA;
00403             ++f;
00404             continue;
00405          // if we have kilo marker (none->kilo->kibi->jedec)
00406          case '$':
00407             if (fl & STBSP__METRIC_SUFFIX) {
00408                if (fl & STBSP__METRIC_1024) {
00409                   fl |= STBSP__METRIC_JEDEC;
00410                } else {
00411                   fl |= STBSP__METRIC_1024;
00412                }
00413             } else {
00414                fl |= STBSP__METRIC_SUFFIX;
00415             }
00416             ++f;
00417             continue;
00418          // if we don't want space between metric suffix and number
00419          case '_':
00420             fl |= STBSP__METRIC_NOSPACE;
00421             ++f;
00422             continue;
00423          // if we have leading zero
00424          case '0':
00425             fl |= STBSP__LEADINGZERO;
00426             ++f;
00427             goto flags_done;
00428          default: goto flags_done;
00429          }
00430       }
00431    flags_done:
00432 
00433       // get the field width
00434       if (f[0] == '*') {
00435          fw = va_arg(va, stbsp__uint32);
00436          ++f;
00437       } else {
00438          while ((f[0] >= '0') && (f[0] <= '9')) {
00439             fw = fw * 10 + f[0] - '0';
00440             f++;
00441          }
00442       }
00443       // get the precision
00444       if (f[0] == '.') {
00445          ++f;
00446          if (f[0] == '*') {
00447             pr = va_arg(va, stbsp__uint32);
00448             ++f;
00449          } else {
00450             pr = 0;
00451             while ((f[0] >= '0') && (f[0] <= '9')) {
00452                pr = pr * 10 + f[0] - '0';
00453                f++;
00454             }
00455          }
00456       }
00457 
00458       // handle integer size overrides
00459       switch (f[0]) {
00460       // are we halfwidth?
00461       case 'h':
00462          fl |= STBSP__HALFWIDTH;
00463          ++f;
00464          break;
00465       // are we 64-bit (unix style)
00466       case 'l':
00467          fl |= ((sizeof(long) == 8) ? STBSP__INTMAX : 0);
00468          ++f;
00469          if (f[0] == 'l') {
00470             fl |= STBSP__INTMAX;
00471             ++f;
00472          }
00473          break;
00474       // are we 64-bit on intmax? (c99)
00475       case 'j':
00476          fl |= (sizeof(size_t) == 8) ? STBSP__INTMAX : 0;
00477          ++f;
00478          break;
00479       // are we 64-bit on size_t or ptrdiff_t? (c99)
00480       case 'z':
00481          fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0;
00482          ++f;
00483          break;
00484       case 't':
00485          fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0;
00486          ++f;
00487          break;
00488       // are we 64-bit (msft style)
00489       case 'I':
00490          if ((f[1] == '6') && (f[2] == '4')) {
00491             fl |= STBSP__INTMAX;
00492             f += 3;
00493          } else if ((f[1] == '3') && (f[2] == '2')) {
00494             f += 3;
00495          } else {
00496             fl |= ((sizeof(void *) == 8) ? STBSP__INTMAX : 0);
00497             ++f;
00498          }
00499          break;
00500       default: break;
00501       }
00502 
00503       // handle each replacement
00504       switch (f[0]) {
00505          #define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307
00506          char num[STBSP__NUMSZ];
00507          char lead[8];
00508          char tail[8];
00509          char *s;
00510          char const *h;
00511          stbsp__uint32 l, n, cs;
00512          stbsp__uint64 n64;
00513 #ifndef STB_SPRINTF_NOFLOAT
00514          double fv;
00515 #endif
00516          stbsp__int32 dp;
00517          char const *sn;
00518 
00519       case 's':
00520          // get the string
00521          s = va_arg(va, char *);
00522          if (s == 0)
00523             s = (char *)"null";
00524          // get the length
00525          sn = s;
00526          for (;;) {
00527             if ((((stbsp__uintptr)sn) & 3) == 0)
00528                break;
00529          lchk:
00530             if (sn[0] == 0)
00531                goto ld;
00532             ++sn;
00533          }
00534          n = 0xffffffff;
00535          if (pr >= 0) {
00536             n = (stbsp__uint32)(sn - s);
00537             if (n >= (stbsp__uint32)pr)
00538                goto ld;
00539             n = ((stbsp__uint32)(pr - n)) >> 2;
00540          }
00541          while (n) {
00542             stbsp__uint32 v = *(stbsp__uint32 *)sn;
00543             if ((v - 0x01010101) & (~v) & 0x80808080UL)
00544                goto lchk;
00545             sn += 4;
00546             --n;
00547          }
00548          goto lchk;
00549       ld:
00550 
00551          l = (stbsp__uint32)(sn - s);
00552          // clamp to precision
00553          if (l > (stbsp__uint32)pr)
00554             l = pr;
00555          lead[0] = 0;
00556          tail[0] = 0;
00557          pr = 0;
00558          dp = 0;
00559          cs = 0;
00560          // copy the string in
00561          goto scopy;
00562 
00563       case 'c': // char
00564          // get the character
00565          s = num + STBSP__NUMSZ - 1;
00566          *s = (char)va_arg(va, int);
00567          l = 1;
00568          lead[0] = 0;
00569          tail[0] = 0;
00570          pr = 0;
00571          dp = 0;
00572          cs = 0;
00573          goto scopy;
00574 
00575       case 'n': // weird write-bytes specifier
00576       {
00577          int *d = va_arg(va, int *);
00578          *d = tlen + (int)(bf - buf);
00579       } break;
00580 
00581 #ifdef STB_SPRINTF_NOFLOAT
00582       case 'A':              // float
00583       case 'a':              // hex float
00584       case 'G':              // float
00585       case 'g':              // float
00586       case 'E':              // float
00587       case 'e':              // float
00588       case 'f':              // float
00589          va_arg(va, double); // eat it
00590          s = (char *)"No float";
00591          l = 8;
00592          lead[0] = 0;
00593          tail[0] = 0;
00594          pr = 0;
00595          dp = 0;
00596          cs = 0;
00597          goto scopy;
00598 #else
00599       case 'A': // hex float
00600       case 'a': // hex float
00601          h = (f[0] == 'A') ? hexu : hex;
00602          fv = va_arg(va, double);
00603          if (pr == -1)
00604             pr = 6; // default is 6
00605          // read the double into a string
00606          if (stbsp__real_to_parts((stbsp__int64 *)&n64, &dp, fv))
00607             fl |= STBSP__NEGATIVE;
00608 
00609          s = num + 64;
00610 
00611          stbsp__lead_sign(fl, lead);
00612 
00613          if (dp == -1023)
00614             dp = (n64) ? -1022 : 0;
00615          else
00616             n64 |= (((stbsp__uint64)1) << 52);
00617          n64 <<= (64 - 56);
00618          if (pr < 15)
00619             n64 += ((((stbsp__uint64)8) << 56) >> (pr * 4));
00620 // add leading chars
00621 
00622 #ifdef STB_SPRINTF_MSVC_MODE
00623          *s++ = '0';
00624          *s++ = 'x';
00625 #else
00626          lead[1 + lead[0]] = '0';
00627          lead[2 + lead[0]] = 'x';
00628          lead[0] += 2;
00629 #endif
00630          *s++ = h[(n64 >> 60) & 15];
00631          n64 <<= 4;
00632          if (pr)
00633             *s++ = stbsp__period;
00634          sn = s;
00635 
00636          // print the bits
00637          n = pr;
00638          if (n > 13)
00639             n = 13;
00640          if (pr > (stbsp__int32)n)
00641             tz = pr - n;
00642          pr = 0;
00643          while (n--) {
00644             *s++ = h[(n64 >> 60) & 15];
00645             n64 <<= 4;
00646          }
00647 
00648          // print the expo
00649          tail[1] = h[17];
00650          if (dp < 0) {
00651             tail[2] = '-';
00652             dp = -dp;
00653          } else
00654             tail[2] = '+';
00655          n = (dp >= 1000) ? 6 : ((dp >= 100) ? 5 : ((dp >= 10) ? 4 : 3));
00656          tail[0] = (char)n;
00657          for (;;) {
00658             tail[n] = '0' + dp % 10;
00659             if (n <= 3)
00660                break;
00661             --n;
00662             dp /= 10;
00663          }
00664 
00665          dp = (int)(s - sn);
00666          l = (int)(s - (num + 64));
00667          s = num + 64;
00668          cs = 1 + (3 << 24);
00669          goto scopy;
00670 
00671       case 'G': // float
00672       case 'g': // float
00673          h = (f[0] == 'G') ? hexu : hex;
00674          fv = va_arg(va, double);
00675          if (pr == -1)
00676             pr = 6;
00677          else if (pr == 0)
00678             pr = 1; // default is 6
00679          // read the double into a string
00680          if (stbsp__real_to_str(&sn, &l, num, &dp, fv, (pr - 1) | 0x80000000))
00681             fl |= STBSP__NEGATIVE;
00682 
00683          // clamp the precision and delete extra zeros after clamp
00684          n = pr;
00685          if (l > (stbsp__uint32)pr)
00686             l = pr;
00687          while ((l > 1) && (pr) && (sn[l - 1] == '0')) {
00688             --pr;
00689             --l;
00690          }
00691 
00692          // should we use %e
00693          if ((dp <= -4) || (dp > (stbsp__int32)n)) {
00694             if (pr > (stbsp__int32)l)
00695                pr = l - 1;
00696             else if (pr)
00697                --pr; // when using %e, there is one digit before the decimal
00698             goto doexpfromg;
00699          }
00700          // this is the insane action to get the pr to match %g semantics for %f
00701          if (dp > 0) {
00702             pr = (dp < (stbsp__int32)l) ? l - dp : 0;
00703          } else {
00704             pr = -dp + ((pr > (stbsp__int32)l) ? (stbsp__int32) l : pr);
00705          }
00706          goto dofloatfromg;
00707 
00708       case 'E': // float
00709       case 'e': // float
00710          h = (f[0] == 'E') ? hexu : hex;
00711          fv = va_arg(va, double);
00712          if (pr == -1)
00713             pr = 6; // default is 6
00714          // read the double into a string
00715          if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr | 0x80000000))
00716             fl |= STBSP__NEGATIVE;
00717       doexpfromg:
00718          tail[0] = 0;
00719          stbsp__lead_sign(fl, lead);
00720          if (dp == STBSP__SPECIAL) {
00721             s = (char *)sn;
00722             cs = 0;
00723             pr = 0;
00724             goto scopy;
00725          }
00726          s = num + 64;
00727          // handle leading chars
00728          *s++ = sn[0];
00729 
00730          if (pr)
00731             *s++ = stbsp__period;
00732 
00733          // handle after decimal
00734          if ((l - 1) > (stbsp__uint32)pr)
00735             l = pr + 1;
00736          for (n = 1; n < l; n++)
00737             *s++ = sn[n];
00738          // trailing zeros
00739          tz = pr - (l - 1);
00740          pr = 0;
00741          // dump expo
00742          tail[1] = h[0xe];
00743          dp -= 1;
00744          if (dp < 0) {
00745             tail[2] = '-';
00746             dp = -dp;
00747          } else
00748             tail[2] = '+';
00749 #ifdef STB_SPRINTF_MSVC_MODE
00750          n = 5;
00751 #else
00752          n = (dp >= 100) ? 5 : 4;
00753 #endif
00754          tail[0] = (char)n;
00755          for (;;) {
00756             tail[n] = '0' + dp % 10;
00757             if (n <= 3)
00758                break;
00759             --n;
00760             dp /= 10;
00761          }
00762          cs = 1 + (3 << 24); // how many tens
00763          goto flt_lead;
00764 
00765       case 'f': // float
00766          fv = va_arg(va, double);
00767       doafloat:
00768          // do kilos
00769          if (fl & STBSP__METRIC_SUFFIX) {
00770             double divisor;
00771             divisor = 1000.0f;
00772             if (fl & STBSP__METRIC_1024)
00773                divisor = 1024.0;
00774             while (fl < 0x4000000) {
00775                if ((fv < divisor) && (fv > -divisor))
00776                   break;
00777                fv /= divisor;
00778                fl += 0x1000000;
00779             }
00780          }
00781          if (pr == -1)
00782             pr = 6; // default is 6
00783          // read the double into a string
00784          if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr))
00785             fl |= STBSP__NEGATIVE;
00786       dofloatfromg:
00787          tail[0] = 0;
00788          stbsp__lead_sign(fl, lead);
00789          if (dp == STBSP__SPECIAL) {
00790             s = (char *)sn;
00791             cs = 0;
00792             pr = 0;
00793             goto scopy;
00794          }
00795          s = num + 64;
00796 
00797          // handle the three decimal varieties
00798          if (dp <= 0) {
00799             stbsp__int32 i;
00800             // handle 0.000*000xxxx
00801             *s++ = '0';
00802             if (pr)
00803                *s++ = stbsp__period;
00804             n = -dp;
00805             if ((stbsp__int32)n > pr)
00806                n = pr;
00807             i = n;
00808             while (i) {
00809                if ((((stbsp__uintptr)s) & 3) == 0)
00810                   break;
00811                *s++ = '0';
00812                --i;
00813             }
00814             while (i >= 4) {
00815                *(stbsp__uint32 *)s = 0x30303030;
00816                s += 4;
00817                i -= 4;
00818             }
00819             while (i) {
00820                *s++ = '0';
00821                --i;
00822             }
00823             if ((stbsp__int32)(l + n) > pr)
00824                l = pr - n;
00825             i = l;
00826             while (i) {
00827                *s++ = *sn++;
00828                --i;
00829             }
00830             tz = pr - (n + l);
00831             cs = 1 + (3 << 24); // how many tens did we write (for commas below)
00832          } else {
00833             cs = (fl & STBSP__TRIPLET_COMMA) ? ((600 - (stbsp__uint32)dp) % 3) : 0;
00834             if ((stbsp__uint32)dp >= l) {
00835                // handle xxxx000*000.0
00836                n = 0;
00837                for (;;) {
00838                   if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) {
00839                      cs = 0;
00840                      *s++ = stbsp__comma;
00841                   } else {
00842                      *s++ = sn[n];
00843                      ++n;
00844                      if (n >= l)
00845                         break;
00846                   }
00847                }
00848                if (n < (stbsp__uint32)dp) {
00849                   n = dp - n;
00850                   if ((fl & STBSP__TRIPLET_COMMA) == 0) {
00851                      while (n) {
00852                         if ((((stbsp__uintptr)s) & 3) == 0)
00853                            break;
00854                         *s++ = '0';
00855                         --n;
00856                      }
00857                      while (n >= 4) {
00858                         *(stbsp__uint32 *)s = 0x30303030;
00859                         s += 4;
00860                         n -= 4;
00861                      }
00862                   }
00863                   while (n) {
00864                      if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) {
00865                         cs = 0;
00866                         *s++ = stbsp__comma;
00867                      } else {
00868                         *s++ = '0';
00869                         --n;
00870                      }
00871                   }
00872                }
00873                cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens
00874                if (pr) {
00875                   *s++ = stbsp__period;
00876                   tz = pr;
00877                }
00878             } else {
00879                // handle xxxxx.xxxx000*000
00880                n = 0;
00881                for (;;) {
00882                   if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) {
00883                      cs = 0;
00884                      *s++ = stbsp__comma;
00885                   } else {
00886                      *s++ = sn[n];
00887                      ++n;
00888                      if (n >= (stbsp__uint32)dp)
00889                         break;
00890                   }
00891                }
00892                cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens
00893                if (pr)
00894                   *s++ = stbsp__period;
00895                if ((l - dp) > (stbsp__uint32)pr)
00896                   l = pr + dp;
00897                while (n < l) {
00898                   *s++ = sn[n];
00899                   ++n;
00900                }
00901                tz = pr - (l - dp);
00902             }
00903          }
00904          pr = 0;
00905 
00906          // handle k,m,g,t
00907          if (fl & STBSP__METRIC_SUFFIX) {
00908             char idx;
00909             idx = 1;
00910             if (fl & STBSP__METRIC_NOSPACE)
00911                idx = 0;
00912             tail[0] = idx;
00913             tail[1] = ' ';
00914             {
00915                if (fl >> 24) { // SI kilo is 'k', JEDEC and SI kibits are 'K'.
00916                   if (fl & STBSP__METRIC_1024)
00917                      tail[idx + 1] = "_KMGT"[fl >> 24];
00918                   else
00919                      tail[idx + 1] = "_kMGT"[fl >> 24];
00920                   idx++;
00921                   // If printing kibits and not in jedec, add the 'i'.
00922                   if (fl & STBSP__METRIC_1024 && !(fl & STBSP__METRIC_JEDEC)) {
00923                      tail[idx + 1] = 'i';
00924                      idx++;
00925                   }
00926                   tail[0] = idx;
00927                }
00928             }
00929          };
00930 
00931       flt_lead:
00932          // get the length that we copied
00933          l = (stbsp__uint32)(s - (num + 64));
00934          s = num + 64;
00935          goto scopy;
00936 #endif
00937 
00938       case 'B': // upper binary
00939       case 'b': // lower binary
00940          h = (f[0] == 'B') ? hexu : hex;
00941          lead[0] = 0;
00942          if (fl & STBSP__LEADING_0X) {
00943             lead[0] = 2;
00944             lead[1] = '0';
00945             lead[2] = h[0xb];
00946          }
00947          l = (8 << 4) | (1 << 8);
00948          goto radixnum;
00949 
00950       case 'o': // octal
00951          h = hexu;
00952          lead[0] = 0;
00953          if (fl & STBSP__LEADING_0X) {
00954             lead[0] = 1;
00955             lead[1] = '0';
00956          }
00957          l = (3 << 4) | (3 << 8);
00958          goto radixnum;
00959 
00960       case 'p': // pointer
00961          fl |= (sizeof(void *) == 8) ? STBSP__INTMAX : 0;
00962          pr = sizeof(void *) * 2;
00963          fl &= ~STBSP__LEADINGZERO; // 'p' only prints the pointer with zeros
00964                                     // fall through - to X
00965 
00966       case 'X': // upper hex
00967       case 'x': // lower hex
00968          h = (f[0] == 'X') ? hexu : hex;
00969          l = (4 << 4) | (4 << 8);
00970          lead[0] = 0;
00971          if (fl & STBSP__LEADING_0X) {
00972             lead[0] = 2;
00973             lead[1] = '0';
00974             lead[2] = h[16];
00975          }
00976       radixnum:
00977          // get the number
00978          if (fl & STBSP__INTMAX)
00979             n64 = va_arg(va, stbsp__uint64);
00980          else
00981             n64 = va_arg(va, stbsp__uint32);
00982 
00983          s = num + STBSP__NUMSZ;
00984          dp = 0;
00985          // clear tail, and clear leading if value is zero
00986          tail[0] = 0;
00987          if (n64 == 0) {
00988             lead[0] = 0;
00989             if (pr == 0) {
00990                l = 0;
00991                cs = (((l >> 4) & 15)) << 24;
00992                goto scopy;
00993             }
00994          }
00995          // convert to string
00996          for (;;) {
00997             *--s = h[n64 & ((1 << (l >> 8)) - 1)];
00998             n64 >>= (l >> 8);
00999             if (!((n64) || ((stbsp__int32)((num + STBSP__NUMSZ) - s) < pr)))
01000                break;
01001             if (fl & STBSP__TRIPLET_COMMA) {
01002                ++l;
01003                if ((l & 15) == ((l >> 4) & 15)) {
01004                   l &= ~15;
01005                   *--s = stbsp__comma;
01006                }
01007             }
01008          };
01009          // get the tens and the comma pos
01010          cs = (stbsp__uint32)((num + STBSP__NUMSZ) - s) + ((((l >> 4) & 15)) << 24);
01011          // get the length that we copied
01012          l = (stbsp__uint32)((num + STBSP__NUMSZ) - s);
01013          // copy it
01014          goto scopy;
01015 
01016       case 'u': // unsigned
01017       case 'i':
01018       case 'd': // integer
01019          // get the integer and abs it
01020          if (fl & STBSP__INTMAX) {
01021             stbsp__int64 i64 = va_arg(va, stbsp__int64);
01022             n64 = (stbsp__uint64)i64;
01023             if ((f[0] != 'u') && (i64 < 0)) {
01024                n64 = (stbsp__uint64)-i64;
01025                fl |= STBSP__NEGATIVE;
01026             }
01027          } else {
01028             stbsp__int32 i = va_arg(va, stbsp__int32);
01029             n64 = (stbsp__uint32)i;
01030             if ((f[0] != 'u') && (i < 0)) {
01031                n64 = (stbsp__uint32)-i;
01032                fl |= STBSP__NEGATIVE;
01033             }
01034          }
01035 
01036 #ifndef STB_SPRINTF_NOFLOAT
01037          if (fl & STBSP__METRIC_SUFFIX) {
01038             if (n64 < 1024)
01039                pr = 0;
01040             else if (pr == -1)
01041                pr = 1;
01042             fv = (double)(stbsp__int64)n64;
01043             goto doafloat;
01044          }
01045 #endif
01046 
01047          // convert to string
01048          s = num + STBSP__NUMSZ;
01049          l = 0;
01050 
01051          for (;;) {
01052             // do in 32-bit chunks (avoid lots of 64-bit divides even with constant denominators)
01053             char *o = s - 8;
01054             if (n64 >= 100000000) {
01055                n = (stbsp__uint32)(n64 % 100000000);
01056                n64 /= 100000000;
01057             } else {
01058                n = (stbsp__uint32)n64;
01059                n64 = 0;
01060             }
01061             if ((fl & STBSP__TRIPLET_COMMA) == 0) {
01062                do {
01063                   s -= 2;
01064                   *(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2];
01065                   n /= 100;
01066                } while (n);
01067             }
01068             while (n) {
01069                if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) {
01070                   l = 0;
01071                   *--s = stbsp__comma;
01072                   --o;
01073                } else {
01074                   *--s = (char)(n % 10) + '0';
01075                   n /= 10;
01076                }
01077             }
01078             if (n64 == 0) {
01079                if ((s[0] == '0') && (s != (num + STBSP__NUMSZ)))
01080                   ++s;
01081                break;
01082             }
01083             while (s != o)
01084                if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) {
01085                   l = 0;
01086                   *--s = stbsp__comma;
01087                   --o;
01088                } else {
01089                   *--s = '0';
01090                }
01091          }
01092 
01093          tail[0] = 0;
01094          stbsp__lead_sign(fl, lead);
01095 
01096          // get the length that we copied
01097          l = (stbsp__uint32)((num + STBSP__NUMSZ) - s);
01098          if (l == 0) {
01099             *--s = '0';
01100             l = 1;
01101          }
01102          cs = l + (3 << 24);
01103          if (pr < 0)
01104             pr = 0;
01105 
01106       scopy:
01107          // get fw=leading/trailing space, pr=leading zeros
01108          if (pr < (stbsp__int32)l)
01109             pr = l;
01110          n = pr + lead[0] + tail[0] + tz;
01111          if (fw < (stbsp__int32)n)
01112             fw = n;
01113          fw -= n;
01114          pr -= l;
01115 
01116          // handle right justify and leading zeros
01117          if ((fl & STBSP__LEFTJUST) == 0) {
01118             if (fl & STBSP__LEADINGZERO) // if leading zeros, everything is in pr
01119             {
01120                pr = (fw > pr) ? fw : pr;
01121                fw = 0;
01122             } else {
01123                fl &= ~STBSP__TRIPLET_COMMA; // if no leading zeros, then no commas
01124             }
01125          }
01126 
01127          // copy the spaces and/or zeros
01128          if (fw + pr) {
01129             stbsp__int32 i;
01130             stbsp__uint32 c;
01131 
01132             // copy leading spaces (or when doing %8.4d stuff)
01133             if ((fl & STBSP__LEFTJUST) == 0)
01134                while (fw > 0) {
01135                   stbsp__cb_buf_clamp(i, fw);
01136                   fw -= i;
01137                   while (i) {
01138                      if ((((stbsp__uintptr)bf) & 3) == 0)
01139                         break;
01140                      *bf++ = ' ';
01141                      --i;
01142                   }
01143                   while (i >= 4) {
01144                      *(stbsp__uint32 *)bf = 0x20202020;
01145                      bf += 4;
01146                      i -= 4;
01147                   }
01148                   while (i) {
01149                      *bf++ = ' ';
01150                      --i;
01151                   }
01152                   stbsp__chk_cb_buf(1);
01153                }
01154 
01155             // copy leader
01156             sn = lead + 1;
01157             while (lead[0]) {
01158                stbsp__cb_buf_clamp(i, lead[0]);
01159                lead[0] -= (char)i;
01160                while (i) {
01161                   *bf++ = *sn++;
01162                   --i;
01163                }
01164                stbsp__chk_cb_buf(1);
01165             }
01166 
01167             // copy leading zeros
01168             c = cs >> 24;
01169             cs &= 0xffffff;
01170             cs = (fl & STBSP__TRIPLET_COMMA) ? ((stbsp__uint32)(c - ((pr + cs) % (c + 1)))) : 0;
01171             while (pr > 0) {
01172                stbsp__cb_buf_clamp(i, pr);
01173                pr -= i;
01174                if ((fl & STBSP__TRIPLET_COMMA) == 0) {
01175                   while (i) {
01176                      if ((((stbsp__uintptr)bf) & 3) == 0)
01177                         break;
01178                      *bf++ = '0';
01179                      --i;
01180                   }
01181                   while (i >= 4) {
01182                      *(stbsp__uint32 *)bf = 0x30303030;
01183                      bf += 4;
01184                      i -= 4;
01185                   }
01186                }
01187                while (i) {
01188                   if ((fl & STBSP__TRIPLET_COMMA) && (cs++ == c)) {
01189                      cs = 0;
01190                      *bf++ = stbsp__comma;
01191                   } else
01192                      *bf++ = '0';
01193                   --i;
01194                }
01195                stbsp__chk_cb_buf(1);
01196             }
01197          }
01198 
01199          // copy leader if there is still one
01200          sn = lead + 1;
01201          while (lead[0]) {
01202             stbsp__int32 i;
01203             stbsp__cb_buf_clamp(i, lead[0]);
01204             lead[0] -= (char)i;
01205             while (i) {
01206                *bf++ = *sn++;
01207                --i;
01208             }
01209             stbsp__chk_cb_buf(1);
01210          }
01211 
01212          // copy the string
01213          n = l;
01214          while (n) {
01215             stbsp__int32 i;
01216             stbsp__cb_buf_clamp(i, n);
01217             n -= i;
01218             STBSP__UNALIGNED(while (i >= 4) {
01219                *(stbsp__uint32 *)bf = *(stbsp__uint32 *)s;
01220                bf += 4;
01221                s += 4;
01222                i -= 4;
01223             })
01224             while (i) {
01225                *bf++ = *s++;
01226                --i;
01227             }
01228             stbsp__chk_cb_buf(1);
01229          }
01230 
01231          // copy trailing zeros
01232          while (tz) {
01233             stbsp__int32 i;
01234             stbsp__cb_buf_clamp(i, tz);
01235             tz -= i;
01236             while (i) {
01237                if ((((stbsp__uintptr)bf) & 3) == 0)
01238                   break;
01239                *bf++ = '0';
01240                --i;
01241             }
01242             while (i >= 4) {
01243                *(stbsp__uint32 *)bf = 0x30303030;
01244                bf += 4;
01245                i -= 4;
01246             }
01247             while (i) {
01248                *bf++ = '0';
01249                --i;
01250             }
01251             stbsp__chk_cb_buf(1);
01252          }
01253 
01254          // copy tail if there is one
01255          sn = tail + 1;
01256          while (tail[0]) {
01257             stbsp__int32 i;
01258             stbsp__cb_buf_clamp(i, tail[0]);
01259             tail[0] -= (char)i;
01260             while (i) {
01261                *bf++ = *sn++;
01262                --i;
01263             }
01264             stbsp__chk_cb_buf(1);
01265          }
01266 
01267          // handle the left justify
01268          if (fl & STBSP__LEFTJUST)
01269             if (fw > 0) {
01270                while (fw) {
01271                   stbsp__int32 i;
01272                   stbsp__cb_buf_clamp(i, fw);
01273                   fw -= i;
01274                   while (i) {
01275                      if ((((stbsp__uintptr)bf) & 3) == 0)
01276                         break;
01277                      *bf++ = ' ';
01278                      --i;
01279                   }
01280                   while (i >= 4) {
01281                      *(stbsp__uint32 *)bf = 0x20202020;
01282                      bf += 4;
01283                      i -= 4;
01284                   }
01285                   while (i--)
01286                      *bf++ = ' ';
01287                   stbsp__chk_cb_buf(1);
01288                }
01289             }
01290          break;
01291 
01292       default: // unknown, just copy code
01293          s = num + STBSP__NUMSZ - 1;
01294          *s = f[0];
01295          l = 1;
01296          fw = fl = 0;
01297          lead[0] = 0;
01298          tail[0] = 0;
01299          pr = 0;
01300          dp = 0;
01301          cs = 0;
01302          goto scopy;
01303       }
01304       ++f;
01305    }
01306 endfmt:
01307 
01308    if (!callback)
01309       *bf = 0;
01310    else
01311       stbsp__flush_cb();
01312 
01313 done:
01314    return tlen + (int)(bf - buf);
01315 }
01316 
01317 // cleanup
01318 #undef STBSP__LEFTJUST
01319 #undef STBSP__LEADINGPLUS
01320 #undef STBSP__LEADINGSPACE
01321 #undef STBSP__LEADING_0X
01322 #undef STBSP__LEADINGZERO
01323 #undef STBSP__INTMAX
01324 #undef STBSP__TRIPLET_COMMA
01325 #undef STBSP__NEGATIVE
01326 #undef STBSP__METRIC_SUFFIX
01327 #undef STBSP__NUMSZ
01328 #undef stbsp__chk_cb_bufL
01329 #undef stbsp__chk_cb_buf
01330 #undef stbsp__flush_cb
01331 #undef stbsp__cb_buf_clamp
01332 
01333 // ============================================================================
01334 //   wrapper functions
01335 
01336 STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...)
01337 {
01338    int result;
01339    va_list va;
01340    va_start(va, fmt);
01341    result = STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va);
01342    va_end(va);
01343    return result;
01344 }
01345 
01346 typedef struct stbsp__context {
01347    char *buf;
01348    int count;
01349    char tmp[STB_SPRINTF_MIN];
01350 } stbsp__context;
01351 
01352 static char *stbsp__clamp_callback(char *buf, void *user, int len)
01353 {
01354    stbsp__context *c = (stbsp__context *)user;
01355 
01356    if (len > c->count)
01357       len = c->count;
01358 
01359    if (len) {
01360       if (buf != c->buf) {
01361          char *s, *d, *se;
01362          d = c->buf;
01363          s = buf;
01364          se = buf + len;
01365          do {
01366             *d++ = *s++;
01367          } while (s < se);
01368       }
01369       c->buf += len;
01370       c->count -= len;
01371    }
01372 
01373    if (c->count <= 0)
01374       return 0;
01375    return (c->count >= STB_SPRINTF_MIN) ? c->buf : c->tmp; // go direct into buffer if you can
01376 }
01377 
01378 static char * stbsp__count_clamp_callback( char * buf, void * user, int len )
01379 {
01380    stbsp__context * c = (stbsp__context*)user;
01381 
01382    c->count += len;
01383    return c->tmp; // go direct into buffer if you can
01384 }
01385 
01386 STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, char const * fmt, va_list va )
01387 {
01388    stbsp__context c;
01389    int l;
01390 
01391    if ( (count == 0) && !buf )
01392    {
01393       c.count = 0;
01394 
01395       STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__count_clamp_callback, &c, c.tmp, fmt, va );
01396       l = c.count;
01397    }
01398    else
01399    {
01400       if ( count == 0 )
01401          return 0;
01402 
01403       c.buf = buf;
01404       c.count = count;
01405 
01406       STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__clamp_callback, &c, stbsp__clamp_callback(0,&c,0), fmt, va );
01407 
01408       // zero-terminate
01409       l = (int)( c.buf - buf );
01410       if ( l >= count ) // should never be greater, only equal (or less) than count
01411          l = count - 1;
01412       buf[l] = 0;
01413    }
01414 
01415    return l;
01416 }
01417 
01418 STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...)
01419 {
01420    int result;
01421    va_list va;
01422    va_start(va, fmt);
01423 
01424    result = STB_SPRINTF_DECORATE(vsnprintf)(buf, count, fmt, va);
01425    va_end(va);
01426 
01427    return result;
01428 }
01429 
01430 STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va)
01431 {
01432    return STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va);
01433 }
01434 
01435 // =======================================================================
01436 //   low level float utility functions
01437 
01438 #ifndef STB_SPRINTF_NOFLOAT
01439 
01440 // copies d to bits w/ strict aliasing (this compiles to nothing on /Ox)
01441 #define STBSP__COPYFP(dest, src)                   \
01442    {                                               \
01443       int cn;                                      \
01444       for (cn = 0; cn < 8; cn++)                   \
01445          ((char *)&dest)[cn] = ((char *)&src)[cn]; \
01446    }
01447 
01448 // get float info
01449 static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value)
01450 {
01451    double d;
01452    stbsp__int64 b = 0;
01453 
01454    // load value and round at the frac_digits
01455    d = value;
01456 
01457    STBSP__COPYFP(b, d);
01458 
01459    *bits = b & ((((stbsp__uint64)1) << 52) - 1);
01460    *expo = (stbsp__int32)(((b >> 52) & 2047) - 1023);
01461 
01462    return (stbsp__int32)((stbsp__uint64) b >> 63);
01463 }
01464 
01465 static double const stbsp__bot[23] = {
01466    1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, 1e+010, 1e+011,
01467    1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, 1e+020, 1e+021, 1e+022
01468 };
01469 static double const stbsp__negbot[22] = {
01470    1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009, 1e-010, 1e-011,
01471    1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018, 1e-019, 1e-020, 1e-021, 1e-022
01472 };
01473 static double const stbsp__negboterr[22] = {
01474    -5.551115123125783e-018,  -2.0816681711721684e-019, -2.0816681711721686e-020, -4.7921736023859299e-021, -8.1803053914031305e-022, 4.5251888174113741e-023,
01475    4.5251888174113739e-024,  -2.0922560830128471e-025, -6.2281591457779853e-026, -3.6432197315497743e-027, 6.0503030718060191e-028,  2.0113352370744385e-029,
01476    -3.0373745563400371e-030, 1.1806906454401013e-032,  -7.7705399876661076e-032, 2.0902213275965398e-033,  -7.1542424054621921e-034, -7.1542424054621926e-035,
01477    2.4754073164739869e-036,  5.4846728545790429e-037,  9.2462547772103625e-038,  -4.8596774326570872e-039
01478 };
01479 static double const stbsp__top[13] = {
01480    1e+023, 1e+046, 1e+069, 1e+092, 1e+115, 1e+138, 1e+161, 1e+184, 1e+207, 1e+230, 1e+253, 1e+276, 1e+299
01481 };
01482 static double const stbsp__negtop[13] = {
01483    1e-023, 1e-046, 1e-069, 1e-092, 1e-115, 1e-138, 1e-161, 1e-184, 1e-207, 1e-230, 1e-253, 1e-276, 1e-299
01484 };
01485 static double const stbsp__toperr[13] = {
01486    8388608,
01487    6.8601809640529717e+028,
01488    -7.253143638152921e+052,
01489    -4.3377296974619174e+075,
01490    -1.5559416129466825e+098,
01491    -3.2841562489204913e+121,
01492    -3.7745893248228135e+144,
01493    -1.7356668416969134e+167,
01494    -3.8893577551088374e+190,
01495    -9.9566444326005119e+213,
01496    6.3641293062232429e+236,
01497    -5.2069140800249813e+259,
01498    -5.2504760255204387e+282
01499 };
01500 static double const stbsp__negtoperr[13] = {
01501    3.9565301985100693e-040,  -2.299904345391321e-063,  3.6506201437945798e-086,  1.1875228833981544e-109,
01502    -5.0644902316928607e-132, -6.7156837247865426e-155, -2.812077463003139e-178,  -5.7778912386589953e-201,
01503    7.4997100559334532e-224,  -4.6439668915134491e-247, -6.3691100762962136e-270, -9.436808465446358e-293,
01504    8.0970921678014997e-317
01505 };
01506 
01507 #if defined(_MSC_VER) && (_MSC_VER <= 1200)
01508 static stbsp__uint64 const stbsp__powten[20] = {
01509    1,
01510    10,
01511    100,
01512    1000,
01513    10000,
01514    100000,
01515    1000000,
01516    10000000,
01517    100000000,
01518    1000000000,
01519    10000000000,
01520    100000000000,
01521    1000000000000,
01522    10000000000000,
01523    100000000000000,
01524    1000000000000000,
01525    10000000000000000,
01526    100000000000000000,
01527    1000000000000000000,
01528    10000000000000000000U
01529 };
01530 #define stbsp__tento19th ((stbsp__uint64)1000000000000000000)
01531 #else
01532 static stbsp__uint64 const stbsp__powten[20] = {
01533    1,
01534    10,
01535    100,
01536    1000,
01537    10000,
01538    100000,
01539    1000000,
01540    10000000,
01541    100000000,
01542    1000000000,
01543    10000000000ULL,
01544    100000000000ULL,
01545    1000000000000ULL,
01546    10000000000000ULL,
01547    100000000000000ULL,
01548    1000000000000000ULL,
01549    10000000000000000ULL,
01550    100000000000000000ULL,
01551    1000000000000000000ULL,
01552    10000000000000000000ULL
01553 };
01554 #define stbsp__tento19th (1000000000000000000ULL)
01555 #endif
01556 
01557 #define stbsp__ddmulthi(oh, ol, xh, yh)                            \
01558    {                                                               \
01559       double ahi = 0, alo, bhi = 0, blo;                           \
01560       stbsp__int64 bt;                                             \
01561       oh = xh * yh;                                                \
01562       STBSP__COPYFP(bt, xh);                                       \
01563       bt &= ((~(stbsp__uint64)0) << 27);                           \
01564       STBSP__COPYFP(ahi, bt);                                      \
01565       alo = xh - ahi;                                              \
01566       STBSP__COPYFP(bt, yh);                                       \
01567       bt &= ((~(stbsp__uint64)0) << 27);                           \
01568       STBSP__COPYFP(bhi, bt);                                      \
01569       blo = yh - bhi;                                              \
01570       ol = ((ahi * bhi - oh) + ahi * blo + alo * bhi) + alo * blo; \
01571    }
01572 
01573 #define stbsp__ddtoS64(ob, xh, xl)          \
01574    {                                        \
01575       double ahi = 0, alo, vh, t;           \
01576       ob = (stbsp__int64)ph;                \
01577       vh = (double)ob;                      \
01578       ahi = (xh - vh);                      \
01579       t = (ahi - xh);                       \
01580       alo = (xh - (ahi - t)) - (vh + t);    \
01581       ob += (stbsp__int64)(ahi + alo + xl); \
01582    }
01583 
01584 #define stbsp__ddrenorm(oh, ol) \
01585    {                            \
01586       double s;                 \
01587       s = oh + ol;              \
01588       ol = ol - (s - oh);       \
01589       oh = s;                   \
01590    }
01591 
01592 #define stbsp__ddmultlo(oh, ol, xh, xl, yh, yl) ol = ol + (xh * yl + xl * yh);
01593 
01594 #define stbsp__ddmultlos(oh, ol, xh, yl) ol = ol + (xh * yl);
01595 
01596 static void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__int32 power) // power can be -323 to +350
01597 {
01598    double ph, pl;
01599    if ((power >= 0) && (power <= 22)) {
01600       stbsp__ddmulthi(ph, pl, d, stbsp__bot[power]);
01601    } else {
01602       stbsp__int32 e, et, eb;
01603       double p2h, p2l;
01604 
01605       e = power;
01606       if (power < 0)
01607          e = -e;
01608       et = (e * 0x2c9) >> 14; /* %23 */
01609       if (et > 13)
01610          et = 13;
01611       eb = e - (et * 23);
01612 
01613       ph = d;
01614       pl = 0.0;
01615       if (power < 0) {
01616          if (eb) {
01617             --eb;
01618             stbsp__ddmulthi(ph, pl, d, stbsp__negbot[eb]);
01619             stbsp__ddmultlos(ph, pl, d, stbsp__negboterr[eb]);
01620          }
01621          if (et) {
01622             stbsp__ddrenorm(ph, pl);
01623             --et;
01624             stbsp__ddmulthi(p2h, p2l, ph, stbsp__negtop[et]);
01625             stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__negtop[et], stbsp__negtoperr[et]);
01626             ph = p2h;
01627             pl = p2l;
01628          }
01629       } else {
01630          if (eb) {
01631             e = eb;
01632             if (eb > 22)
01633                eb = 22;
01634             e -= eb;
01635             stbsp__ddmulthi(ph, pl, d, stbsp__bot[eb]);
01636             if (e) {
01637                stbsp__ddrenorm(ph, pl);
01638                stbsp__ddmulthi(p2h, p2l, ph, stbsp__bot[e]);
01639                stbsp__ddmultlos(p2h, p2l, stbsp__bot[e], pl);
01640                ph = p2h;
01641                pl = p2l;
01642             }
01643          }
01644          if (et) {
01645             stbsp__ddrenorm(ph, pl);
01646             --et;
01647             stbsp__ddmulthi(p2h, p2l, ph, stbsp__top[et]);
01648             stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__top[et], stbsp__toperr[et]);
01649             ph = p2h;
01650             pl = p2l;
01651          }
01652       }
01653    }
01654    stbsp__ddrenorm(ph, pl);
01655    *ohi = ph;
01656    *olo = pl;
01657 }
01658 
01659 // given a float value, returns the significant bits in bits, and the position of the
01660 //   decimal point in decimal_pos.  +/-INF and NAN are specified by special values
01661 //   returned in the decimal_pos parameter.
01662 // frac_digits is absolute normally, but if you want from first significant digits (got %g and %e), or in 0x80000000
01663 static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits)
01664 {
01665    double d;
01666    stbsp__int64 bits = 0;
01667    stbsp__int32 expo, e, ng, tens;
01668 
01669    d = value;
01670    STBSP__COPYFP(bits, d);
01671    expo = (stbsp__int32)((bits >> 52) & 2047);
01672    ng = (stbsp__int32)((stbsp__uint64) bits >> 63);
01673    if (ng)
01674       d = -d;
01675 
01676    if (expo == 2047) // is nan or inf?
01677    {
01678       *start = (bits & ((((stbsp__uint64)1) << 52) - 1)) ? "NaN" : "Inf";
01679       *decimal_pos = STBSP__SPECIAL;
01680       *len = 3;
01681       return ng;
01682    }
01683 
01684    if (expo == 0) // is zero or denormal
01685    {
01686       if ((bits << 1) == 0) // do zero
01687       {
01688          *decimal_pos = 1;
01689          *start = out;
01690          out[0] = '0';
01691          *len = 1;
01692          return ng;
01693       }
01694       // find the right expo for denormals
01695       {
01696          stbsp__int64 v = ((stbsp__uint64)1) << 51;
01697          while ((bits & v) == 0) {
01698             --expo;
01699             v >>= 1;
01700          }
01701       }
01702    }
01703 
01704    // find the decimal exponent as well as the decimal bits of the value
01705    {
01706       double ph, pl;
01707 
01708       // log10 estimate - very specifically tweaked to hit or undershoot by no more than 1 of log10 of all expos 1..2046
01709       tens = expo - 1023;
01710       tens = (tens < 0) ? ((tens * 617) / 2048) : (((tens * 1233) / 4096) + 1);
01711 
01712       // move the significant bits into position and stick them into an int
01713       stbsp__raise_to_power10(&ph, &pl, d, 18 - tens);
01714 
01715       // get full as much precision from double-double as possible
01716       stbsp__ddtoS64(bits, ph, pl);
01717 
01718       // check if we undershot
01719       if (((stbsp__uint64)bits) >= stbsp__tento19th)
01720          ++tens;
01721    }
01722 
01723    // now do the rounding in integer land
01724    frac_digits = (frac_digits & 0x80000000) ? ((frac_digits & 0x7ffffff) + 1) : (tens + frac_digits);
01725    if ((frac_digits < 24)) {
01726       stbsp__uint32 dg = 1;
01727       if ((stbsp__uint64)bits >= stbsp__powten[9])
01728          dg = 10;
01729       while ((stbsp__uint64)bits >= stbsp__powten[dg]) {
01730          ++dg;
01731          if (dg == 20)
01732             goto noround;
01733       }
01734       if (frac_digits < dg) {
01735          stbsp__uint64 r;
01736          // add 0.5 at the right position and round
01737          e = dg - frac_digits;
01738          if ((stbsp__uint32)e >= 24)
01739             goto noround;
01740          r = stbsp__powten[e];
01741          bits = bits + (r / 2);
01742          if ((stbsp__uint64)bits >= stbsp__powten[dg])
01743             ++tens;
01744          bits /= r;
01745       }
01746    noround:;
01747    }
01748 
01749    // kill long trailing runs of zeros
01750    if (bits) {
01751       stbsp__uint32 n;
01752       for (;;) {
01753          if (bits <= 0xffffffff)
01754             break;
01755          if (bits % 1000)
01756             goto donez;
01757          bits /= 1000;
01758       }
01759       n = (stbsp__uint32)bits;
01760       while ((n % 1000) == 0)
01761          n /= 1000;
01762       bits = n;
01763    donez:;
01764    }
01765 
01766    // convert to string
01767    out += 64;
01768    e = 0;
01769    for (;;) {
01770       stbsp__uint32 n;
01771       char *o = out - 8;
01772       // do the conversion in chunks of U32s (avoid most 64-bit divides, worth it, constant denomiators be damned)
01773       if (bits >= 100000000) {
01774          n = (stbsp__uint32)(bits % 100000000);
01775          bits /= 100000000;
01776       } else {
01777          n = (stbsp__uint32)bits;
01778          bits = 0;
01779       }
01780       while (n) {
01781          out -= 2;
01782          *(stbsp__uint16 *)out = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2];
01783          n /= 100;
01784          e += 2;
01785       }
01786       if (bits == 0) {
01787          if ((e) && (out[0] == '0')) {
01788             ++out;
01789             --e;
01790          }
01791          break;
01792       }
01793       while (out != o) {
01794          *--out = '0';
01795          ++e;
01796       }
01797    }
01798 
01799    *decimal_pos = tens;
01800    *start = out;
01801    *len = e;
01802    return ng;
01803 }
01804 
01805 #undef stbsp__ddmulthi
01806 #undef stbsp__ddrenorm
01807 #undef stbsp__ddmultlo
01808 #undef stbsp__ddmultlos
01809 #undef STBSP__SPECIAL
01810 #undef STBSP__COPYFP
01811 
01812 #endif // STB_SPRINTF_NOFLOAT
01813 
01814 // clean up
01815 #undef stbsp__uint16
01816 #undef stbsp__uint32
01817 #undef stbsp__int32
01818 #undef stbsp__uint64
01819 #undef stbsp__int64
01820 #undef STBSP__UNALIGNED
01821 
01822 #endif // STB_SPRINTF_IMPLEMENTATION
01823 
01824 /*
01825 ------------------------------------------------------------------------------
01826 This software is available under 2 licenses -- choose whichever you prefer.
01827 ------------------------------------------------------------------------------
01828 ALTERNATIVE A - MIT License
01829 Copyright (c) 2017 Sean Barrett
01830 Permission is hereby granted, free of charge, to any person obtaining a copy of
01831 this software and associated documentation files (the "Software"), to deal in
01832 the Software without restriction, including without limitation the rights to
01833 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
01834 of the Software, and to permit persons to whom the Software is furnished to do
01835 so, subject to the following conditions:
01836 The above copyright notice and this permission notice shall be included in all
01837 copies or substantial portions of the Software.
01838 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
01839 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
01840 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
01841 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
01842 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
01843 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
01844 SOFTWARE.
01845 ------------------------------------------------------------------------------
01846 ALTERNATIVE B - Public Domain (www.unlicense.org)
01847 This is free and unencumbered software released into the public domain.
01848 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
01849 software, either in source code form or as a compiled binary, for any purpose,
01850 commercial or non-commercial, and by any means.
01851 In jurisdictions that recognize copyright laws, the author or authors of this
01852 software dedicate any and all copyright interest in the software to the public
01853 domain. We make this dedication for the benefit of the public at large and to
01854 the detriment of our heirs and successors. We intend this dedication to be an
01855 overt act of relinquishment in perpetuity of all present and future rights to
01856 this software under copyright law.
01857 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
01858 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
01859 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
01860 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
01861 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
01862 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
01863 ------------------------------------------------------------------------------
01864 */
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines