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