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