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