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