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