Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
folium-app
GitHub Repository: folium-app/Folium
Path: blob/a-new-beginning/SharedDependencies/Sources/microprofile/include/stb_sprintf.h
2 views
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
STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char pcomma, char pperiod)
275
{
276
stbsp__period = pperiod;
277
stbsp__comma = pcomma;
278
}
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
static void stbsp__lead_sign(stbsp__uint32 fl, char *sign)
295
{
296
sign[0] = 0;
297
if (fl & STBSP__NEGATIVE) {
298
sign[0] = 1;
299
sign[1] = '-';
300
} else if (fl & STBSP__LEADINGSPACE) {
301
sign[0] = 1;
302
sign[1] = ' ';
303
} else if (fl & STBSP__LEADINGPLUS) {
304
sign[0] = 1;
305
sign[1] = '+';
306
}
307
}
308
309
static STBSP__ASAN stbsp__uint32 stbsp__strlen_limited(char const *s, stbsp__uint32 limit)
310
{
311
char const * sn = s;
312
313
// get up to 4-byte alignment
314
for (;;) {
315
if (((stbsp__uintptr)sn & 3) == 0)
316
break;
317
318
if (!limit || *sn == 0)
319
return (stbsp__uint32)(sn - s);
320
321
++sn;
322
--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
while (limit >= 4) {
331
stbsp__uint32 v = *(stbsp__uint32 *)sn;
332
// bit hack to find if there's a 0 byte in there
333
if ((v - 0x01010101) & (~v) & 0x80808080UL)
334
break;
335
336
sn += 4;
337
limit -= 4;
338
}
339
340
// handle the last few characters to find actual size
341
while (limit && *sn) {
342
++sn;
343
--limit;
344
}
345
346
return (stbsp__uint32)(sn - s);
347
}
348
349
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
int tlen = 0;
356
357
bf = buf;
358
f = fmt;
359
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
while (((stbsp__uintptr)f) & 3) {
394
schk1:
395
if (f[0] == '%')
396
goto scandd;
397
schk2:
398
if (f[0] == 0)
399
goto endfmt;
400
stbsp__chk_cb_buf(1);
401
*bf++ = f[0];
402
++f;
403
}
404
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
v = *(stbsp__uint32 *)f;
410
c = (~v) & 0x80808080;
411
if (((v ^ 0x25252525) - 0x01010101) & c)
412
goto schk1;
413
if ((v - 0x01010101) & c)
414
goto schk2;
415
if (callback)
416
if ((STB_SPRINTF_MIN - (int)(bf - buf)) < 4)
417
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
*(stbsp__uint32 *)bf = v;
428
}
429
bf += 4;
430
f += 4;
431
}
432
}
433
scandd:
434
435
++f;
436
437
// ok, we have a percent, read the modifiers first
438
fw = 0;
439
pr = -1;
440
fl = 0;
441
tz = 0;
442
443
// flags
444
for (;;) {
445
switch (f[0]) {
446
// if we have left justify
447
case '-':
448
fl |= STBSP__LEFTJUST;
449
++f;
450
continue;
451
// if we have leading plus
452
case '+':
453
fl |= STBSP__LEADINGPLUS;
454
++f;
455
continue;
456
// if we have leading space
457
case ' ':
458
fl |= STBSP__LEADINGSPACE;
459
++f;
460
continue;
461
// if we have leading 0x
462
case '#':
463
fl |= STBSP__LEADING_0X;
464
++f;
465
continue;
466
// if we have thousand commas
467
case '\'':
468
fl |= STBSP__TRIPLET_COMMA;
469
++f;
470
continue;
471
// if we have kilo marker (none->kilo->kibi->jedec)
472
case '$':
473
if (fl & STBSP__METRIC_SUFFIX) {
474
if (fl & STBSP__METRIC_1024) {
475
fl |= STBSP__METRIC_JEDEC;
476
} else {
477
fl |= STBSP__METRIC_1024;
478
}
479
} else {
480
fl |= STBSP__METRIC_SUFFIX;
481
}
482
++f;
483
continue;
484
// if we don't want space between metric suffix and number
485
case '_':
486
fl |= STBSP__METRIC_NOSPACE;
487
++f;
488
continue;
489
// if we have leading zero
490
case '0':
491
fl |= STBSP__LEADINGZERO;
492
++f;
493
goto flags_done;
494
default: goto flags_done;
495
}
496
}
497
flags_done:
498
499
// get the field width
500
if (f[0] == '*') {
501
fw = va_arg(va, stbsp__uint32);
502
++f;
503
} else {
504
while ((f[0] >= '0') && (f[0] <= '9')) {
505
fw = fw * 10 + f[0] - '0';
506
f++;
507
}
508
}
509
// get the precision
510
if (f[0] == '.') {
511
++f;
512
if (f[0] == '*') {
513
pr = va_arg(va, stbsp__uint32);
514
++f;
515
} else {
516
pr = 0;
517
while ((f[0] >= '0') && (f[0] <= '9')) {
518
pr = pr * 10 + f[0] - '0';
519
f++;
520
}
521
}
522
}
523
524
// handle integer size overrides
525
switch (f[0]) {
526
// are we halfwidth?
527
case 'h':
528
fl |= STBSP__HALFWIDTH;
529
++f;
530
if (f[0] == 'h')
531
++f; // QUARTERWIDTH
532
break;
533
// are we 64-bit (unix style)
534
case 'l':
535
fl |= ((sizeof(long) == 8) ? STBSP__INTMAX : 0);
536
++f;
537
if (f[0] == 'l') {
538
fl |= STBSP__INTMAX;
539
++f;
540
}
541
break;
542
// are we 64-bit on intmax? (c99)
543
case 'j':
544
fl |= (sizeof(size_t) == 8) ? STBSP__INTMAX : 0;
545
++f;
546
break;
547
// are we 64-bit on size_t or ptrdiff_t? (c99)
548
case 'z':
549
fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0;
550
++f;
551
break;
552
case 't':
553
fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0;
554
++f;
555
break;
556
// are we 64-bit (msft style)
557
case 'I':
558
if ((f[1] == '6') && (f[2] == '4')) {
559
fl |= STBSP__INTMAX;
560
f += 3;
561
} else if ((f[1] == '3') && (f[2] == '2')) {
562
f += 3;
563
} else {
564
fl |= ((sizeof(void *) == 8) ? STBSP__INTMAX : 0);
565
++f;
566
}
567
break;
568
default: break;
569
}
570
571
// handle each replacement
572
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
case 's':
588
// get the string
589
s = va_arg(va, char *);
590
if (s == 0)
591
s = (char *)"null";
592
// get the length, limited to desired precision
593
// always limit to ~0u chars since our counts are 32b
594
l = stbsp__strlen_limited(s, (pr >= 0) ? pr : ~0u);
595
lead[0] = 0;
596
tail[0] = 0;
597
pr = 0;
598
dp = 0;
599
cs = 0;
600
// copy the string in
601
goto scopy;
602
603
case 'c': // char
604
// get the character
605
s = num + STBSP__NUMSZ - 1;
606
*s = (char)va_arg(va, int);
607
l = 1;
608
lead[0] = 0;
609
tail[0] = 0;
610
pr = 0;
611
dp = 0;
612
cs = 0;
613
goto scopy;
614
615
case 'n': // weird write-bytes specifier
616
{
617
int *d = va_arg(va, int *);
618
*d = tlen + (int)(bf - buf);
619
} 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
case 'A': // hex float
640
case 'a': // hex float
641
h = (f[0] == 'A') ? hexu : hex;
642
fv = va_arg(va, double);
643
if (pr == -1)
644
pr = 6; // default is 6
645
// read the double into a string
646
if (stbsp__real_to_parts((stbsp__int64 *)&n64, &dp, fv))
647
fl |= STBSP__NEGATIVE;
648
649
s = num + 64;
650
651
stbsp__lead_sign(fl, lead);
652
653
if (dp == -1023)
654
dp = (n64) ? -1022 : 0;
655
else
656
n64 |= (((stbsp__uint64)1) << 52);
657
n64 <<= (64 - 56);
658
if (pr < 15)
659
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
lead[1 + lead[0]] = '0';
667
lead[2 + lead[0]] = 'x';
668
lead[0] += 2;
669
#endif
670
*s++ = h[(n64 >> 60) & 15];
671
n64 <<= 4;
672
if (pr)
673
*s++ = stbsp__period;
674
sn = s;
675
676
// print the bits
677
n = pr;
678
if (n > 13)
679
n = 13;
680
if (pr > (stbsp__int32)n)
681
tz = pr - n;
682
pr = 0;
683
while (n--) {
684
*s++ = h[(n64 >> 60) & 15];
685
n64 <<= 4;
686
}
687
688
// print the expo
689
tail[1] = h[17];
690
if (dp < 0) {
691
tail[2] = '-';
692
dp = -dp;
693
} else
694
tail[2] = '+';
695
n = (dp >= 1000) ? 6 : ((dp >= 100) ? 5 : ((dp >= 10) ? 4 : 3));
696
tail[0] = (char)n;
697
for (;;) {
698
tail[n] = '0' + dp % 10;
699
if (n <= 3)
700
break;
701
--n;
702
dp /= 10;
703
}
704
705
dp = (int)(s - sn);
706
l = (int)(s - (num + 64));
707
s = num + 64;
708
cs = 1 + (3 << 24);
709
goto scopy;
710
711
case 'G': // float
712
case 'g': // float
713
h = (f[0] == 'G') ? hexu : hex;
714
fv = va_arg(va, double);
715
if (pr == -1)
716
pr = 6;
717
else if (pr == 0)
718
pr = 1; // default is 6
719
// read the double into a string
720
if (stbsp__real_to_str(&sn, &l, num, &dp, fv, (pr - 1) | 0x80000000))
721
fl |= STBSP__NEGATIVE;
722
723
// clamp the precision and delete extra zeros after clamp
724
n = pr;
725
if (l > (stbsp__uint32)pr)
726
l = pr;
727
while ((l > 1) && (pr) && (sn[l - 1] == '0')) {
728
--pr;
729
--l;
730
}
731
732
// should we use %e
733
if ((dp <= -4) || (dp > (stbsp__int32)n)) {
734
if (pr > (stbsp__int32)l)
735
pr = l - 1;
736
else if (pr)
737
--pr; // when using %e, there is one digit before the decimal
738
goto doexpfromg;
739
}
740
// this is the insane action to get the pr to match %g semantics for %f
741
if (dp > 0) {
742
pr = (dp < (stbsp__int32)l) ? l - dp : 0;
743
} else {
744
pr = -dp + ((pr > (stbsp__int32)l) ? (stbsp__int32) l : pr);
745
}
746
goto dofloatfromg;
747
748
case 'E': // float
749
case 'e': // float
750
h = (f[0] == 'E') ? hexu : hex;
751
fv = va_arg(va, double);
752
if (pr == -1)
753
pr = 6; // default is 6
754
// read the double into a string
755
if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr | 0x80000000))
756
fl |= STBSP__NEGATIVE;
757
doexpfromg:
758
tail[0] = 0;
759
stbsp__lead_sign(fl, lead);
760
if (dp == STBSP__SPECIAL) {
761
s = (char *)sn;
762
cs = 0;
763
pr = 0;
764
goto scopy;
765
}
766
s = num + 64;
767
// handle leading chars
768
*s++ = sn[0];
769
770
if (pr)
771
*s++ = stbsp__period;
772
773
// handle after decimal
774
if ((l - 1) > (stbsp__uint32)pr)
775
l = pr + 1;
776
for (n = 1; n < l; n++)
777
*s++ = sn[n];
778
// trailing zeros
779
tz = pr - (l - 1);
780
pr = 0;
781
// dump expo
782
tail[1] = h[0xe];
783
dp -= 1;
784
if (dp < 0) {
785
tail[2] = '-';
786
dp = -dp;
787
} else
788
tail[2] = '+';
789
#ifdef STB_SPRINTF_MSVC_MODE
790
n = 5;
791
#else
792
n = (dp >= 100) ? 5 : 4;
793
#endif
794
tail[0] = (char)n;
795
for (;;) {
796
tail[n] = '0' + dp % 10;
797
if (n <= 3)
798
break;
799
--n;
800
dp /= 10;
801
}
802
cs = 1 + (3 << 24); // how many tens
803
goto flt_lead;
804
805
case 'f': // float
806
fv = va_arg(va, double);
807
doafloat:
808
// do kilos
809
if (fl & STBSP__METRIC_SUFFIX) {
810
double divisor;
811
divisor = 1000.0f;
812
if (fl & STBSP__METRIC_1024)
813
divisor = 1024.0;
814
while (fl < 0x4000000) {
815
if ((fv < divisor) && (fv > -divisor))
816
break;
817
fv /= divisor;
818
fl += 0x1000000;
819
}
820
}
821
if (pr == -1)
822
pr = 6; // default is 6
823
// read the double into a string
824
if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr))
825
fl |= STBSP__NEGATIVE;
826
dofloatfromg:
827
tail[0] = 0;
828
stbsp__lead_sign(fl, lead);
829
if (dp == STBSP__SPECIAL) {
830
s = (char *)sn;
831
cs = 0;
832
pr = 0;
833
goto scopy;
834
}
835
s = num + 64;
836
837
// handle the three decimal varieties
838
if (dp <= 0) {
839
stbsp__int32 i;
840
// handle 0.000*000xxxx
841
*s++ = '0';
842
if (pr)
843
*s++ = stbsp__period;
844
n = -dp;
845
if ((stbsp__int32)n > pr)
846
n = pr;
847
i = n;
848
while (i) {
849
if ((((stbsp__uintptr)s) & 3) == 0)
850
break;
851
*s++ = '0';
852
--i;
853
}
854
while (i >= 4) {
855
*(stbsp__uint32 *)s = 0x30303030;
856
s += 4;
857
i -= 4;
858
}
859
while (i) {
860
*s++ = '0';
861
--i;
862
}
863
if ((stbsp__int32)(l + n) > pr)
864
l = pr - n;
865
i = l;
866
while (i) {
867
*s++ = *sn++;
868
--i;
869
}
870
tz = pr - (n + l);
871
cs = 1 + (3 << 24); // how many tens did we write (for commas below)
872
} else {
873
cs = (fl & STBSP__TRIPLET_COMMA) ? ((600 - (stbsp__uint32)dp) % 3) : 0;
874
if ((stbsp__uint32)dp >= l) {
875
// handle xxxx000*000.0
876
n = 0;
877
for (;;) {
878
if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) {
879
cs = 0;
880
*s++ = stbsp__comma;
881
} else {
882
*s++ = sn[n];
883
++n;
884
if (n >= l)
885
break;
886
}
887
}
888
if (n < (stbsp__uint32)dp) {
889
n = dp - n;
890
if ((fl & STBSP__TRIPLET_COMMA) == 0) {
891
while (n) {
892
if ((((stbsp__uintptr)s) & 3) == 0)
893
break;
894
*s++ = '0';
895
--n;
896
}
897
while (n >= 4) {
898
*(stbsp__uint32 *)s = 0x30303030;
899
s += 4;
900
n -= 4;
901
}
902
}
903
while (n) {
904
if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) {
905
cs = 0;
906
*s++ = stbsp__comma;
907
} else {
908
*s++ = '0';
909
--n;
910
}
911
}
912
}
913
cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens
914
if (pr) {
915
*s++ = stbsp__period;
916
tz = pr;
917
}
918
} else {
919
// handle xxxxx.xxxx000*000
920
n = 0;
921
for (;;) {
922
if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) {
923
cs = 0;
924
*s++ = stbsp__comma;
925
} else {
926
*s++ = sn[n];
927
++n;
928
if (n >= (stbsp__uint32)dp)
929
break;
930
}
931
}
932
cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens
933
if (pr)
934
*s++ = stbsp__period;
935
if ((l - dp) > (stbsp__uint32)pr)
936
l = pr + dp;
937
while (n < l) {
938
*s++ = sn[n];
939
++n;
940
}
941
tz = pr - (l - dp);
942
}
943
}
944
pr = 0;
945
946
// handle k,m,g,t
947
if (fl & STBSP__METRIC_SUFFIX) {
948
char idx;
949
idx = 1;
950
if (fl & STBSP__METRIC_NOSPACE)
951
idx = 0;
952
tail[0] = idx;
953
tail[1] = ' ';
954
{
955
if (fl >> 24) { // SI kilo is 'k', JEDEC and SI kibits are 'K'.
956
if (fl & STBSP__METRIC_1024)
957
tail[idx + 1] = "_KMGT"[fl >> 24];
958
else
959
tail[idx + 1] = "_kMGT"[fl >> 24];
960
idx++;
961
// If printing kibits and not in jedec, add the 'i'.
962
if (fl & STBSP__METRIC_1024 && !(fl & STBSP__METRIC_JEDEC)) {
963
tail[idx + 1] = 'i';
964
idx++;
965
}
966
tail[0] = idx;
967
}
968
}
969
};
970
971
flt_lead:
972
// get the length that we copied
973
l = (stbsp__uint32)(s - (num + 64));
974
s = num + 64;
975
goto scopy;
976
#endif
977
978
case 'B': // upper binary
979
case 'b': // lower binary
980
h = (f[0] == 'B') ? hexu : hex;
981
lead[0] = 0;
982
if (fl & STBSP__LEADING_0X) {
983
lead[0] = 2;
984
lead[1] = '0';
985
lead[2] = h[0xb];
986
}
987
l = (8 << 4) | (1 << 8);
988
goto radixnum;
989
990
case 'o': // octal
991
h = hexu;
992
lead[0] = 0;
993
if (fl & STBSP__LEADING_0X) {
994
lead[0] = 1;
995
lead[1] = '0';
996
}
997
l = (3 << 4) | (3 << 8);
998
goto radixnum;
999
1000
case 'p': // pointer
1001
fl |= (sizeof(void *) == 8) ? STBSP__INTMAX : 0;
1002
pr = sizeof(void *) * 2;
1003
fl &= ~STBSP__LEADINGZERO; // 'p' only prints the pointer with zeros
1004
// fall through - to X
1005
1006
case 'X': // upper hex
1007
case 'x': // lower hex
1008
h = (f[0] == 'X') ? hexu : hex;
1009
l = (4 << 4) | (4 << 8);
1010
lead[0] = 0;
1011
if (fl & STBSP__LEADING_0X) {
1012
lead[0] = 2;
1013
lead[1] = '0';
1014
lead[2] = h[16];
1015
}
1016
radixnum:
1017
// get the number
1018
if (fl & STBSP__INTMAX)
1019
n64 = va_arg(va, stbsp__uint64);
1020
else
1021
n64 = va_arg(va, stbsp__uint32);
1022
1023
s = num + STBSP__NUMSZ;
1024
dp = 0;
1025
// clear tail, and clear leading if value is zero
1026
tail[0] = 0;
1027
if (n64 == 0) {
1028
lead[0] = 0;
1029
if (pr == 0) {
1030
l = 0;
1031
cs = 0;
1032
goto scopy;
1033
}
1034
}
1035
// convert to string
1036
for (;;) {
1037
*--s = h[n64 & ((1 << (l >> 8)) - 1)];
1038
n64 >>= (l >> 8);
1039
if (!((n64) || ((stbsp__int32)((num + STBSP__NUMSZ) - s) < pr)))
1040
break;
1041
if (fl & STBSP__TRIPLET_COMMA) {
1042
++l;
1043
if ((l & 15) == ((l >> 4) & 15)) {
1044
l &= ~15;
1045
*--s = stbsp__comma;
1046
}
1047
}
1048
};
1049
// get the tens and the comma pos
1050
cs = (stbsp__uint32)((num + STBSP__NUMSZ) - s) + ((((l >> 4) & 15)) << 24);
1051
// get the length that we copied
1052
l = (stbsp__uint32)((num + STBSP__NUMSZ) - s);
1053
// copy it
1054
goto scopy;
1055
1056
case 'u': // unsigned
1057
case 'i':
1058
case 'd': // integer
1059
// get the integer and abs it
1060
if (fl & STBSP__INTMAX) {
1061
stbsp__int64 i64 = va_arg(va, stbsp__int64);
1062
n64 = (stbsp__uint64)i64;
1063
if ((f[0] != 'u') && (i64 < 0)) {
1064
n64 = (stbsp__uint64)-i64;
1065
fl |= STBSP__NEGATIVE;
1066
}
1067
} else {
1068
stbsp__int32 i = va_arg(va, stbsp__int32);
1069
n64 = (stbsp__uint32)i;
1070
if ((f[0] != 'u') && (i < 0)) {
1071
n64 = (stbsp__uint32)-i;
1072
fl |= STBSP__NEGATIVE;
1073
}
1074
}
1075
1076
#ifndef STB_SPRINTF_NOFLOAT
1077
if (fl & STBSP__METRIC_SUFFIX) {
1078
if (n64 < 1024)
1079
pr = 0;
1080
else if (pr == -1)
1081
pr = 1;
1082
fv = (double)(stbsp__int64)n64;
1083
goto doafloat;
1084
}
1085
#endif
1086
1087
// convert to string
1088
s = num + STBSP__NUMSZ;
1089
l = 0;
1090
1091
for (;;) {
1092
// do in 32-bit chunks (avoid lots of 64-bit divides even with constant denominators)
1093
char *o = s - 8;
1094
if (n64 >= 100000000) {
1095
n = (stbsp__uint32)(n64 % 100000000);
1096
n64 /= 100000000;
1097
} else {
1098
n = (stbsp__uint32)n64;
1099
n64 = 0;
1100
}
1101
if ((fl & STBSP__TRIPLET_COMMA) == 0) {
1102
do {
1103
s -= 2;
1104
*(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2];
1105
n /= 100;
1106
} while (n);
1107
}
1108
while (n) {
1109
if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) {
1110
l = 0;
1111
*--s = stbsp__comma;
1112
--o;
1113
} else {
1114
*--s = (char)(n % 10) + '0';
1115
n /= 10;
1116
}
1117
}
1118
if (n64 == 0) {
1119
if ((s[0] == '0') && (s != (num + STBSP__NUMSZ)))
1120
++s;
1121
break;
1122
}
1123
while (s != o)
1124
if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) {
1125
l = 0;
1126
*--s = stbsp__comma;
1127
--o;
1128
} else {
1129
*--s = '0';
1130
}
1131
}
1132
1133
tail[0] = 0;
1134
stbsp__lead_sign(fl, lead);
1135
1136
// get the length that we copied
1137
l = (stbsp__uint32)((num + STBSP__NUMSZ) - s);
1138
if (l == 0) {
1139
*--s = '0';
1140
l = 1;
1141
}
1142
cs = l + (3 << 24);
1143
if (pr < 0)
1144
pr = 0;
1145
1146
scopy:
1147
// get fw=leading/trailing space, pr=leading zeros
1148
if (pr < (stbsp__int32)l)
1149
pr = l;
1150
n = pr + lead[0] + tail[0] + tz;
1151
if (fw < (stbsp__int32)n)
1152
fw = n;
1153
fw -= n;
1154
pr -= l;
1155
1156
// handle right justify and leading zeros
1157
if ((fl & STBSP__LEFTJUST) == 0) {
1158
if (fl & STBSP__LEADINGZERO) // if leading zeros, everything is in pr
1159
{
1160
pr = (fw > pr) ? fw : pr;
1161
fw = 0;
1162
} else {
1163
fl &= ~STBSP__TRIPLET_COMMA; // if no leading zeros, then no commas
1164
}
1165
}
1166
1167
// copy the spaces and/or zeros
1168
if (fw + pr) {
1169
stbsp__int32 i;
1170
stbsp__uint32 c;
1171
1172
// copy leading spaces (or when doing %8.4d stuff)
1173
if ((fl & STBSP__LEFTJUST) == 0)
1174
while (fw > 0) {
1175
stbsp__cb_buf_clamp(i, fw);
1176
fw -= i;
1177
while (i) {
1178
if ((((stbsp__uintptr)bf) & 3) == 0)
1179
break;
1180
*bf++ = ' ';
1181
--i;
1182
}
1183
while (i >= 4) {
1184
*(stbsp__uint32 *)bf = 0x20202020;
1185
bf += 4;
1186
i -= 4;
1187
}
1188
while (i) {
1189
*bf++ = ' ';
1190
--i;
1191
}
1192
stbsp__chk_cb_buf(1);
1193
}
1194
1195
// copy leader
1196
sn = lead + 1;
1197
while (lead[0]) {
1198
stbsp__cb_buf_clamp(i, lead[0]);
1199
lead[0] -= (char)i;
1200
while (i) {
1201
*bf++ = *sn++;
1202
--i;
1203
}
1204
stbsp__chk_cb_buf(1);
1205
}
1206
1207
// copy leading zeros
1208
c = cs >> 24;
1209
cs &= 0xffffff;
1210
cs = (fl & STBSP__TRIPLET_COMMA) ? ((stbsp__uint32)(c - ((pr + cs) % (c + 1)))) : 0;
1211
while (pr > 0) {
1212
stbsp__cb_buf_clamp(i, pr);
1213
pr -= i;
1214
if ((fl & STBSP__TRIPLET_COMMA) == 0) {
1215
while (i) {
1216
if ((((stbsp__uintptr)bf) & 3) == 0)
1217
break;
1218
*bf++ = '0';
1219
--i;
1220
}
1221
while (i >= 4) {
1222
*(stbsp__uint32 *)bf = 0x30303030;
1223
bf += 4;
1224
i -= 4;
1225
}
1226
}
1227
while (i) {
1228
if ((fl & STBSP__TRIPLET_COMMA) && (cs++ == c)) {
1229
cs = 0;
1230
*bf++ = stbsp__comma;
1231
} else
1232
*bf++ = '0';
1233
--i;
1234
}
1235
stbsp__chk_cb_buf(1);
1236
}
1237
}
1238
1239
// copy leader if there is still one
1240
sn = lead + 1;
1241
while (lead[0]) {
1242
stbsp__int32 i;
1243
stbsp__cb_buf_clamp(i, lead[0]);
1244
lead[0] -= (char)i;
1245
while (i) {
1246
*bf++ = *sn++;
1247
--i;
1248
}
1249
stbsp__chk_cb_buf(1);
1250
}
1251
1252
// copy the string
1253
n = l;
1254
while (n) {
1255
stbsp__int32 i;
1256
stbsp__cb_buf_clamp(i, n);
1257
n -= i;
1258
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
while (i) {
1265
*bf++ = *s++;
1266
--i;
1267
}
1268
stbsp__chk_cb_buf(1);
1269
}
1270
1271
// copy trailing zeros
1272
while (tz) {
1273
stbsp__int32 i;
1274
stbsp__cb_buf_clamp(i, tz);
1275
tz -= i;
1276
while (i) {
1277
if ((((stbsp__uintptr)bf) & 3) == 0)
1278
break;
1279
*bf++ = '0';
1280
--i;
1281
}
1282
while (i >= 4) {
1283
*(stbsp__uint32 *)bf = 0x30303030;
1284
bf += 4;
1285
i -= 4;
1286
}
1287
while (i) {
1288
*bf++ = '0';
1289
--i;
1290
}
1291
stbsp__chk_cb_buf(1);
1292
}
1293
1294
// copy tail if there is one
1295
sn = tail + 1;
1296
while (tail[0]) {
1297
stbsp__int32 i;
1298
stbsp__cb_buf_clamp(i, tail[0]);
1299
tail[0] -= (char)i;
1300
while (i) {
1301
*bf++ = *sn++;
1302
--i;
1303
}
1304
stbsp__chk_cb_buf(1);
1305
}
1306
1307
// handle the left justify
1308
if (fl & STBSP__LEFTJUST)
1309
if (fw > 0) {
1310
while (fw) {
1311
stbsp__int32 i;
1312
stbsp__cb_buf_clamp(i, fw);
1313
fw -= i;
1314
while (i) {
1315
if ((((stbsp__uintptr)bf) & 3) == 0)
1316
break;
1317
*bf++ = ' ';
1318
--i;
1319
}
1320
while (i >= 4) {
1321
*(stbsp__uint32 *)bf = 0x20202020;
1322
bf += 4;
1323
i -= 4;
1324
}
1325
while (i--)
1326
*bf++ = ' ';
1327
stbsp__chk_cb_buf(1);
1328
}
1329
}
1330
break;
1331
1332
default: // unknown, just copy code
1333
s = num + STBSP__NUMSZ - 1;
1334
*s = f[0];
1335
l = 1;
1336
fw = fl = 0;
1337
lead[0] = 0;
1338
tail[0] = 0;
1339
pr = 0;
1340
dp = 0;
1341
cs = 0;
1342
goto scopy;
1343
}
1344
++f;
1345
}
1346
endfmt:
1347
1348
if (!callback)
1349
*bf = 0;
1350
else
1351
stbsp__flush_cb();
1352
1353
done:
1354
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
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...)
1377
{
1378
int result;
1379
va_list va;
1380
va_start(va, fmt);
1381
result = STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va);
1382
va_end(va);
1383
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
static char *stbsp__clamp_callback(const char *buf, void *user, int len)
1394
{
1395
stbsp__context *c = (stbsp__context *)user;
1396
c->length += len;
1397
1398
if (len > c->count)
1399
len = c->count;
1400
1401
if (len) {
1402
if (buf != c->buf) {
1403
const char *s, *se;
1404
char *d;
1405
d = c->buf;
1406
s = buf;
1407
se = buf + len;
1408
do {
1409
*d++ = *s++;
1410
} while (s < se);
1411
}
1412
c->buf += len;
1413
c->count -= len;
1414
}
1415
1416
if (c->count <= 0)
1417
return c->tmp;
1418
return (c->count >= STB_SPRINTF_MIN) ? c->buf : c->tmp; // go direct into buffer if you can
1419
}
1420
1421
static char * stbsp__count_clamp_callback( const char * buf, void * user, int len )
1422
{
1423
stbsp__context * c = (stbsp__context*)user;
1424
(void) sizeof(buf);
1425
1426
c->length += len;
1427
return c->tmp; // go direct into buffer if you can
1428
}
1429
1430
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, char const * fmt, va_list va )
1431
{
1432
stbsp__context c;
1433
1434
if ( (count == 0) && !buf )
1435
{
1436
c.length = 0;
1437
1438
STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__count_clamp_callback, &c, c.tmp, fmt, va );
1439
}
1440
else
1441
{
1442
int l;
1443
1444
c.buf = buf;
1445
c.count = count;
1446
c.length = 0;
1447
1448
STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__clamp_callback, &c, stbsp__clamp_callback(0,&c,0), fmt, va );
1449
1450
// zero-terminate
1451
l = (int)( c.buf - buf );
1452
if ( l >= count ) // should never be greater, only equal (or less) than count
1453
l = count - 1;
1454
buf[l] = 0;
1455
}
1456
1457
return c.length;
1458
}
1459
1460
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...)
1461
{
1462
int result;
1463
va_list va;
1464
va_start(va, fmt);
1465
1466
result = STB_SPRINTF_DECORATE(vsnprintf)(buf, count, fmt, va);
1467
va_end(va);
1468
1469
return result;
1470
}
1471
1472
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va)
1473
{
1474
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
static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value)
1492
{
1493
double d;
1494
stbsp__int64 b = 0;
1495
1496
// load value and round at the frac_digits
1497
d = value;
1498
1499
STBSP__COPYFP(b, d);
1500
1501
*bits = b & ((((stbsp__uint64)1) << 52) - 1);
1502
*expo = (stbsp__int32)(((b >> 52) & 2047) - 1023);
1503
1504
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
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
if ((power >= 0) && (power <= 22)) {
1642
stbsp__ddmulthi(ph, pl, d, stbsp__bot[power]);
1643
} else {
1644
stbsp__int32 e, et, eb;
1645
double p2h, p2l;
1646
1647
e = power;
1648
if (power < 0)
1649
e = -e;
1650
et = (e * 0x2c9) >> 14; /* %23 */
1651
if (et > 13)
1652
et = 13;
1653
eb = e - (et * 23);
1654
1655
ph = d;
1656
pl = 0.0;
1657
if (power < 0) {
1658
if (eb) {
1659
--eb;
1660
stbsp__ddmulthi(ph, pl, d, stbsp__negbot[eb]);
1661
stbsp__ddmultlos(ph, pl, d, stbsp__negboterr[eb]);
1662
}
1663
if (et) {
1664
stbsp__ddrenorm(ph, pl);
1665
--et;
1666
stbsp__ddmulthi(p2h, p2l, ph, stbsp__negtop[et]);
1667
stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__negtop[et], stbsp__negtoperr[et]);
1668
ph = p2h;
1669
pl = p2l;
1670
}
1671
} else {
1672
if (eb) {
1673
e = eb;
1674
if (eb > 22)
1675
eb = 22;
1676
e -= eb;
1677
stbsp__ddmulthi(ph, pl, d, stbsp__bot[eb]);
1678
if (e) {
1679
stbsp__ddrenorm(ph, pl);
1680
stbsp__ddmulthi(p2h, p2l, ph, stbsp__bot[e]);
1681
stbsp__ddmultlos(p2h, p2l, stbsp__bot[e], pl);
1682
ph = p2h;
1683
pl = p2l;
1684
}
1685
}
1686
if (et) {
1687
stbsp__ddrenorm(ph, pl);
1688
--et;
1689
stbsp__ddmulthi(p2h, p2l, ph, stbsp__top[et]);
1690
stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__top[et], stbsp__toperr[et]);
1691
ph = p2h;
1692
pl = p2l;
1693
}
1694
}
1695
}
1696
stbsp__ddrenorm(ph, pl);
1697
*ohi = ph;
1698
*olo = pl;
1699
}
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
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
stbsp__int64 bits = 0;
1709
stbsp__int32 expo, e, ng, tens;
1710
1711
d = value;
1712
STBSP__COPYFP(bits, d);
1713
expo = (stbsp__int32)((bits >> 52) & 2047);
1714
ng = (stbsp__int32)((stbsp__uint64) bits >> 63);
1715
if (ng)
1716
d = -d;
1717
1718
if (expo == 2047) // is nan or inf?
1719
{
1720
*start = (bits & ((((stbsp__uint64)1) << 52) - 1)) ? "NaN" : "Inf";
1721
*decimal_pos = STBSP__SPECIAL;
1722
*len = 3;
1723
return ng;
1724
}
1725
1726
if (expo == 0) // is zero or denormal
1727
{
1728
if (((stbsp__uint64) bits << 1) == 0) // do zero
1729
{
1730
*decimal_pos = 1;
1731
*start = out;
1732
out[0] = '0';
1733
*len = 1;
1734
return ng;
1735
}
1736
// find the right expo for denormals
1737
{
1738
stbsp__int64 v = ((stbsp__uint64)1) << 51;
1739
while ((bits & v) == 0) {
1740
--expo;
1741
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
tens = expo - 1023;
1752
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
stbsp__raise_to_power10(&ph, &pl, d, 18 - tens);
1756
1757
// get full as much precision from double-double as possible
1758
stbsp__ddtoS64(bits, ph, pl);
1759
1760
// check if we undershot
1761
if (((stbsp__uint64)bits) >= stbsp__tento19th)
1762
++tens;
1763
}
1764
1765
// now do the rounding in integer land
1766
frac_digits = (frac_digits & 0x80000000) ? ((frac_digits & 0x7ffffff) + 1) : (tens + frac_digits);
1767
if ((frac_digits < 24)) {
1768
stbsp__uint32 dg = 1;
1769
if ((stbsp__uint64)bits >= stbsp__powten[9])
1770
dg = 10;
1771
while ((stbsp__uint64)bits >= stbsp__powten[dg]) {
1772
++dg;
1773
if (dg == 20)
1774
goto noround;
1775
}
1776
if (frac_digits < dg) {
1777
stbsp__uint64 r;
1778
// add 0.5 at the right position and round
1779
e = dg - frac_digits;
1780
if ((stbsp__uint32)e >= 24)
1781
goto noround;
1782
r = stbsp__powten[e];
1783
bits = bits + (r / 2);
1784
if ((stbsp__uint64)bits >= stbsp__powten[dg])
1785
++tens;
1786
bits /= r;
1787
}
1788
noround:;
1789
}
1790
1791
// kill long trailing runs of zeros
1792
if (bits) {
1793
stbsp__uint32 n;
1794
for (;;) {
1795
if (bits <= 0xffffffff)
1796
break;
1797
if (bits % 1000)
1798
goto donez;
1799
bits /= 1000;
1800
}
1801
n = (stbsp__uint32)bits;
1802
while ((n % 1000) == 0)
1803
n /= 1000;
1804
bits = n;
1805
donez:;
1806
}
1807
1808
// convert to string
1809
out += 64;
1810
e = 0;
1811
for (;;) {
1812
stbsp__uint32 n;
1813
char *o = out - 8;
1814
// do the conversion in chunks of U32s (avoid most 64-bit divides, worth it, constant denomiators be damned)
1815
if (bits >= 100000000) {
1816
n = (stbsp__uint32)(bits % 100000000);
1817
bits /= 100000000;
1818
} else {
1819
n = (stbsp__uint32)bits;
1820
bits = 0;
1821
}
1822
while (n) {
1823
out -= 2;
1824
*(stbsp__uint16 *)out = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2];
1825
n /= 100;
1826
e += 2;
1827
}
1828
if (bits == 0) {
1829
if ((e) && (out[0] == '0')) {
1830
++out;
1831
--e;
1832
}
1833
break;
1834
}
1835
while (out != o) {
1836
*--out = '0';
1837
++e;
1838
}
1839
}
1840
1841
*decimal_pos = tens;
1842
*start = out;
1843
*len = e;
1844
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
*/
1907
1908