1 // stb_sprintf - v1.06 - public domain snprintf() implementation
2 // originally by Jeff Roberts / RAD Game Tools, 2015/10/20
3 // http://github.com/nothings/stb
4 //
5 // allowed types:  sc uidBboXx p AaGgEef n
6 // lengths      :  h ll j z t I64 I32 I
7 //
8 // Contributors:
9 //    Fabian "ryg" Giesen (reformatting)
10 //
11 // Contributors (bugfixes):
12 //    github:d26435
13 //    github:trex78
14 //    github:account-login
15 //    Jari Komppa (SI suffixes)
16 //    Rohit Nirmal
17 //    Marcin Wojdyr
18 //    Leonard Ritter
19 //    Stefano Zanotti
20 //    Adam Allison
21 //
22 // LICENSE:
23 //
24 //   See end of file for license information.
25 
26 #ifndef STB_SPRINTF_H_INCLUDE
27 #define STB_SPRINTF_H_INCLUDE
28 
29 /*
30 Single file sprintf replacement.
31 
32 Originally written by Jeff Roberts at RAD Game Tools - 2015/10/20.
33 Hereby placed in public domain.
34 
35 This is a full sprintf replacement that supports everything that
36 the C runtime sprintfs support, including float/double, 64-bit integers,
37 hex floats, field parameters (%*.*d stuff), length reads backs, etc.
38 
39 Why would you need this if sprintf already exists?  Well, first off,
40 it's *much* faster (see below). It's also much smaller than the CRT
41 versions code-space-wise. We've also added some simple improvements
42 that are super handy (commas in thousands, callbacks at buffer full,
43 for example). Finally, the format strings for MSVC and GCC differ
44 for 64-bit integers (among other small things), so this lets you use
45 the same format strings in cross platform code.
46 
47 It uses the standard single file trick of being both the header file
48 and the source itself. If you just include it normally, you just get
49 the header file function definitions. To get the code, you include
50 it from a C or C++ file and define STB_SPRINTF_IMPLEMENTATION first.
51 
52 It only uses va_args macros from the C runtime to do it's work. It
53 does cast doubles to S64s and shifts and divides U64s, which does
54 drag in CRT code on most platforms.
55 
56 It compiles to roughly 8K with float support, and 4K without.
57 As a comparison, when using MSVC static libs, calling sprintf drags
58 in 16K.
59 
60 API:
61 ====
62 int stbsp_sprintf( char * buf, char const * fmt, ... )
63 int stbsp_snprintf( char * buf, int count, char const * fmt, ... )
64   Convert an arg list into a buffer.  stbsp_snprintf always returns
65   a zero-terminated string (unlike regular snprintf).
66 
67 int stbsp_vsprintf( char * buf, char const * fmt, va_list va )
68 int stbsp_vsnprintf( char * buf, int count, char const * fmt, va_list va )
69   Convert a va_list arg list into a buffer.  stbsp_vsnprintf always returns
70   a zero-terminated string (unlike regular snprintf).
71 
72 int stbsp_vsprintfcb( STBSP_SPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va )
73     typedef char * STBSP_SPRINTFCB( char const * buf, void * user, int len );
74   Convert into a buffer, calling back every STB_SPRINTF_MIN chars.
75   Your callback can then copy the chars out, print them or whatever.
76   This function is actually the workhorse for everything else.
77   The buffer you pass in must hold at least STB_SPRINTF_MIN characters.
78     // you return the next buffer to use or 0 to stop converting
79 
80 void stbsp_set_separators( char comma, char period )
81   Set the comma and period characters to use.
82 
83 FLOATS/DOUBLES:
84 ===============
85 This code uses a internal float->ascii conversion method that uses
86 doubles with error correction (double-doubles, for ~105 bits of
87 precision).  This conversion is round-trip perfect - that is, an atof
88 of the values output here will give you the bit-exact double back.
89 
90 One difference is that our insignificant digits will be different than
91 with MSVC or GCC (but they don't match each other either).  We also
92 don't attempt to find the minimum length matching float (pre-MSVC15
93 doesn't either).
94 
95 If you don't need float or doubles at all, define STB_SPRINTF_NOFLOAT
96 and you'll save 4K of code space.
97 
98 64-BIT INTS:
99 ============
100 This library also supports 64-bit integers and you can use MSVC style or
101 GCC style indicators (%I64d or %lld).  It supports the C99 specifiers
102 for size_t and ptr_diff_t (%jd %zd) as well.
103 
104 EXTRAS:
105 =======
106 Like some GCCs, for integers and floats, you can use a ' (single quote)
107 specifier and commas will be inserted on the thousands: "%'d" on 12345
108 would print 12,345.
109 
110 For integers and floats, you can use a "$" specifier and the number
111 will be converted to float and then divided to get kilo, mega, giga or
112 tera and then printed, so "%$d" 1000 is "1.0 k", "%$.2d" 2536000 is
113 "2.53 M", etc. For byte values, use two $:s, like "%$$d" to turn
114 2536000 to "2.42 Mi". If you prefer JEDEC suffixes to SI ones, use three
115 $:s: "%$$$d" -> "2.42 M". To remove the space between the number and the
116 suffix, add "_" specifier: "%_$d" -> "2.53M".
117 
118 In addition to octal and hexadecimal conversions, you can print
119 integers in binary: "%b" for 256 would print 100.
120 
121 PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC):
122 ===================================================================
123 "%d" across all 32-bit ints (4.8x/4.0x faster than 32-/64-bit MSVC)
124 "%24d" across all 32-bit ints (4.5x/4.2x faster)
125 "%x" across all 32-bit ints (4.5x/3.8x faster)
126 "%08x" across all 32-bit ints (4.3x/3.8x faster)
127 "%f" across e-10 to e+10 floats (7.3x/6.0x faster)
128 "%e" across e-10 to e+10 floats (8.1x/6.0x faster)
129 "%g" across e-10 to e+10 floats (10.0x/7.1x faster)
130 "%f" for values near e-300 (7.9x/6.5x faster)
131 "%f" for values near e+300 (10.0x/9.1x faster)
132 "%e" for values near e-300 (10.1x/7.0x faster)
133 "%e" for values near e+300 (9.2x/6.0x faster)
134 "%.320f" for values near e-300 (12.6x/11.2x faster)
135 "%a" for random values (8.6x/4.3x faster)
136 "%I64d" for 64-bits with 32-bit values (4.8x/3.4x faster)
137 "%I64d" for 64-bits > 32-bit values (4.9x/5.5x faster)
138 "%s%s%s" for 64 char strings (7.1x/7.3x faster)
139 "...512 char string..." ( 35.0x/32.5x faster!)
140 */
141 
142 #if defined(__has_feature)
143    #if __has_feature(address_sanitizer)
144       #define STBI__ASAN __attribute__((no_sanitize("address")))
145    #endif
146 #endif
147 #ifndef STBI__ASAN
148 #define STBI__ASAN
149 #endif
150 
151 #ifdef STB_SPRINTF_STATIC
152 #define STBSP__PUBLICDEC static
153 #define STBSP__PUBLICDEF static STBI__ASAN
154 #else
155 #ifdef __cplusplus
156 #define STBSP__PUBLICDEC extern "C"
157 #define STBSP__PUBLICDEF extern "C" STBI__ASAN
158 #else
159 #define STBSP__PUBLICDEC extern
160 #define STBSP__PUBLICDEF STBI__ASAN
161 #endif
162 #endif
163 
164 #include <stdarg.h> // for va_list()
165 #include <stddef.h> // size_t, ptrdiff_t
166 
167 #ifndef STB_SPRINTF_MIN
168 #define STB_SPRINTF_MIN 512 // how many characters per callback
169 #endif
170 typedef char *STBSP_SPRINTFCB(char *buf, void *user, int len);
171 
172 #ifndef STB_SPRINTF_DECORATE
173 #define STB_SPRINTF_DECORATE(name) stbsp_##name // define this before including if you want to change the names
174 #endif
175 
176 STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va);
177 STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, int count, char const *fmt, va_list va);
178 STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...);
179 STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...);
180 
181 STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va);
182 STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char comma, char period);
183 
184 #endif // STB_SPRINTF_H_INCLUDE
185 
186 #ifdef STB_SPRINTF_IMPLEMENTATION
187 
188 #include <stdlib.h> // for va_arg()
189 
190 #define stbsp__uint32 unsigned int
191 #define stbsp__int32 signed int
192 
193 #ifdef _MSC_VER
194 #define stbsp__uint64 unsigned __int64
195 #define stbsp__int64 signed __int64
196 #else
197 #define stbsp__uint64 unsigned long long
198 #define stbsp__int64 signed long long
199 #endif
200 #define stbsp__uint16 unsigned short
201 
202 #ifndef stbsp__uintptr
203 #if defined(__ppc64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64)
204 #define stbsp__uintptr stbsp__uint64
205 #else
206 #define stbsp__uintptr stbsp__uint32
207 #endif
208 #endif
209 
210 #ifndef STB_SPRINTF_MSVC_MODE // used for MSVC2013 and earlier (MSVC2015 matches GCC)
211 #if defined(_MSC_VER) && (_MSC_VER < 1900)
212 #define STB_SPRINTF_MSVC_MODE
213 #endif
214 #endif
215 
216 #ifdef STB_SPRINTF_NOUNALIGNED // define this before inclusion to force stbsp_sprintf to always use aligned accesses
217 #define STBSP__UNALIGNED(code)
218 #else
219 #define STBSP__UNALIGNED(code) code
220 #endif
221 
222 #ifndef STB_SPRINTF_NOFLOAT
223 // internal float utility functions
224 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);
225 static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value);
226 #define STBSP__SPECIAL 0x7000
227 #endif
228 
229 static char stbsp__period = '.';
230 static char stbsp__comma = ',';
231 static struct
232 {
233    short temp; // force next field to be 2-byte aligned
234    char pair[201];
235 } stbsp__digitpair =
236 {
237   0,
238    "00010203040506070809101112131415161718192021222324"
239    "25262728293031323334353637383940414243444546474849"
240    "50515253545556575859606162636465666768697071727374"
241    "75767778798081828384858687888990919293949596979899"
242 };
243 
STB_SPRINTF_DECORATE(set_separators)244 STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char pcomma, char pperiod)
245 {
246    stbsp__period = pperiod;
247    stbsp__comma = pcomma;
248 }
249 
250 #define STBSP__LEFTJUST 1
251 #define STBSP__LEADINGPLUS 2
252 #define STBSP__LEADINGSPACE 4
253 #define STBSP__LEADING_0X 8
254 #define STBSP__LEADINGZERO 16
255 #define STBSP__INTMAX 32
256 #define STBSP__TRIPLET_COMMA 64
257 #define STBSP__NEGATIVE 128
258 #define STBSP__METRIC_SUFFIX 256
259 #define STBSP__HALFWIDTH 512
260 #define STBSP__METRIC_NOSPACE 1024
261 #define STBSP__METRIC_1024 2048
262 #define STBSP__METRIC_JEDEC 4096
263 
stbsp__lead_sign(stbsp__uint32 fl,char * sign)264 static void stbsp__lead_sign(stbsp__uint32 fl, char *sign)
265 {
266    sign[0] = 0;
267    if (fl & STBSP__NEGATIVE) {
268       sign[0] = 1;
269       sign[1] = '-';
270    } else if (fl & STBSP__LEADINGSPACE) {
271       sign[0] = 1;
272       sign[1] = ' ';
273    } else if (fl & STBSP__LEADINGPLUS) {
274       sign[0] = 1;
275       sign[1] = '+';
276    }
277 }
278 
STB_SPRINTF_DECORATE(vsprintfcb)279 STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va)
280 {
281    static char hex[] = "0123456789abcdefxp";
282    static char hexu[] = "0123456789ABCDEFXP";
283    char *bf;
284    char const *f;
285    int tlen = 0;
286 
287    bf = buf;
288    f = fmt;
289    for (;;) {
290       stbsp__int32 fw, pr, tz;
291       stbsp__uint32 fl;
292 
293       // macros for the callback buffer stuff
294       #define stbsp__chk_cb_bufL(bytes)                        \
295          {                                                     \
296             int len = (int)(bf - buf);                         \
297             if ((len + (bytes)) >= STB_SPRINTF_MIN) {          \
298                tlen += len;                                    \
299                if (0 == (bf = buf = callback(buf, user, len))) \
300                   goto done;                                   \
301             }                                                  \
302          }
303       #define stbsp__chk_cb_buf(bytes)    \
304          {                                \
305             if (callback) {               \
306                stbsp__chk_cb_bufL(bytes); \
307             }                             \
308          }
309       #define stbsp__flush_cb()                      \
310          {                                           \
311             stbsp__chk_cb_bufL(STB_SPRINTF_MIN - 1); \
312          } // flush if there is even one byte in the buffer
313       #define stbsp__cb_buf_clamp(cl, v)                \
314          cl = v;                                        \
315          if (callback) {                                \
316             int lg = STB_SPRINTF_MIN - (int)(bf - buf); \
317             if (cl > lg)                                \
318                cl = lg;                                 \
319          }
320 
321       // fast copy everything up to the next % (or end of string)
322       for (;;) {
323          while (((stbsp__uintptr)f) & 3) {
324          schk1:
325             if (f[0] == '%')
326                goto scandd;
327          schk2:
328             if (f[0] == 0)
329                goto endfmt;
330             stbsp__chk_cb_buf(1);
331             *bf++ = f[0];
332             ++f;
333          }
334          for (;;) {
335             // Check if the next 4 bytes contain %(0x25) or end of string.
336             // Using the 'hasless' trick:
337             // https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord
338             stbsp__uint32 v, c;
339             v = *(stbsp__uint32 *)f;
340             c = (~v) & 0x80808080;
341             if (((v ^ 0x25252525) - 0x01010101) & c)
342                goto schk1;
343             if ((v - 0x01010101) & c)
344                goto schk2;
345             if (callback)
346                if ((STB_SPRINTF_MIN - (int)(bf - buf)) < 4)
347                   goto schk1;
348             #ifdef STB_SPRINTF_NOUNALIGNED
349                 if(((stbsp__uintptr)bf) & 3) {
350                     bf[0] = f[0];
351                     bf[1] = f[1];
352                     bf[2] = f[2];
353                     bf[3] = f[3];
354                 } else
355             #endif
356             {
357                 *(stbsp__uint32 *)bf = v;
358             }
359             bf += 4;
360             f += 4;
361          }
362       }
363    scandd:
364 
365       ++f;
366 
367       // ok, we have a percent, read the modifiers first
368       fw = 0;
369       pr = -1;
370       fl = 0;
371       tz = 0;
372 
373       // flags
374       for (;;) {
375          switch (f[0]) {
376          // if we have left justify
377          case '-':
378             fl |= STBSP__LEFTJUST;
379             ++f;
380             continue;
381          // if we have leading plus
382          case '+':
383             fl |= STBSP__LEADINGPLUS;
384             ++f;
385             continue;
386          // if we have leading space
387          case ' ':
388             fl |= STBSP__LEADINGSPACE;
389             ++f;
390             continue;
391          // if we have leading 0x
392          case '#':
393             fl |= STBSP__LEADING_0X;
394             ++f;
395             continue;
396          // if we have thousand commas
397          case '\'':
398             fl |= STBSP__TRIPLET_COMMA;
399             ++f;
400             continue;
401          // if we have kilo marker (none->kilo->kibi->jedec)
402          case '$':
403             if (fl & STBSP__METRIC_SUFFIX) {
404                if (fl & STBSP__METRIC_1024) {
405                   fl |= STBSP__METRIC_JEDEC;
406                } else {
407                   fl |= STBSP__METRIC_1024;
408                }
409             } else {
410                fl |= STBSP__METRIC_SUFFIX;
411             }
412             ++f;
413             continue;
414          // if we don't want space between metric suffix and number
415          case '_':
416             fl |= STBSP__METRIC_NOSPACE;
417             ++f;
418             continue;
419          // if we have leading zero
420          case '0':
421             fl |= STBSP__LEADINGZERO;
422             ++f;
423             goto flags_done;
424          default: goto flags_done;
425          }
426       }
427    flags_done:
428 
429       // get the field width
430       if (f[0] == '*') {
431          fw = va_arg(va, stbsp__uint32);
432          ++f;
433       } else {
434          while ((f[0] >= '0') && (f[0] <= '9')) {
435             fw = fw * 10 + f[0] - '0';
436             f++;
437          }
438       }
439       // get the precision
440       if (f[0] == '.') {
441          ++f;
442          if (f[0] == '*') {
443             pr = va_arg(va, stbsp__uint32);
444             ++f;
445          } else {
446             pr = 0;
447             while ((f[0] >= '0') && (f[0] <= '9')) {
448                pr = pr * 10 + f[0] - '0';
449                f++;
450             }
451          }
452       }
453 
454       // handle integer size overrides
455       switch (f[0]) {
456       // are we halfwidth?
457       case 'h':
458          fl |= STBSP__HALFWIDTH;
459          ++f;
460          break;
461       // are we 64-bit (unix style)
462       case 'l':
463          fl |= ((sizeof(long) == 8) ? STBSP__INTMAX : 0);
464          ++f;
465          if (f[0] == 'l') {
466             fl |= STBSP__INTMAX;
467             ++f;
468          }
469          break;
470       // are we 64-bit on intmax? (c99)
471       case 'j':
472          fl |= (sizeof(size_t) == 8) ? STBSP__INTMAX : 0;
473          ++f;
474          break;
475       // are we 64-bit on size_t or ptrdiff_t? (c99)
476       case 'z':
477          fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0;
478          ++f;
479          break;
480       case 't':
481          fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0;
482          ++f;
483          break;
484       // are we 64-bit (msft style)
485       case 'I':
486          if ((f[1] == '6') && (f[2] == '4')) {
487             fl |= STBSP__INTMAX;
488             f += 3;
489          } else if ((f[1] == '3') && (f[2] == '2')) {
490             f += 3;
491          } else {
492             fl |= ((sizeof(void *) == 8) ? STBSP__INTMAX : 0);
493             ++f;
494          }
495          break;
496       default: break;
497       }
498 
499       // handle each replacement
500       switch (f[0]) {
501          #define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307
502          char num[STBSP__NUMSZ];
503          char lead[8];
504          char tail[8];
505          char *s;
506          char const *h;
507          stbsp__uint32 l, n, cs;
508          stbsp__uint64 n64;
509 #ifndef STB_SPRINTF_NOFLOAT
510          double fv;
511 #endif
512          stbsp__int32 dp;
513          char const *sn;
514 
515       case 's':
516          // get the string
517          s = va_arg(va, char *);
518          if (s == 0)
519             s = (char *)"null";
520          // get the length
521          sn = s;
522          for (;;) {
523             if ((((stbsp__uintptr)sn) & 3) == 0)
524                break;
525          lchk:
526             if (sn[0] == 0)
527                goto ld;
528             ++sn;
529          }
530          n = 0xffffffff;
531          if (pr >= 0) {
532             n = (stbsp__uint32)(sn - s);
533             if (n >= (stbsp__uint32)pr)
534                goto ld;
535             n = ((stbsp__uint32)(pr - n)) >> 2;
536          }
537          while (n) {
538             stbsp__uint32 v = *(stbsp__uint32 *)sn;
539             if ((v - 0x01010101) & (~v) & 0x80808080UL)
540                goto lchk;
541             sn += 4;
542             --n;
543          }
544          goto lchk;
545       ld:
546 
547          l = (stbsp__uint32)(sn - s);
548          // clamp to precision
549          if (l > (stbsp__uint32)pr)
550             l = pr;
551          lead[0] = 0;
552          tail[0] = 0;
553          pr = 0;
554          dp = 0;
555          cs = 0;
556          // copy the string in
557          goto scopy;
558 
559       case 'c': // char
560          // get the character
561          s = num + STBSP__NUMSZ - 1;
562          *s = (char)va_arg(va, int);
563          l = 1;
564          lead[0] = 0;
565          tail[0] = 0;
566          pr = 0;
567          dp = 0;
568          cs = 0;
569          goto scopy;
570 
571       case 'n': // weird write-bytes specifier
572       {
573          int *d = va_arg(va, int *);
574          *d = tlen + (int)(bf - buf);
575       } break;
576 
577 #ifdef STB_SPRINTF_NOFLOAT
578       case 'A':              // float
579       case 'a':              // hex float
580       case 'G':              // float
581       case 'g':              // float
582       case 'E':              // float
583       case 'e':              // float
584       case 'f':              // float
585          va_arg(va, double); // eat it
586          s = (char *)"No float";
587          l = 8;
588          lead[0] = 0;
589          tail[0] = 0;
590          pr = 0;
591          dp = 0;
592          cs = 0;
593          goto scopy;
594 #else
595       case 'A': // hex float
596       case 'a': // hex float
597          h = (f[0] == 'A') ? hexu : hex;
598          fv = va_arg(va, double);
599          if (pr == -1)
600             pr = 6; // default is 6
601          // read the double into a string
602          if (stbsp__real_to_parts((stbsp__int64 *)&n64, &dp, fv))
603             fl |= STBSP__NEGATIVE;
604 
605          s = num + 64;
606 
607          stbsp__lead_sign(fl, lead);
608 
609          if (dp == -1023)
610             dp = (n64) ? -1022 : 0;
611          else
612             n64 |= (((stbsp__uint64)1) << 52);
613          n64 <<= (64 - 56);
614          if (pr < 15)
615             n64 += ((((stbsp__uint64)8) << 56) >> (pr * 4));
616 // add leading chars
617 
618 #ifdef STB_SPRINTF_MSVC_MODE
619          *s++ = '0';
620          *s++ = 'x';
621 #else
622          lead[1 + lead[0]] = '0';
623          lead[2 + lead[0]] = 'x';
624          lead[0] += 2;
625 #endif
626          *s++ = h[(n64 >> 60) & 15];
627          n64 <<= 4;
628          if (pr)
629             *s++ = stbsp__period;
630          sn = s;
631 
632          // print the bits
633          n = pr;
634          if (n > 13)
635             n = 13;
636          if (pr > (stbsp__int32)n)
637             tz = pr - n;
638          pr = 0;
639          while (n--) {
640             *s++ = h[(n64 >> 60) & 15];
641             n64 <<= 4;
642          }
643 
644          // print the expo
645          tail[1] = h[17];
646          if (dp < 0) {
647             tail[2] = '-';
648             dp = -dp;
649          } else
650             tail[2] = '+';
651          n = (dp >= 1000) ? 6 : ((dp >= 100) ? 5 : ((dp >= 10) ? 4 : 3));
652          tail[0] = (char)n;
653          for (;;) {
654             tail[n] = '0' + dp % 10;
655             if (n <= 3)
656                break;
657             --n;
658             dp /= 10;
659          }
660 
661          dp = (int)(s - sn);
662          l = (int)(s - (num + 64));
663          s = num + 64;
664          cs = 1 + (3 << 24);
665          goto scopy;
666 
667       case 'G': // float
668       case 'g': // float
669          h = (f[0] == 'G') ? hexu : hex;
670          fv = va_arg(va, double);
671          if (pr == -1)
672             pr = 6;
673          else if (pr == 0)
674             pr = 1; // default is 6
675          // read the double into a string
676          if (stbsp__real_to_str(&sn, &l, num, &dp, fv, (pr - 1) | 0x80000000))
677             fl |= STBSP__NEGATIVE;
678 
679          // clamp the precision and delete extra zeros after clamp
680          n = pr;
681          if (l > (stbsp__uint32)pr)
682             l = pr;
683          while ((l > 1) && (pr) && (sn[l - 1] == '0')) {
684             --pr;
685             --l;
686          }
687 
688          // should we use %e
689          if ((dp <= -4) || (dp > (stbsp__int32)n)) {
690             if (pr > (stbsp__int32)l)
691                pr = l - 1;
692             else if (pr)
693                --pr; // when using %e, there is one digit before the decimal
694             goto doexpfromg;
695          }
696          // this is the insane action to get the pr to match %g semantics for %f
697          if (dp > 0) {
698             pr = (dp < (stbsp__int32)l) ? l - dp : 0;
699          } else {
700             pr = -dp + ((pr > (stbsp__int32)l) ? (stbsp__int32) l : pr);
701          }
702          goto dofloatfromg;
703 
704       case 'E': // float
705       case 'e': // float
706          h = (f[0] == 'E') ? hexu : hex;
707          fv = va_arg(va, double);
708          if (pr == -1)
709             pr = 6; // default is 6
710          // read the double into a string
711          if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr | 0x80000000))
712             fl |= STBSP__NEGATIVE;
713       doexpfromg:
714          tail[0] = 0;
715          stbsp__lead_sign(fl, lead);
716          if (dp == STBSP__SPECIAL) {
717             s = (char *)sn;
718             cs = 0;
719             pr = 0;
720             goto scopy;
721          }
722          s = num + 64;
723          // handle leading chars
724          *s++ = sn[0];
725 
726          if (pr)
727             *s++ = stbsp__period;
728 
729          // handle after decimal
730          if ((l - 1) > (stbsp__uint32)pr)
731             l = pr + 1;
732          for (n = 1; n < l; n++)
733             *s++ = sn[n];
734          // trailing zeros
735          tz = pr - (l - 1);
736          pr = 0;
737          // dump expo
738          tail[1] = h[0xe];
739          dp -= 1;
740          if (dp < 0) {
741             tail[2] = '-';
742             dp = -dp;
743          } else
744             tail[2] = '+';
745 #ifdef STB_SPRINTF_MSVC_MODE
746          n = 5;
747 #else
748          n = (dp >= 100) ? 5 : 4;
749 #endif
750          tail[0] = (char)n;
751          for (;;) {
752             tail[n] = '0' + dp % 10;
753             if (n <= 3)
754                break;
755             --n;
756             dp /= 10;
757          }
758          cs = 1 + (3 << 24); // how many tens
759          goto flt_lead;
760 
761       case 'f': // float
762          fv = va_arg(va, double);
763       doafloat:
764          // do kilos
765          if (fl & STBSP__METRIC_SUFFIX) {
766             double divisor;
767             divisor = 1000.0f;
768             if (fl & STBSP__METRIC_1024)
769                divisor = 1024.0;
770             while (fl < 0x4000000) {
771                if ((fv < divisor) && (fv > -divisor))
772                   break;
773                fv /= divisor;
774                fl += 0x1000000;
775             }
776          }
777          if (pr == -1)
778             pr = 6; // default is 6
779          // read the double into a string
780          if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr))
781             fl |= STBSP__NEGATIVE;
782       dofloatfromg:
783          tail[0] = 0;
784          stbsp__lead_sign(fl, lead);
785          if (dp == STBSP__SPECIAL) {
786             s = (char *)sn;
787             cs = 0;
788             pr = 0;
789             goto scopy;
790          }
791          s = num + 64;
792 
793          // handle the three decimal varieties
794          if (dp <= 0) {
795             stbsp__int32 i;
796             // handle 0.000*000xxxx
797             *s++ = '0';
798             if (pr)
799                *s++ = stbsp__period;
800             n = -dp;
801             if ((stbsp__int32)n > pr)
802                n = pr;
803             i = n;
804             while (i) {
805                if ((((stbsp__uintptr)s) & 3) == 0)
806                   break;
807                *s++ = '0';
808                --i;
809             }
810             while (i >= 4) {
811                *(stbsp__uint32 *)s = 0x30303030;
812                s += 4;
813                i -= 4;
814             }
815             while (i) {
816                *s++ = '0';
817                --i;
818             }
819             if ((stbsp__int32)(l + n) > pr)
820                l = pr - n;
821             i = l;
822             while (i) {
823                *s++ = *sn++;
824                --i;
825             }
826             tz = pr - (n + l);
827             cs = 1 + (3 << 24); // how many tens did we write (for commas below)
828          } else {
829             cs = (fl & STBSP__TRIPLET_COMMA) ? ((600 - (stbsp__uint32)dp) % 3) : 0;
830             if ((stbsp__uint32)dp >= l) {
831                // handle xxxx000*000.0
832                n = 0;
833                for (;;) {
834                   if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) {
835                      cs = 0;
836                      *s++ = stbsp__comma;
837                   } else {
838                      *s++ = sn[n];
839                      ++n;
840                      if (n >= l)
841                         break;
842                   }
843                }
844                if (n < (stbsp__uint32)dp) {
845                   n = dp - n;
846                   if ((fl & STBSP__TRIPLET_COMMA) == 0) {
847                      while (n) {
848                         if ((((stbsp__uintptr)s) & 3) == 0)
849                            break;
850                         *s++ = '0';
851                         --n;
852                      }
853                      while (n >= 4) {
854                         *(stbsp__uint32 *)s = 0x30303030;
855                         s += 4;
856                         n -= 4;
857                      }
858                   }
859                   while (n) {
860                      if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) {
861                         cs = 0;
862                         *s++ = stbsp__comma;
863                      } else {
864                         *s++ = '0';
865                         --n;
866                      }
867                   }
868                }
869                cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens
870                if (pr) {
871                   *s++ = stbsp__period;
872                   tz = pr;
873                }
874             } else {
875                // handle xxxxx.xxxx000*000
876                n = 0;
877                for (;;) {
878                   if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) {
879                      cs = 0;
880                      *s++ = stbsp__comma;
881                   } else {
882                      *s++ = sn[n];
883                      ++n;
884                      if (n >= (stbsp__uint32)dp)
885                         break;
886                   }
887                }
888                cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens
889                if (pr)
890                   *s++ = stbsp__period;
891                if ((l - dp) > (stbsp__uint32)pr)
892                   l = pr + dp;
893                while (n < l) {
894                   *s++ = sn[n];
895                   ++n;
896                }
897                tz = pr - (l - dp);
898             }
899          }
900          pr = 0;
901 
902          // handle k,m,g,t
903          if (fl & STBSP__METRIC_SUFFIX) {
904             char idx;
905             idx = 1;
906             if (fl & STBSP__METRIC_NOSPACE)
907                idx = 0;
908             tail[0] = idx;
909             tail[1] = ' ';
910             {
911                if (fl >> 24) { // SI kilo is 'k', JEDEC and SI kibits are 'K'.
912                   if (fl & STBSP__METRIC_1024)
913                      tail[idx + 1] = "_KMGT"[fl >> 24];
914                   else
915                      tail[idx + 1] = "_kMGT"[fl >> 24];
916                   idx++;
917                   // If printing kibits and not in jedec, add the 'i'.
918                   if (fl & STBSP__METRIC_1024 && !(fl & STBSP__METRIC_JEDEC)) {
919                      tail[idx + 1] = 'i';
920                      idx++;
921                   }
922                   tail[0] = idx;
923                }
924             }
925          };
926 
927       flt_lead:
928          // get the length that we copied
929          l = (stbsp__uint32)(s - (num + 64));
930          s = num + 64;
931          goto scopy;
932 #endif
933 
934       case 'B': // upper binary
935       case 'b': // lower binary
936          h = (f[0] == 'B') ? hexu : hex;
937          lead[0] = 0;
938          if (fl & STBSP__LEADING_0X) {
939             lead[0] = 2;
940             lead[1] = '0';
941             lead[2] = h[0xb];
942          }
943          l = (8 << 4) | (1 << 8);
944          goto radixnum;
945 
946       case 'o': // octal
947          h = hexu;
948          lead[0] = 0;
949          if (fl & STBSP__LEADING_0X) {
950             lead[0] = 1;
951             lead[1] = '0';
952          }
953          l = (3 << 4) | (3 << 8);
954          goto radixnum;
955 
956       case 'p': // pointer
957          fl |= (sizeof(void *) == 8) ? STBSP__INTMAX : 0;
958          pr = sizeof(void *) * 2;
959          fl &= ~STBSP__LEADINGZERO; // 'p' only prints the pointer with zeros
960                                     // fall through - to X
961 
962       case 'X': // upper hex
963       case 'x': // lower hex
964          h = (f[0] == 'X') ? hexu : hex;
965          l = (4 << 4) | (4 << 8);
966          lead[0] = 0;
967          if (fl & STBSP__LEADING_0X) {
968             lead[0] = 2;
969             lead[1] = '0';
970             lead[2] = h[16];
971          }
972       radixnum:
973          // get the number
974          if (fl & STBSP__INTMAX)
975             n64 = va_arg(va, stbsp__uint64);
976          else
977             n64 = va_arg(va, stbsp__uint32);
978 
979          s = num + STBSP__NUMSZ;
980          dp = 0;
981          // clear tail, and clear leading if value is zero
982          tail[0] = 0;
983          if (n64 == 0) {
984             lead[0] = 0;
985             if (pr == 0) {
986                l = 0;
987                cs = (((l >> 4) & 15)) << 24;
988                goto scopy;
989             }
990          }
991          // convert to string
992          for (;;) {
993             *--s = h[n64 & ((1 << (l >> 8)) - 1)];
994             n64 >>= (l >> 8);
995             if (!((n64) || ((stbsp__int32)((num + STBSP__NUMSZ) - s) < pr)))
996                break;
997             if (fl & STBSP__TRIPLET_COMMA) {
998                ++l;
999                if ((l & 15) == ((l >> 4) & 15)) {
1000                   l &= ~15;
1001                   *--s = stbsp__comma;
1002                }
1003             }
1004          };
1005          // get the tens and the comma pos
1006          cs = (stbsp__uint32)((num + STBSP__NUMSZ) - s) + ((((l >> 4) & 15)) << 24);
1007          // get the length that we copied
1008          l = (stbsp__uint32)((num + STBSP__NUMSZ) - s);
1009          // copy it
1010          goto scopy;
1011 
1012       case 'u': // unsigned
1013       case 'i':
1014       case 'd': // integer
1015          // get the integer and abs it
1016          if (fl & STBSP__INTMAX) {
1017             stbsp__int64 i64 = va_arg(va, stbsp__int64);
1018             n64 = (stbsp__uint64)i64;
1019             if ((f[0] != 'u') && (i64 < 0)) {
1020                n64 = (stbsp__uint64)-i64;
1021                fl |= STBSP__NEGATIVE;
1022             }
1023          } else {
1024             stbsp__int32 i = va_arg(va, stbsp__int32);
1025             n64 = (stbsp__uint32)i;
1026             if ((f[0] != 'u') && (i < 0)) {
1027                n64 = (stbsp__uint32)-i;
1028                fl |= STBSP__NEGATIVE;
1029             }
1030          }
1031 
1032 #ifndef STB_SPRINTF_NOFLOAT
1033          if (fl & STBSP__METRIC_SUFFIX) {
1034             if (n64 < 1024)
1035                pr = 0;
1036             else if (pr == -1)
1037                pr = 1;
1038             fv = (double)(stbsp__int64)n64;
1039             goto doafloat;
1040          }
1041 #endif
1042 
1043          // convert to string
1044          s = num + STBSP__NUMSZ;
1045          l = 0;
1046 
1047          for (;;) {
1048             // do in 32-bit chunks (avoid lots of 64-bit divides even with constant denominators)
1049             char *o = s - 8;
1050             if (n64 >= 100000000) {
1051                n = (stbsp__uint32)(n64 % 100000000);
1052                n64 /= 100000000;
1053             } else {
1054                n = (stbsp__uint32)n64;
1055                n64 = 0;
1056             }
1057             if ((fl & STBSP__TRIPLET_COMMA) == 0) {
1058                do {
1059                   s -= 2;
1060                   *(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2];
1061                   n /= 100;
1062                } while (n);
1063             }
1064             while (n) {
1065                if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) {
1066                   l = 0;
1067                   *--s = stbsp__comma;
1068                   --o;
1069                } else {
1070                   *--s = (char)(n % 10) + '0';
1071                   n /= 10;
1072                }
1073             }
1074             if (n64 == 0) {
1075                if ((s[0] == '0') && (s != (num + STBSP__NUMSZ)))
1076                   ++s;
1077                break;
1078             }
1079             while (s != o)
1080                if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) {
1081                   l = 0;
1082                   *--s = stbsp__comma;
1083                   --o;
1084                } else {
1085                   *--s = '0';
1086                }
1087          }
1088 
1089          tail[0] = 0;
1090          stbsp__lead_sign(fl, lead);
1091 
1092          // get the length that we copied
1093          l = (stbsp__uint32)((num + STBSP__NUMSZ) - s);
1094          if (l == 0) {
1095             *--s = '0';
1096             l = 1;
1097          }
1098          cs = l + (3 << 24);
1099          if (pr < 0)
1100             pr = 0;
1101 
1102       scopy:
1103          // get fw=leading/trailing space, pr=leading zeros
1104          if (pr < (stbsp__int32)l)
1105             pr = l;
1106          n = pr + lead[0] + tail[0] + tz;
1107          if (fw < (stbsp__int32)n)
1108             fw = n;
1109          fw -= n;
1110          pr -= l;
1111 
1112          // handle right justify and leading zeros
1113          if ((fl & STBSP__LEFTJUST) == 0) {
1114             if (fl & STBSP__LEADINGZERO) // if leading zeros, everything is in pr
1115             {
1116                pr = (fw > pr) ? fw : pr;
1117                fw = 0;
1118             } else {
1119                fl &= ~STBSP__TRIPLET_COMMA; // if no leading zeros, then no commas
1120             }
1121          }
1122 
1123          // copy the spaces and/or zeros
1124          if (fw + pr) {
1125             stbsp__int32 i;
1126             stbsp__uint32 c;
1127 
1128             // copy leading spaces (or when doing %8.4d stuff)
1129             if ((fl & STBSP__LEFTJUST) == 0)
1130                while (fw > 0) {
1131                   stbsp__cb_buf_clamp(i, fw);
1132                   fw -= i;
1133                   while (i) {
1134                      if ((((stbsp__uintptr)bf) & 3) == 0)
1135                         break;
1136                      *bf++ = ' ';
1137                      --i;
1138                   }
1139                   while (i >= 4) {
1140                      *(stbsp__uint32 *)bf = 0x20202020;
1141                      bf += 4;
1142                      i -= 4;
1143                   }
1144                   while (i) {
1145                      *bf++ = ' ';
1146                      --i;
1147                   }
1148                   stbsp__chk_cb_buf(1);
1149                }
1150 
1151             // copy leader
1152             sn = lead + 1;
1153             while (lead[0]) {
1154                stbsp__cb_buf_clamp(i, lead[0]);
1155                lead[0] -= (char)i;
1156                while (i) {
1157                   *bf++ = *sn++;
1158                   --i;
1159                }
1160                stbsp__chk_cb_buf(1);
1161             }
1162 
1163             // copy leading zeros
1164             c = cs >> 24;
1165             cs &= 0xffffff;
1166             cs = (fl & STBSP__TRIPLET_COMMA) ? ((stbsp__uint32)(c - ((pr + cs) % (c + 1)))) : 0;
1167             while (pr > 0) {
1168                stbsp__cb_buf_clamp(i, pr);
1169                pr -= i;
1170                if ((fl & STBSP__TRIPLET_COMMA) == 0) {
1171                   while (i) {
1172                      if ((((stbsp__uintptr)bf) & 3) == 0)
1173                         break;
1174                      *bf++ = '0';
1175                      --i;
1176                   }
1177                   while (i >= 4) {
1178                      *(stbsp__uint32 *)bf = 0x30303030;
1179                      bf += 4;
1180                      i -= 4;
1181                   }
1182                }
1183                while (i) {
1184                   if ((fl & STBSP__TRIPLET_COMMA) && (cs++ == c)) {
1185                      cs = 0;
1186                      *bf++ = stbsp__comma;
1187                   } else
1188                      *bf++ = '0';
1189                   --i;
1190                }
1191                stbsp__chk_cb_buf(1);
1192             }
1193          }
1194 
1195          // copy leader if there is still one
1196          sn = lead + 1;
1197          while (lead[0]) {
1198             stbsp__int32 i;
1199             stbsp__cb_buf_clamp(i, lead[0]);
1200             lead[0] -= (char)i;
1201             while (i) {
1202                *bf++ = *sn++;
1203                --i;
1204             }
1205             stbsp__chk_cb_buf(1);
1206          }
1207 
1208          // copy the string
1209          n = l;
1210          while (n) {
1211             stbsp__int32 i;
1212             stbsp__cb_buf_clamp(i, n);
1213             n -= i;
1214             STBSP__UNALIGNED(while (i >= 4) {
1215                *(stbsp__uint32 *)bf = *(stbsp__uint32 *)s;
1216                bf += 4;
1217                s += 4;
1218                i -= 4;
1219             })
1220             while (i) {
1221                *bf++ = *s++;
1222                --i;
1223             }
1224             stbsp__chk_cb_buf(1);
1225          }
1226 
1227          // copy trailing zeros
1228          while (tz) {
1229             stbsp__int32 i;
1230             stbsp__cb_buf_clamp(i, tz);
1231             tz -= i;
1232             while (i) {
1233                if ((((stbsp__uintptr)bf) & 3) == 0)
1234                   break;
1235                *bf++ = '0';
1236                --i;
1237             }
1238             while (i >= 4) {
1239                *(stbsp__uint32 *)bf = 0x30303030;
1240                bf += 4;
1241                i -= 4;
1242             }
1243             while (i) {
1244                *bf++ = '0';
1245                --i;
1246             }
1247             stbsp__chk_cb_buf(1);
1248          }
1249 
1250          // copy tail if there is one
1251          sn = tail + 1;
1252          while (tail[0]) {
1253             stbsp__int32 i;
1254             stbsp__cb_buf_clamp(i, tail[0]);
1255             tail[0] -= (char)i;
1256             while (i) {
1257                *bf++ = *sn++;
1258                --i;
1259             }
1260             stbsp__chk_cb_buf(1);
1261          }
1262 
1263          // handle the left justify
1264          if (fl & STBSP__LEFTJUST)
1265             if (fw > 0) {
1266                while (fw) {
1267                   stbsp__int32 i;
1268                   stbsp__cb_buf_clamp(i, fw);
1269                   fw -= i;
1270                   while (i) {
1271                      if ((((stbsp__uintptr)bf) & 3) == 0)
1272                         break;
1273                      *bf++ = ' ';
1274                      --i;
1275                   }
1276                   while (i >= 4) {
1277                      *(stbsp__uint32 *)bf = 0x20202020;
1278                      bf += 4;
1279                      i -= 4;
1280                   }
1281                   while (i--)
1282                      *bf++ = ' ';
1283                   stbsp__chk_cb_buf(1);
1284                }
1285             }
1286          break;
1287 
1288       default: // unknown, just copy code
1289          s = num + STBSP__NUMSZ - 1;
1290          *s = f[0];
1291          l = 1;
1292          fw = fl = 0;
1293          lead[0] = 0;
1294          tail[0] = 0;
1295          pr = 0;
1296          dp = 0;
1297          cs = 0;
1298          goto scopy;
1299       }
1300       ++f;
1301    }
1302 endfmt:
1303 
1304    if (!callback)
1305       *bf = 0;
1306    else
1307       stbsp__flush_cb();
1308 
1309 done:
1310    return tlen + (int)(bf - buf);
1311 }
1312 
1313 // cleanup
1314 #undef STBSP__LEFTJUST
1315 #undef STBSP__LEADINGPLUS
1316 #undef STBSP__LEADINGSPACE
1317 #undef STBSP__LEADING_0X
1318 #undef STBSP__LEADINGZERO
1319 #undef STBSP__INTMAX
1320 #undef STBSP__TRIPLET_COMMA
1321 #undef STBSP__NEGATIVE
1322 #undef STBSP__METRIC_SUFFIX
1323 #undef STBSP__NUMSZ
1324 #undef stbsp__chk_cb_bufL
1325 #undef stbsp__chk_cb_buf
1326 #undef stbsp__flush_cb
1327 #undef stbsp__cb_buf_clamp
1328 
1329 // ============================================================================
1330 //   wrapper functions
1331 
STB_SPRINTF_DECORATE(sprintf)1332 STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...)
1333 {
1334    int result;
1335    va_list va;
1336    va_start(va, fmt);
1337    result = STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va);
1338    va_end(va);
1339    return result;
1340 }
1341 
1342 typedef struct stbsp__context {
1343    char *buf;
1344    int count;
1345    char tmp[STB_SPRINTF_MIN];
1346 } stbsp__context;
1347 
stbsp__clamp_callback(char * buf,void * user,int len)1348 static char *stbsp__clamp_callback(char *buf, void *user, int len)
1349 {
1350    stbsp__context *c = (stbsp__context *)user;
1351 
1352    if (len > c->count)
1353       len = c->count;
1354 
1355    if (len) {
1356       if (buf != c->buf) {
1357          char *s, *d, *se;
1358          d = c->buf;
1359          s = buf;
1360          se = buf + len;
1361          do {
1362             *d++ = *s++;
1363          } while (s < se);
1364       }
1365       c->buf += len;
1366       c->count -= len;
1367    }
1368 
1369    if (c->count <= 0)
1370       return 0;
1371    return (c->count >= STB_SPRINTF_MIN) ? c->buf : c->tmp; // go direct into buffer if you can
1372 }
1373 
stbsp__count_clamp_callback(char * buf,void * user,int len)1374 static char * stbsp__count_clamp_callback( char * buf, void * user, int len )
1375 {
1376    stbsp__context * c = (stbsp__context*)user;
1377 
1378    c->count += len;
1379    return c->tmp; // go direct into buffer if you can
1380 }
1381 
STB_SPRINTF_DECORATE(vsnprintf)1382 STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, char const * fmt, va_list va )
1383 {
1384    stbsp__context c;
1385    int l;
1386 
1387    if ( (count == 0) && !buf )
1388    {
1389       c.count = 0;
1390 
1391       STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__count_clamp_callback, &c, c.tmp, fmt, va );
1392       l = c.count;
1393    }
1394    else
1395    {
1396       if ( count == 0 )
1397          return 0;
1398 
1399       c.buf = buf;
1400       c.count = count;
1401 
1402       STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__clamp_callback, &c, stbsp__clamp_callback(0,&c,0), fmt, va );
1403 
1404       // zero-terminate
1405       l = (int)( c.buf - buf );
1406       if ( l >= count ) // should never be greater, only equal (or less) than count
1407          l = count - 1;
1408       buf[l] = 0;
1409    }
1410 
1411    return l;
1412 }
1413 
STB_SPRINTF_DECORATE(snprintf)1414 STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...)
1415 {
1416    int result;
1417    va_list va;
1418    va_start(va, fmt);
1419 
1420    result = STB_SPRINTF_DECORATE(vsnprintf)(buf, count, fmt, va);
1421    va_end(va);
1422 
1423    return result;
1424 }
1425 
STB_SPRINTF_DECORATE(vsprintf)1426 STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va)
1427 {
1428    return STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va);
1429 }
1430 
1431 // =======================================================================
1432 //   low level float utility functions
1433 
1434 #ifndef STB_SPRINTF_NOFLOAT
1435 
1436 // copies d to bits w/ strict aliasing (this compiles to nothing on /Ox)
1437 #define STBSP__COPYFP(dest, src)                   \
1438    {                                               \
1439       int cn;                                      \
1440       for (cn = 0; cn < 8; cn++)                   \
1441          ((char *)&dest)[cn] = ((char *)&src)[cn]; \
1442    }
1443 
1444 // get float info
stbsp__real_to_parts(stbsp__int64 * bits,stbsp__int32 * expo,double value)1445 static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value)
1446 {
1447    double d;
1448    stbsp__int64 b = 0;
1449 
1450    // load value and round at the frac_digits
1451    d = value;
1452 
1453    STBSP__COPYFP(b, d);
1454 
1455    *bits = b & ((((stbsp__uint64)1) << 52) - 1);
1456    *expo = (stbsp__int32)(((b >> 52) & 2047) - 1023);
1457 
1458    return (stbsp__int32)((stbsp__uint64) b >> 63);
1459 }
1460 
1461 static double const stbsp__bot[23] = {
1462    1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, 1e+010, 1e+011,
1463    1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, 1e+020, 1e+021, 1e+022
1464 };
1465 static double const stbsp__negbot[22] = {
1466    1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009, 1e-010, 1e-011,
1467    1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018, 1e-019, 1e-020, 1e-021, 1e-022
1468 };
1469 static double const stbsp__negboterr[22] = {
1470    -5.551115123125783e-018,  -2.0816681711721684e-019, -2.0816681711721686e-020, -4.7921736023859299e-021, -8.1803053914031305e-022, 4.5251888174113741e-023,
1471    4.5251888174113739e-024,  -2.0922560830128471e-025, -6.2281591457779853e-026, -3.6432197315497743e-027, 6.0503030718060191e-028,  2.0113352370744385e-029,
1472    -3.0373745563400371e-030, 1.1806906454401013e-032,  -7.7705399876661076e-032, 2.0902213275965398e-033,  -7.1542424054621921e-034, -7.1542424054621926e-035,
1473    2.4754073164739869e-036,  5.4846728545790429e-037,  9.2462547772103625e-038,  -4.8596774326570872e-039
1474 };
1475 static double const stbsp__top[13] = {
1476    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
1477 };
1478 static double const stbsp__negtop[13] = {
1479    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
1480 };
1481 static double const stbsp__toperr[13] = {
1482    8388608,
1483    6.8601809640529717e+028,
1484    -7.253143638152921e+052,
1485    -4.3377296974619174e+075,
1486    -1.5559416129466825e+098,
1487    -3.2841562489204913e+121,
1488    -3.7745893248228135e+144,
1489    -1.7356668416969134e+167,
1490    -3.8893577551088374e+190,
1491    -9.9566444326005119e+213,
1492    6.3641293062232429e+236,
1493    -5.2069140800249813e+259,
1494    -5.2504760255204387e+282
1495 };
1496 static double const stbsp__negtoperr[13] = {
1497    3.9565301985100693e-040,  -2.299904345391321e-063,  3.6506201437945798e-086,  1.1875228833981544e-109,
1498    -5.0644902316928607e-132, -6.7156837247865426e-155, -2.812077463003139e-178,  -5.7778912386589953e-201,
1499    7.4997100559334532e-224,  -4.6439668915134491e-247, -6.3691100762962136e-270, -9.436808465446358e-293,
1500    8.0970921678014997e-317
1501 };
1502 
1503 #if defined(_MSC_VER) && (_MSC_VER <= 1200)
1504 static stbsp__uint64 const stbsp__powten[20] = {
1505    1,
1506    10,
1507    100,
1508    1000,
1509    10000,
1510    100000,
1511    1000000,
1512    10000000,
1513    100000000,
1514    1000000000,
1515    10000000000,
1516    100000000000,
1517    1000000000000,
1518    10000000000000,
1519    100000000000000,
1520    1000000000000000,
1521    10000000000000000,
1522    100000000000000000,
1523    1000000000000000000,
1524    10000000000000000000U
1525 };
1526 #define stbsp__tento19th ((stbsp__uint64)1000000000000000000)
1527 #else
1528 static stbsp__uint64 const stbsp__powten[20] = {
1529    1,
1530    10,
1531    100,
1532    1000,
1533    10000,
1534    100000,
1535    1000000,
1536    10000000,
1537    100000000,
1538    1000000000,
1539    10000000000ULL,
1540    100000000000ULL,
1541    1000000000000ULL,
1542    10000000000000ULL,
1543    100000000000000ULL,
1544    1000000000000000ULL,
1545    10000000000000000ULL,
1546    100000000000000000ULL,
1547    1000000000000000000ULL,
1548    10000000000000000000ULL
1549 };
1550 #define stbsp__tento19th (1000000000000000000ULL)
1551 #endif
1552 
1553 #define stbsp__ddmulthi(oh, ol, xh, yh)                            \
1554    {                                                               \
1555       double ahi = 0, alo, bhi = 0, blo;                           \
1556       stbsp__int64 bt;                                             \
1557       oh = xh * yh;                                                \
1558       STBSP__COPYFP(bt, xh);                                       \
1559       bt &= ((~(stbsp__uint64)0) << 27);                           \
1560       STBSP__COPYFP(ahi, bt);                                      \
1561       alo = xh - ahi;                                              \
1562       STBSP__COPYFP(bt, yh);                                       \
1563       bt &= ((~(stbsp__uint64)0) << 27);                           \
1564       STBSP__COPYFP(bhi, bt);                                      \
1565       blo = yh - bhi;                                              \
1566       ol = ((ahi * bhi - oh) + ahi * blo + alo * bhi) + alo * blo; \
1567    }
1568 
1569 #define stbsp__ddtoS64(ob, xh, xl)          \
1570    {                                        \
1571       double ahi = 0, alo, vh, t;           \
1572       ob = (stbsp__int64)ph;                \
1573       vh = (double)ob;                      \
1574       ahi = (xh - vh);                      \
1575       t = (ahi - xh);                       \
1576       alo = (xh - (ahi - t)) - (vh + t);    \
1577       ob += (stbsp__int64)(ahi + alo + xl); \
1578    }
1579 
1580 #define stbsp__ddrenorm(oh, ol) \
1581    {                            \
1582       double s;                 \
1583       s = oh + ol;              \
1584       ol = ol - (s - oh);       \
1585       oh = s;                   \
1586    }
1587 
1588 #define stbsp__ddmultlo(oh, ol, xh, xl, yh, yl) ol = ol + (xh * yl + xl * yh);
1589 
1590 #define stbsp__ddmultlos(oh, ol, xh, yl) ol = ol + (xh * yl);
1591 
stbsp__raise_to_power10(double * ohi,double * olo,double d,stbsp__int32 power)1592 static void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__int32 power) // power can be -323 to +350
1593 {
1594    double ph, pl;
1595    if ((power >= 0) && (power <= 22)) {
1596       stbsp__ddmulthi(ph, pl, d, stbsp__bot[power]);
1597    } else {
1598       stbsp__int32 e, et, eb;
1599       double p2h, p2l;
1600 
1601       e = power;
1602       if (power < 0)
1603          e = -e;
1604       et = (e * 0x2c9) >> 14; /* %23 */
1605       if (et > 13)
1606          et = 13;
1607       eb = e - (et * 23);
1608 
1609       ph = d;
1610       pl = 0.0;
1611       if (power < 0) {
1612          if (eb) {
1613             --eb;
1614             stbsp__ddmulthi(ph, pl, d, stbsp__negbot[eb]);
1615             stbsp__ddmultlos(ph, pl, d, stbsp__negboterr[eb]);
1616          }
1617          if (et) {
1618             stbsp__ddrenorm(ph, pl);
1619             --et;
1620             stbsp__ddmulthi(p2h, p2l, ph, stbsp__negtop[et]);
1621             stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__negtop[et], stbsp__negtoperr[et]);
1622             ph = p2h;
1623             pl = p2l;
1624          }
1625       } else {
1626          if (eb) {
1627             e = eb;
1628             if (eb > 22)
1629                eb = 22;
1630             e -= eb;
1631             stbsp__ddmulthi(ph, pl, d, stbsp__bot[eb]);
1632             if (e) {
1633                stbsp__ddrenorm(ph, pl);
1634                stbsp__ddmulthi(p2h, p2l, ph, stbsp__bot[e]);
1635                stbsp__ddmultlos(p2h, p2l, stbsp__bot[e], pl);
1636                ph = p2h;
1637                pl = p2l;
1638             }
1639          }
1640          if (et) {
1641             stbsp__ddrenorm(ph, pl);
1642             --et;
1643             stbsp__ddmulthi(p2h, p2l, ph, stbsp__top[et]);
1644             stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__top[et], stbsp__toperr[et]);
1645             ph = p2h;
1646             pl = p2l;
1647          }
1648       }
1649    }
1650    stbsp__ddrenorm(ph, pl);
1651    *ohi = ph;
1652    *olo = pl;
1653 }
1654 
1655 // given a float value, returns the significant bits in bits, and the position of the
1656 //   decimal point in decimal_pos.  +/-INF and NAN are specified by special values
1657 //   returned in the decimal_pos parameter.
1658 // frac_digits is absolute normally, but if you want from first significant digits (got %g and %e), or in 0x80000000
stbsp__real_to_str(char const ** start,stbsp__uint32 * len,char * out,stbsp__int32 * decimal_pos,double value,stbsp__uint32 frac_digits)1659 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)
1660 {
1661    double d;
1662    stbsp__int64 bits = 0;
1663    stbsp__int32 expo, e, ng, tens;
1664 
1665    d = value;
1666    STBSP__COPYFP(bits, d);
1667    expo = (stbsp__int32)((bits >> 52) & 2047);
1668    ng = (stbsp__int32)((stbsp__uint64) bits >> 63);
1669    if (ng)
1670       d = -d;
1671 
1672    if (expo == 2047) // is nan or inf?
1673    {
1674       *start = (bits & ((((stbsp__uint64)1) << 52) - 1)) ? "NaN" : "Inf";
1675       *decimal_pos = STBSP__SPECIAL;
1676       *len = 3;
1677       return ng;
1678    }
1679 
1680    if (expo == 0) // is zero or denormal
1681    {
1682       if ((bits << 1) == 0) // do zero
1683       {
1684          *decimal_pos = 1;
1685          *start = out;
1686          out[0] = '0';
1687          *len = 1;
1688          return ng;
1689       }
1690       // find the right expo for denormals
1691       {
1692          stbsp__int64 v = ((stbsp__uint64)1) << 51;
1693          while ((bits & v) == 0) {
1694             --expo;
1695             v >>= 1;
1696          }
1697       }
1698    }
1699 
1700    // find the decimal exponent as well as the decimal bits of the value
1701    {
1702       double ph, pl;
1703 
1704       // log10 estimate - very specifically tweaked to hit or undershoot by no more than 1 of log10 of all expos 1..2046
1705       tens = expo - 1023;
1706       tens = (tens < 0) ? ((tens * 617) / 2048) : (((tens * 1233) / 4096) + 1);
1707 
1708       // move the significant bits into position and stick them into an int
1709       stbsp__raise_to_power10(&ph, &pl, d, 18 - tens);
1710 
1711       // get full as much precision from double-double as possible
1712       stbsp__ddtoS64(bits, ph, pl);
1713 
1714       // check if we undershot
1715       if (((stbsp__uint64)bits) >= stbsp__tento19th)
1716          ++tens;
1717    }
1718 
1719    // now do the rounding in integer land
1720    frac_digits = (frac_digits & 0x80000000) ? ((frac_digits & 0x7ffffff) + 1) : (tens + frac_digits);
1721    if ((frac_digits < 24)) {
1722       stbsp__uint32 dg = 1;
1723       if ((stbsp__uint64)bits >= stbsp__powten[9])
1724          dg = 10;
1725       while ((stbsp__uint64)bits >= stbsp__powten[dg]) {
1726          ++dg;
1727          if (dg == 20)
1728             goto noround;
1729       }
1730       if (frac_digits < dg) {
1731          stbsp__uint64 r;
1732          // add 0.5 at the right position and round
1733          e = dg - frac_digits;
1734          if ((stbsp__uint32)e >= 24)
1735             goto noround;
1736          r = stbsp__powten[e];
1737          bits = bits + (r / 2);
1738          if ((stbsp__uint64)bits >= stbsp__powten[dg])
1739             ++tens;
1740          bits /= r;
1741       }
1742    noround:;
1743    }
1744 
1745    // kill long trailing runs of zeros
1746    if (bits) {
1747       stbsp__uint32 n;
1748       for (;;) {
1749          if (bits <= 0xffffffff)
1750             break;
1751          if (bits % 1000)
1752             goto donez;
1753          bits /= 1000;
1754       }
1755       n = (stbsp__uint32)bits;
1756       while ((n % 1000) == 0)
1757          n /= 1000;
1758       bits = n;
1759    donez:;
1760    }
1761 
1762    // convert to string
1763    out += 64;
1764    e = 0;
1765    for (;;) {
1766       stbsp__uint32 n;
1767       char *o = out - 8;
1768       // do the conversion in chunks of U32s (avoid most 64-bit divides, worth it, constant denomiators be damned)
1769       if (bits >= 100000000) {
1770          n = (stbsp__uint32)(bits % 100000000);
1771          bits /= 100000000;
1772       } else {
1773          n = (stbsp__uint32)bits;
1774          bits = 0;
1775       }
1776       while (n) {
1777          out -= 2;
1778          *(stbsp__uint16 *)out = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2];
1779          n /= 100;
1780          e += 2;
1781       }
1782       if (bits == 0) {
1783          if ((e) && (out[0] == '0')) {
1784             ++out;
1785             --e;
1786          }
1787          break;
1788       }
1789       while (out != o) {
1790          *--out = '0';
1791          ++e;
1792       }
1793    }
1794 
1795    *decimal_pos = tens;
1796    *start = out;
1797    *len = e;
1798    return ng;
1799 }
1800 
1801 #undef stbsp__ddmulthi
1802 #undef stbsp__ddrenorm
1803 #undef stbsp__ddmultlo
1804 #undef stbsp__ddmultlos
1805 #undef STBSP__SPECIAL
1806 #undef STBSP__COPYFP
1807 
1808 #endif // STB_SPRINTF_NOFLOAT
1809 
1810 // clean up
1811 #undef stbsp__uint16
1812 #undef stbsp__uint32
1813 #undef stbsp__int32
1814 #undef stbsp__uint64
1815 #undef stbsp__int64
1816 #undef STBSP__UNALIGNED
1817 
1818 #endif // STB_SPRINTF_IMPLEMENTATION
1819 
1820 /*
1821 ------------------------------------------------------------------------------
1822 This software is available under 2 licenses -- choose whichever you prefer.
1823 ------------------------------------------------------------------------------
1824 ALTERNATIVE A - MIT License
1825 Copyright (c) 2017 Sean Barrett
1826 Permission is hereby granted, free of charge, to any person obtaining a copy of
1827 this software and associated documentation files (the "Software"), to deal in
1828 the Software without restriction, including without limitation the rights to
1829 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
1830 of the Software, and to permit persons to whom the Software is furnished to do
1831 so, subject to the following conditions:
1832 The above copyright notice and this permission notice shall be included in all
1833 copies or substantial portions of the Software.
1834 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1835 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1836 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1837 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1838 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1839 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1840 SOFTWARE.
1841 ------------------------------------------------------------------------------
1842 ALTERNATIVE B - Public Domain (www.unlicense.org)
1843 This is free and unencumbered software released into the public domain.
1844 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
1845 software, either in source code form or as a compiled binary, for any purpose,
1846 commercial or non-commercial, and by any means.
1847 In jurisdictions that recognize copyright laws, the author or authors of this
1848 software dedicate any and all copyright interest in the software to the public
1849 domain. We make this dedication for the benefit of the public at large and to
1850 the detriment of our heirs and successors. We intend this dedication to be an
1851 overt act of relinquishment in perpetuity of all present and future rights to
1852 this software under copyright law.
1853 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1854 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1855 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1856 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
1857 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
1858 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1859 ------------------------------------------------------------------------------
1860 */
1861