2017-01-16 11:51:24 +03:00
// stb_sprintf - v1.02 - public domain snprintf() implementation
2016-12-05 14:48:37 +03:00
// originally by Jeff Roberts / RAD Game Tools, 2015/10/20
// http://github.com/nothings/stb
//
// allowed types: sc uidBboXx p AaGgEef n
// lengths : h ll j z t I64 I32 I
2017-01-16 10:57:53 +03:00
//
// Contributors (bugfixes):
// github:d26435
2017-01-16 11:05:58 +03:00
// github:trex78
2017-03-03 18:53:07 +03:00
//
// LICENSE:
//
// See end of file for license information.
2016-12-05 14:48:37 +03:00
# ifndef STB_SPRINTF_H_INCLUDE
# define STB_SPRINTF_H_INCLUDE
2016-12-05 13:57:06 +03:00
/*
Single file sprintf replacement .
Originally written by Jeff Roberts at RAD Game Tools - 2015 / 10 / 20.
Hereby placed in public domain .
This is a full sprintf replacement that supports everything that
the C runtime sprintfs support , including float / double , 64 - bit integers ,
hex floats , field parameters ( % * . * d stuff ) , length reads backs , etc .
Why would you need this if sprintf already exists ? Well , first off ,
it ' s * much * faster ( see below ) . It ' s also much smaller than the CRT
versions code - space - wise . We ' ve also added some simple improvements
that are super handy ( commas in thousands , callbacks at buffer full ,
for example ) . Finally , the format strings for MSVC and GCC differ
for 64 - bit integers ( among other small things ) , so this lets you use
the same format strings in cross platform code .
It uses the standard single file trick of being both the header file
and the source itself . If you just include it normally , you just get
the header file function definitions . To get the code , you include
2016-12-05 14:48:37 +03:00
it from a C or C + + file and define STB_SPRINTF_IMPLEMENTATION first .
2016-12-05 13:57:06 +03:00
It only uses va_args macros from the C runtime to do it ' s work . It
does cast doubles to S64s and shifts and divides U64s , which does
drag in CRT code on most platforms .
It compiles to roughly 8 K with float support , and 4 K without .
As a comparison , when using MSVC static libs , calling sprintf drags
in 16 K .
API :
= = = =
2016-12-05 14:48:37 +03:00
int stbsp_sprintf ( char * buf , char const * fmt , . . . )
int stbsp_snprintf ( char * buf , int count , char const * fmt , . . . )
2016-12-05 17:58:30 +03:00
Convert an arg list into a buffer . stbsp_snprintf always returns
2016-12-05 13:57:06 +03:00
a zero - terminated string ( unlike regular snprintf ) .
2016-12-05 14:48:37 +03:00
int stbsp_vsprintf ( char * buf , char const * fmt , va_list va )
int stbsp_vsnprintf ( char * buf , int count , char const * fmt , va_list va )
2016-12-05 17:58:30 +03:00
Convert a va_list arg list into a buffer . stbsp_vsnprintf always returns
2016-12-05 13:57:06 +03:00
a zero - terminated string ( unlike regular snprintf ) .
2016-12-05 14:48:37 +03:00
int stbsp_vsprintfcb ( STBSP_SPRINTFCB * callback , void * user , char * buf , char const * fmt , va_list va )
typedef char * STBSP_SPRINTFCB ( char const * buf , void * user , int len ) ;
Convert into a buffer , calling back every STB_SPRINTF_MIN chars .
2016-12-05 13:57:06 +03:00
Your callback can then copy the chars out , print them or whatever .
This function is actually the workhorse for everything else .
2016-12-05 14:48:37 +03:00
The buffer you pass in must hold at least STB_SPRINTF_MIN characters .
2016-12-05 13:57:06 +03:00
// you return the next buffer to use or 0 to stop converting
2016-12-05 15:49:39 +03:00
void stbsp_set_separators ( char comma , char period )
2016-12-05 13:57:06 +03:00
Set the comma and period characters to use .
FLOATS / DOUBLES :
= = = = = = = = = = = = = = =
This code uses a internal float - > ascii conversion method that uses
doubles with error correction ( double - doubles , for ~ 105 bits of
precision ) . This conversion is round - trip perfect - that is , an atof
of the values output here will give you the bit - exact double back .
One difference is that our insignificant digits will be different than
with MSVC or GCC ( but they don ' t match each other either ) . We also
don ' t attempt to find the minimum length matching float ( pre - MSVC15
doesn ' t either ) .
2016-12-05 14:48:37 +03:00
If you don ' t need float or doubles at all , define STB_SPRINTF_NOFLOAT
2016-12-05 13:57:06 +03:00
and you ' ll save 4 K of code space .
2016-12-05 14:53:54 +03:00
64 - BIT INTS :
2016-12-05 13:57:06 +03:00
= = = = = = = = = = = =
This library also supports 64 - bit integers and you can use MSVC style or
GCC style indicators ( % I64d or % lld ) . It supports the C99 specifiers
for size_t and ptr_diff_t ( % jd % zd ) as well .
EXTRAS :
= = = = = = =
Like some GCCs , for integers and floats , you can use a ' ( single quote )
specifier and commas will be inserted on the thousands : " %'d " on 12345
would print 12 , 345.
For integers and floats , you can use a " $ " specifier and the number
will be converted to float and then divided to get kilo , mega , giga or
tera and then printed , so " %$d " 1024 is " 1.0 k " , " %$.2d " 2536000 is
" 2.42 m " , etc .
In addition to octal and hexadecimal conversions , you can print
integers in binary : " %b " for 256 would print 100.
PERFORMANCE vs MSVC 2008 32 - / 64 - bit ( GCC is even slower than MSVC ) :
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
" %d " across all 32 - bit ints ( 4.8 x / 4.0 x faster than 32 - / 64 - bit MSVC )
" %24d " across all 32 - bit ints ( 4.5 x / 4.2 x faster )
" %x " across all 32 - bit ints ( 4.5 x / 3.8 x faster )
" %08x " across all 32 - bit ints ( 4.3 x / 3.8 x faster )
" %f " across e - 10 to e + 10 floats ( 7.3 x / 6.0 x faster )
" %e " across e - 10 to e + 10 floats ( 8.1 x / 6.0 x faster )
" %g " across e - 10 to e + 10 floats ( 10.0 x / 7.1 x faster )
" %f " for values near e - 300 ( 7.9 x / 6.5 x faster )
" %f " for values near e + 300 ( 10.0 x / 9.1 x faster )
" %e " for values near e - 300 ( 10.1 x / 7.0 x faster )
" %e " for values near e + 300 ( 9.2 x / 6.0 x faster )
" %.320f " for values near e - 300 ( 12.6 x / 11.2 x faster )
" %a " for random values ( 8.6 x / 4.3 x faster )
" %I64d " for 64 - bits with 32 - bit values ( 4.8 x / 3.4 x faster )
" %I64d " for 64 - bits > 32 - bit values ( 4.9 x / 5.5 x faster )
" %s%s%s " for 64 char strings ( 7.1 x / 7.3 x faster )
" ...512 char string... " ( 35.0 x / 32.5 x faster ! )
*/
2017-01-16 10:57:53 +03:00
# if defined(__has_feature)
# if __has_feature(address_sanitizer)
# define STBI__ASAN __attribute__((no_sanitize("address")))
# endif
# endif
# ifndef STBI__ASAN
# define STBI__ASAN
# endif
2016-12-05 14:48:37 +03:00
# ifdef STB_SPRINTF_STATIC
# define STBSP__PUBLICDEC static
2017-01-16 10:57:53 +03:00
# define STBSP__PUBLICDEF static STBI__ASAN
2016-12-05 13:57:06 +03:00
# else
# ifdef __cplusplus
2016-12-05 14:48:37 +03:00
# define STBSP__PUBLICDEC extern "C"
2017-01-16 10:57:53 +03:00
# define STBSP__PUBLICDEF extern "C" STBI__ASAN
2016-12-05 13:57:06 +03:00
# else
2017-01-16 10:57:53 +03:00
# define STBSP__PUBLICDEC extern
# define STBSP__PUBLICDEF STBI__ASAN
2016-12-05 13:57:06 +03:00
# endif
# endif
# include <stdarg.h> // for va_list()
2016-12-05 14:48:37 +03:00
# ifndef STB_SPRINTF_MIN
# define STB_SPRINTF_MIN 512 // how many characters per callback
2016-12-05 13:57:06 +03:00
# endif
2016-12-05 14:48:37 +03:00
typedef char * STBSP_SPRINTFCB ( char * buf , void * user , int len ) ;
2016-12-05 13:57:06 +03:00
2016-12-05 14:48:37 +03:00
# ifndef STB_SPRINTF_DECORATE
# define STB_SPRINTF_DECORATE(name) stbsp_##name // define this before including if you want to change the names
2016-12-05 13:57:06 +03:00
# endif
2016-12-05 14:48:37 +03:00
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE ( vsprintf ) ( char * buf , char const * fmt , va_list va ) ;
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE ( vsnprintf ) ( char * buf , int count , char const * fmt , va_list va ) ;
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE ( sprintf ) ( char * buf , char const * fmt , . . . ) ;
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE ( snprintf ) ( char * buf , int count , char const * fmt , . . . ) ;
2016-12-05 13:57:06 +03:00
2016-12-05 14:48:37 +03:00
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE ( vsprintfcb ) ( STBSP_SPRINTFCB * callback , void * user , char * buf , char const * fmt , va_list va ) ;
STBSP__PUBLICDEF void STB_SPRINTF_DECORATE ( set_separators ) ( char comma , char period ) ;
2016-12-05 13:57:06 +03:00
2016-12-05 14:48:37 +03:00
# endif // STB_SPRINTF_H_INCLUDE
2016-12-05 13:57:06 +03:00
2016-12-05 17:53:36 +03:00
# ifdef STB_SPRINTF_IMPLEMENTATION
2016-12-05 13:57:06 +03:00
# include <stdlib.h> // for va_arg()
2016-12-05 14:48:37 +03:00
# define stbsp__uint32 unsigned int
# define stbsp__int32 signed int
2016-12-05 13:57:06 +03:00
# ifdef _MSC_VER
2016-12-05 14:48:37 +03:00
# define stbsp__uint64 unsigned __int64
# define stbsp__int64 signed __int64
2016-12-05 13:57:06 +03:00
# else
2016-12-05 14:48:37 +03:00
# define stbsp__uint64 unsigned long long
# define stbsp__int64 signed long long
2016-12-05 13:57:06 +03:00
# endif
2016-12-05 14:48:37 +03:00
# define stbsp__uint16 unsigned short
2016-12-05 13:57:06 +03:00
2016-12-05 14:48:37 +03:00
# ifndef stbsp__uintptr
2016-12-05 13:57:06 +03:00
# if defined(__ppc64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64)
2016-12-05 14:48:37 +03:00
# define stbsp__uintptr stbsp__uint64
2016-12-05 13:57:06 +03:00
# else
2016-12-05 14:48:37 +03:00
# define stbsp__uintptr stbsp__uint32
2016-12-05 13:57:06 +03:00
# endif
# endif
2016-12-05 14:48:37 +03:00
# ifndef STB_SPRINTF_MSVC_MODE // used for MSVC2013 and earlier (MSVC2015 matches GCC)
2016-12-05 13:57:06 +03:00
# if defined(_MSC_VER) && (_MSC_VER<1900)
2016-12-05 14:48:37 +03:00
# define STB_SPRINTF_MSVC_MODE
2016-12-05 13:57:06 +03:00
# endif
# endif
2016-12-05 17:58:30 +03:00
# ifdef STB_SPRINTF_NOUNALIGNED // define this before inclusion to force stbsp_sprintf to always use aligned accesses
2016-12-05 14:48:37 +03:00
# define STBSP__UNALIGNED(code)
2016-12-05 13:57:06 +03:00
# else
2016-12-05 14:48:37 +03:00
# define STBSP__UNALIGNED(code) code
2016-12-05 13:57:06 +03:00
# endif
2016-12-05 14:48:37 +03:00
# ifndef STB_SPRINTF_NOFLOAT
2016-12-05 13:57:06 +03:00
// internal float utility functions
2016-12-05 14:48:37 +03:00
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 ) ;
static stbsp__int32 stbsp__real_to_parts ( stbsp__int64 * bits , stbsp__int32 * expo , double value ) ;
# define STBSP__SPECIAL 0x7000
2016-12-05 13:57:06 +03:00
# endif
2016-12-05 14:48:37 +03:00
static char stbsp__period = ' . ' ;
static char stbsp__comma = ' , ' ;
static char stbsp__digitpair [ 201 ] = " 00010203040506070809101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899 " ;
2016-12-05 13:57:06 +03:00
2016-12-05 14:48:37 +03:00
STBSP__PUBLICDEF void STB_SPRINTF_DECORATE ( set_separators ) ( char pcomma , char pperiod )
2016-12-05 13:57:06 +03:00
{
2016-12-05 14:48:37 +03:00
stbsp__period = pperiod ;
stbsp__comma = pcomma ;
2016-12-05 13:57:06 +03:00
}
2016-12-05 14:48:37 +03:00
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE ( vsprintfcb ) ( STBSP_SPRINTFCB * callback , void * user , char * buf , char const * fmt , va_list va )
2016-12-05 13:57:06 +03:00
{
static char hex [ ] = " 0123456789abcdefxp " ;
static char hexu [ ] = " 0123456789ABCDEFXP " ;
char * bf ;
char const * f ;
int tlen = 0 ;
bf = buf ;
f = fmt ;
for ( ; ; )
{
2016-12-05 14:48:37 +03:00
stbsp__int32 fw , pr , tz ; stbsp__uint32 fl ;
# define STBSP__LEFTJUST 1
# define STBSP__LEADINGPLUS 2
# define STBSP__LEADINGSPACE 4
# define STBSP__LEADING_0X 8
# define STBSP__LEADINGZERO 16
# define STBSP__INTMAX 32
# define STBSP__TRIPLET_COMMA 64
# define STBSP__NEGATIVE 128
# define STBSP__METRIC_SUFFIX 256
# define STBSP__HALFWIDTH 512
2016-12-05 13:57:06 +03:00
// macros for the callback buffer stuff
2016-12-05 14:48:37 +03:00
# define stbsp__chk_cb_bufL(bytes) { int len = (int)(bf-buf); if ((len+(bytes))>=STB_SPRINTF_MIN) { tlen+=len; if (0==(bf=buf=callback(buf,user,len))) goto done; } }
# define stbsp__chk_cb_buf(bytes) { if ( callback ) { stbsp__chk_cb_bufL(bytes); } }
# define stbsp__flush_cb() { stbsp__chk_cb_bufL(STB_SPRINTF_MIN-1); } //flush if there is even one byte in the buffer
# define stbsp__cb_buf_clamp(cl,v) cl = v; if ( callback ) { int lg = STB_SPRINTF_MIN-(int)(bf-buf); if (cl>lg) cl=lg; }
2016-12-05 13:57:06 +03:00
// fast copy everything up to the next % (or end of string)
for ( ; ; )
{
2016-12-05 14:48:37 +03:00
while ( ( ( stbsp__uintptr ) f ) & 3 )
2016-12-05 13:57:06 +03:00
{
schk1 : if ( f [ 0 ] = = ' % ' ) goto scandd ;
schk2 : if ( f [ 0 ] = = 0 ) goto endfmt ;
2016-12-05 14:48:37 +03:00
stbsp__chk_cb_buf ( 1 ) ; * bf + + = f [ 0 ] ; + + f ;
2016-12-05 13:57:06 +03:00
}
for ( ; ; )
{
2016-12-06 00:03:05 +03:00
// Check if the next 4 bytes contain %(0x25) or end of string.
// Using the 'hasless' trick:
// https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord
2016-12-05 14:48:37 +03:00
stbsp__uint32 v , c ;
v = * ( stbsp__uint32 * ) f ; c = ( ~ v ) & 0x80808080 ;
2016-12-06 00:03:05 +03:00
if ( ( ( v ^ 0x25252525 ) - 0x01010101 ) & c ) goto schk1 ;
2016-12-05 13:57:06 +03:00
if ( ( v - 0x01010101 ) & c ) goto schk2 ;
2016-12-05 14:48:37 +03:00
if ( callback ) if ( ( STB_SPRINTF_MIN - ( int ) ( bf - buf ) ) < 4 ) goto schk1 ;
* ( stbsp__uint32 * ) bf = v ; bf + = 4 ; f + = 4 ;
2016-12-05 13:57:06 +03:00
}
} scandd :
+ + f ;
// ok, we have a percent, read the modifiers first
fw = 0 ; pr = - 1 ; fl = 0 ; tz = 0 ;
// flags
for ( ; ; )
{
switch ( f [ 0 ] )
{
2016-12-05 14:48:37 +03:00
// if we have left justify
case ' - ' : fl | = STBSP__LEFTJUST ; + + f ; continue ;
2016-12-05 13:57:06 +03:00
// if we have leading plus
2016-12-05 14:48:37 +03:00
case ' + ' : fl | = STBSP__LEADINGPLUS ; + + f ; continue ;
2016-12-05 13:57:06 +03:00
// if we have leading space
2016-12-05 14:48:37 +03:00
case ' ' : fl | = STBSP__LEADINGSPACE ; + + f ; continue ;
2016-12-05 13:57:06 +03:00
// if we have leading 0x
2016-12-05 14:48:37 +03:00
case ' # ' : fl | = STBSP__LEADING_0X ; + + f ; continue ;
2016-12-05 13:57:06 +03:00
// if we have thousand commas
2016-12-05 14:48:37 +03:00
case ' \' ' : fl | = STBSP__TRIPLET_COMMA ; + + f ; continue ;
2016-12-05 13:57:06 +03:00
// if we have kilo marker
2016-12-05 14:48:37 +03:00
case ' $ ' : fl | = STBSP__METRIC_SUFFIX ; + + f ; continue ;
2016-12-05 13:57:06 +03:00
// if we have leading zero
2016-12-05 14:48:37 +03:00
case ' 0 ' : fl | = STBSP__LEADINGZERO ; + + f ; goto flags_done ;
2016-12-05 13:57:06 +03:00
default : goto flags_done ;
}
}
flags_done :
// get the field width
2016-12-05 14:48:37 +03:00
if ( f [ 0 ] = = ' * ' ) { fw = va_arg ( va , stbsp__uint32 ) ; + + f ; } else { while ( ( f [ 0 ] > = ' 0 ' ) & & ( f [ 0 ] < = ' 9 ' ) ) { fw = fw * 10 + f [ 0 ] - ' 0 ' ; f + + ; } }
2016-12-05 13:57:06 +03:00
// get the precision
2016-12-05 14:48:37 +03:00
if ( f [ 0 ] = = ' . ' ) { + + f ; if ( f [ 0 ] = = ' * ' ) { pr = va_arg ( va , stbsp__uint32 ) ; + + f ; } else { pr = 0 ; while ( ( f [ 0 ] > = ' 0 ' ) & & ( f [ 0 ] < = ' 9 ' ) ) { pr = pr * 10 + f [ 0 ] - ' 0 ' ; f + + ; } } }
2016-12-05 13:57:06 +03:00
// handle integer size overrides
switch ( f [ 0 ] )
{
// are we halfwidth?
2016-12-05 14:48:37 +03:00
case ' h ' : fl | = STBSP__HALFWIDTH ; + + f ; break ;
2016-12-05 13:57:06 +03:00
// are we 64-bit (unix style)
2016-12-05 14:48:37 +03:00
case ' l ' : + + f ; if ( f [ 0 ] = = ' l ' ) { fl | = STBSP__INTMAX ; + + f ; } break ;
2016-12-05 13:57:06 +03:00
// are we 64-bit on intmax? (c99)
2016-12-05 14:48:37 +03:00
case ' j ' : fl | = STBSP__INTMAX ; + + f ; break ;
2016-12-05 13:57:06 +03:00
// are we 64-bit on size_t or ptrdiff_t? (c99)
2016-12-05 14:48:37 +03:00
case ' z ' : case ' t ' : fl | = ( ( sizeof ( char * ) = = 8 ) ? STBSP__INTMAX : 0 ) ; + + f ; break ;
2016-12-05 13:57:06 +03:00
// are we 64-bit (msft style)
2016-12-05 14:48:37 +03:00
case ' I ' : if ( ( f [ 1 ] = = ' 6 ' ) & & ( f [ 2 ] = = ' 4 ' ) ) { fl | = STBSP__INTMAX ; f + = 3 ; }
else if ( ( f [ 1 ] = = ' 3 ' ) & & ( f [ 2 ] = = ' 2 ' ) ) { f + = 3 ; }
else { fl | = ( ( sizeof ( void * ) = = 8 ) ? STBSP__INTMAX : 0 ) ; + + f ; } break ;
2016-12-05 13:57:06 +03:00
default : break ;
}
// handle each replacement
switch ( f [ 0 ] )
{
2016-12-05 14:48:37 +03:00
# define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307
char num [ STBSP__NUMSZ ] ;
2016-12-05 13:57:06 +03:00
char lead [ 8 ] ;
char tail [ 8 ] ;
char * s ;
char const * h ;
2016-12-05 14:48:37 +03:00
stbsp__uint32 l , n , cs ;
stbsp__uint64 n64 ;
# ifndef STB_SPRINTF_NOFLOAT
2016-12-05 13:57:06 +03:00
double fv ;
# endif
2016-12-05 14:48:37 +03:00
stbsp__int32 dp ; char const * sn ;
2016-12-05 13:57:06 +03:00
case ' s ' :
// get the string
s = va_arg ( va , char * ) ; if ( s = = 0 ) s = ( char * ) " null " ;
// get the length
sn = s ;
for ( ; ; )
{
2016-12-05 14:48:37 +03:00
if ( ( ( ( stbsp__uintptr ) sn ) & 3 ) = = 0 ) break ;
2016-12-05 13:57:06 +03:00
lchk :
if ( sn [ 0 ] = = 0 ) goto ld ;
+ + sn ;
}
n = 0xffffffff ;
2016-12-05 14:48:37 +03:00
if ( pr > = 0 ) { n = ( stbsp__uint32 ) ( sn - s ) ; if ( n > = ( stbsp__uint32 ) pr ) goto ld ; n = ( ( stbsp__uint32 ) ( pr - n ) ) > > 2 ; }
2016-12-05 13:57:06 +03:00
while ( n )
{
2016-12-05 14:48:37 +03:00
stbsp__uint32 v = * ( stbsp__uint32 * ) sn ;
2016-12-05 13:57:06 +03:00
if ( ( v - 0x01010101 ) & ( ~ v ) & 0x80808080UL ) goto lchk ;
sn + = 4 ;
- - n ;
}
goto lchk ;
ld :
2016-12-05 14:48:37 +03:00
l = ( stbsp__uint32 ) ( sn - s ) ;
2016-12-05 13:57:06 +03:00
// clamp to precision
2016-12-05 14:48:37 +03:00
if ( l > ( stbsp__uint32 ) pr ) l = pr ;
2016-12-05 13:57:06 +03:00
lead [ 0 ] = 0 ; tail [ 0 ] = 0 ; pr = 0 ; dp = 0 ; cs = 0 ;
// copy the string in
goto scopy ;
case ' c ' : // char
// get the character
2016-12-05 14:48:37 +03:00
s = num + STBSP__NUMSZ - 1 ; * s = ( char ) va_arg ( va , int ) ;
2016-12-05 13:57:06 +03:00
l = 1 ;
lead [ 0 ] = 0 ; tail [ 0 ] = 0 ; pr = 0 ; dp = 0 ; cs = 0 ;
goto scopy ;
case ' n ' : // weird write-bytes specifier
{ int * d = va_arg ( va , int * ) ;
* d = tlen + ( int ) ( bf - buf ) ; }
break ;
2016-12-05 14:48:37 +03:00
# ifdef STB_SPRINTF_NOFLOAT
2016-12-05 13:57:06 +03:00
case ' A ' : // float
case ' a ' : // hex float
case ' G ' : // float
case ' g ' : // float
case ' E ' : // float
case ' e ' : // float
case ' f ' : // float
va_arg ( va , double ) ; // eat it
s = ( char * ) " No float " ;
l = 8 ;
lead [ 0 ] = 0 ; tail [ 0 ] = 0 ; pr = 0 ; dp = 0 ; cs = 0 ;
goto scopy ;
# else
case ' A ' : // float
h = hexu ;
goto hexfloat ;
case ' a ' : // hex float
h = hex ;
hexfloat :
fv = va_arg ( va , double ) ;
if ( pr = = - 1 ) pr = 6 ; // default is 6
// read the double into a string
2016-12-05 14:48:37 +03:00
if ( stbsp__real_to_parts ( ( stbsp__int64 * ) & n64 , & dp , fv ) )
fl | = STBSP__NEGATIVE ;
2016-12-05 13:57:06 +03:00
s = num + 64 ;
// sign
2016-12-05 14:48:37 +03:00
lead [ 0 ] = 0 ; if ( fl & STBSP__NEGATIVE ) { lead [ 0 ] = 1 ; lead [ 1 ] = ' - ' ; } else if ( fl & STBSP__LEADINGSPACE ) { lead [ 0 ] = 1 ; lead [ 1 ] = ' ' ; } else if ( fl & STBSP__LEADINGPLUS ) { lead [ 0 ] = 1 ; lead [ 1 ] = ' + ' ; } ;
2016-12-05 13:57:06 +03:00
2016-12-05 14:48:37 +03:00
if ( dp = = - 1023 ) dp = ( n64 ) ? - 1022 : 0 ; else n64 | = ( ( ( stbsp__uint64 ) 1 ) < < 52 ) ;
2016-12-05 13:57:06 +03:00
n64 < < = ( 64 - 56 ) ;
2016-12-05 14:48:37 +03:00
if ( pr < 15 ) n64 + = ( ( ( ( stbsp__uint64 ) 8 ) < < 56 ) > > ( pr * 4 ) ) ;
2016-12-05 13:57:06 +03:00
// add leading chars
2016-12-05 14:48:37 +03:00
# ifdef STB_SPRINTF_MSVC_MODE
2016-12-05 13:57:06 +03:00
* s + + = ' 0 ' ; * s + + = ' x ' ;
# else
lead [ 1 + lead [ 0 ] ] = ' 0 ' ; lead [ 2 + lead [ 0 ] ] = ' x ' ; lead [ 0 ] + = 2 ;
# endif
* s + + = h [ ( n64 > > 60 ) & 15 ] ; n64 < < = 4 ;
2016-12-05 14:48:37 +03:00
if ( pr ) * s + + = stbsp__period ;
2016-12-05 13:57:06 +03:00
sn = s ;
// print the bits
2016-12-05 14:48:37 +03:00
n = pr ; if ( n > 13 ) n = 13 ; if ( pr > ( stbsp__int32 ) n ) tz = pr - n ; pr = 0 ;
2016-12-05 13:57:06 +03:00
while ( n - - ) { * s + + = h [ ( n64 > > 60 ) & 15 ] ; n64 < < = 4 ; }
// print the expo
tail [ 1 ] = h [ 17 ] ;
if ( dp < 0 ) { tail [ 2 ] = ' - ' ; dp = - dp ; } else tail [ 2 ] = ' + ' ;
n = ( dp > = 1000 ) ? 6 : ( ( dp > = 100 ) ? 5 : ( ( dp > = 10 ) ? 4 : 3 ) ) ;
tail [ 0 ] = ( char ) n ;
for ( ; ; ) { tail [ n ] = ' 0 ' + dp % 10 ; if ( n < = 3 ) break ; - - n ; dp / = 10 ; }
dp = ( int ) ( s - sn ) ;
l = ( int ) ( s - ( num + 64 ) ) ;
s = num + 64 ;
cs = 1 + ( 3 < < 24 ) ;
goto scopy ;
case ' G ' : // float
h = hexu ;
goto dosmallfloat ;
case ' g ' : // float
h = hex ;
dosmallfloat :
fv = va_arg ( va , double ) ;
if ( pr = = - 1 ) pr = 6 ; else if ( pr = = 0 ) pr = 1 ; // default is 6
// read the double into a string
2016-12-05 14:48:37 +03:00
if ( stbsp__real_to_str ( & sn , & l , num , & dp , fv , ( pr - 1 ) | 0x80000000 ) )
fl | = STBSP__NEGATIVE ;
2016-12-05 13:57:06 +03:00
// clamp the precision and delete extra zeros after clamp
n = pr ;
2016-12-05 14:48:37 +03:00
if ( l > ( stbsp__uint32 ) pr ) l = pr ; while ( ( l > 1 ) & & ( pr ) & & ( sn [ l - 1 ] = = ' 0 ' ) ) { - - pr ; - - l ; }
2016-12-05 13:57:06 +03:00
// should we use %e
2016-12-05 14:48:37 +03:00
if ( ( dp < = - 4 ) | | ( dp > ( stbsp__int32 ) n ) )
2016-12-05 13:57:06 +03:00
{
2016-12-05 14:48:37 +03:00
if ( pr > ( stbsp__int32 ) l ) pr = l - 1 ; else if ( pr ) - - pr ; // when using %e, there is one digit before the decimal
2016-12-05 13:57:06 +03:00
goto doexpfromg ;
}
// this is the insane action to get the pr to match %g sematics for %f
2016-12-05 14:48:37 +03:00
if ( dp > 0 ) { pr = ( dp < ( stbsp__int32 ) l ) ? l - dp : 0 ; } else { pr = - dp + ( ( pr > ( stbsp__int32 ) l ) ? l : pr ) ; }
2016-12-05 13:57:06 +03:00
goto dofloatfromg ;
case ' E ' : // float
h = hexu ;
goto doexp ;
case ' e ' : // float
h = hex ;
doexp :
fv = va_arg ( va , double ) ;
if ( pr = = - 1 ) pr = 6 ; // default is 6
// read the double into a string
2016-12-05 14:48:37 +03:00
if ( stbsp__real_to_str ( & sn , & l , num , & dp , fv , pr | 0x80000000 ) )
fl | = STBSP__NEGATIVE ;
2016-12-05 13:57:06 +03:00
doexpfromg :
tail [ 0 ] = 0 ;
2016-12-05 14:48:37 +03:00
lead [ 0 ] = 0 ; if ( fl & STBSP__NEGATIVE ) { lead [ 0 ] = 1 ; lead [ 1 ] = ' - ' ; } else if ( fl & STBSP__LEADINGSPACE ) { lead [ 0 ] = 1 ; lead [ 1 ] = ' ' ; } else if ( fl & STBSP__LEADINGPLUS ) { lead [ 0 ] = 1 ; lead [ 1 ] = ' + ' ; } ;
if ( dp = = STBSP__SPECIAL ) { s = ( char * ) sn ; cs = 0 ; pr = 0 ; goto scopy ; }
2016-12-05 13:57:06 +03:00
s = num + 64 ;
// handle leading chars
* s + + = sn [ 0 ] ;
2016-12-05 14:48:37 +03:00
if ( pr ) * s + + = stbsp__period ;
2016-12-05 13:57:06 +03:00
// handle after decimal
2016-12-05 14:48:37 +03:00
if ( ( l - 1 ) > ( stbsp__uint32 ) pr ) l = pr + 1 ;
2016-12-05 13:57:06 +03:00
for ( n = 1 ; n < l ; n + + ) * s + + = sn [ n ] ;
// trailing zeros
tz = pr - ( l - 1 ) ; pr = 0 ;
// dump expo
tail [ 1 ] = h [ 0xe ] ;
dp - = 1 ;
if ( dp < 0 ) { tail [ 2 ] = ' - ' ; dp = - dp ; } else tail [ 2 ] = ' + ' ;
2016-12-05 14:48:37 +03:00
# ifdef STB_SPRINTF_MSVC_MODE
2016-12-05 13:57:06 +03:00
n = 5 ;
# else
n = ( dp > = 100 ) ? 5 : 4 ;
# endif
tail [ 0 ] = ( char ) n ;
for ( ; ; ) { tail [ n ] = ' 0 ' + dp % 10 ; if ( n < = 3 ) break ; - - n ; dp / = 10 ; }
cs = 1 + ( 3 < < 24 ) ; // how many tens
goto flt_lead ;
case ' f ' : // float
fv = va_arg ( va , double ) ;
doafloat :
// do kilos
2016-12-05 14:48:37 +03:00
if ( fl & STBSP__METRIC_SUFFIX ) { while ( fl < 0x4000000 ) { if ( ( fv < 1024.0 ) & & ( fv > - 1024.0 ) ) break ; fv / = 1024.0 ; fl + = 0x1000000 ; } }
2016-12-05 13:57:06 +03:00
if ( pr = = - 1 ) pr = 6 ; // default is 6
// read the double into a string
2016-12-05 14:48:37 +03:00
if ( stbsp__real_to_str ( & sn , & l , num , & dp , fv , pr ) )
fl | = STBSP__NEGATIVE ;
2016-12-05 13:57:06 +03:00
dofloatfromg :
tail [ 0 ] = 0 ;
// sign
2016-12-05 14:48:37 +03:00
lead [ 0 ] = 0 ; if ( fl & STBSP__NEGATIVE ) { lead [ 0 ] = 1 ; lead [ 1 ] = ' - ' ; } else if ( fl & STBSP__LEADINGSPACE ) { lead [ 0 ] = 1 ; lead [ 1 ] = ' ' ; } else if ( fl & STBSP__LEADINGPLUS ) { lead [ 0 ] = 1 ; lead [ 1 ] = ' + ' ; } ;
if ( dp = = STBSP__SPECIAL ) { s = ( char * ) sn ; cs = 0 ; pr = 0 ; goto scopy ; }
2016-12-05 13:57:06 +03:00
s = num + 64 ;
// handle the three decimal varieties
if ( dp < = 0 )
{
2016-12-05 14:48:37 +03:00
stbsp__int32 i ;
2016-12-05 13:57:06 +03:00
// handle 0.000*000xxxx
2016-12-05 14:48:37 +03:00
* s + + = ' 0 ' ; if ( pr ) * s + + = stbsp__period ;
n = - dp ; if ( ( stbsp__int32 ) n > pr ) n = pr ; i = n ; while ( i ) { if ( ( ( ( stbsp__uintptr ) s ) & 3 ) = = 0 ) break ; * s + + = ' 0 ' ; - - i ; } while ( i > = 4 ) { * ( stbsp__uint32 * ) s = 0x30303030 ; s + = 4 ; i - = 4 ; } while ( i ) { * s + + = ' 0 ' ; - - i ; }
if ( ( stbsp__int32 ) ( l + n ) > pr ) l = pr - n ; i = l ; while ( i ) { * s + + = * sn + + ; - - i ; }
2016-12-05 13:57:06 +03:00
tz = pr - ( n + l ) ;
cs = 1 + ( 3 < < 24 ) ; // how many tens did we write (for commas below)
}
else
{
2016-12-05 14:48:37 +03:00
cs = ( fl & STBSP__TRIPLET_COMMA ) ? ( ( 600 - ( stbsp__uint32 ) dp ) % 3 ) : 0 ;
if ( ( stbsp__uint32 ) dp > = l )
2016-12-05 13:57:06 +03:00
{
// handle xxxx000*000.0
2016-12-05 14:48:37 +03:00
n = 0 ; for ( ; ; ) { if ( ( fl & STBSP__TRIPLET_COMMA ) & & ( + + cs = = 4 ) ) { cs = 0 ; * s + + = stbsp__comma ; } else { * s + + = sn [ n ] ; + + n ; if ( n > = l ) break ; } }
if ( n < ( stbsp__uint32 ) dp )
2016-12-05 13:57:06 +03:00
{
n = dp - n ;
2016-12-05 14:48:37 +03:00
if ( ( fl & STBSP__TRIPLET_COMMA ) = = 0 ) { while ( n ) { if ( ( ( ( stbsp__uintptr ) s ) & 3 ) = = 0 ) break ; * s + + = ' 0 ' ; - - n ; } while ( n > = 4 ) { * ( stbsp__uint32 * ) s = 0x30303030 ; s + = 4 ; n - = 4 ; } }
while ( n ) { if ( ( fl & STBSP__TRIPLET_COMMA ) & & ( + + cs = = 4 ) ) { cs = 0 ; * s + + = stbsp__comma ; } else { * s + + = ' 0 ' ; - - n ; } }
2016-12-05 13:57:06 +03:00
}
cs = ( int ) ( s - ( num + 64 ) ) + ( 3 < < 24 ) ; // cs is how many tens
2016-12-05 14:48:37 +03:00
if ( pr ) { * s + + = stbsp__period ; tz = pr ; }
2016-12-05 13:57:06 +03:00
}
else
{
// handle xxxxx.xxxx000*000
2016-12-05 14:48:37 +03:00
n = 0 ; for ( ; ; ) { if ( ( fl & STBSP__TRIPLET_COMMA ) & & ( + + cs = = 4 ) ) { cs = 0 ; * s + + = stbsp__comma ; } else { * s + + = sn [ n ] ; + + n ; if ( n > = ( stbsp__uint32 ) dp ) break ; } }
2016-12-05 13:57:06 +03:00
cs = ( int ) ( s - ( num + 64 ) ) + ( 3 < < 24 ) ; // cs is how many tens
2016-12-05 14:48:37 +03:00
if ( pr ) * s + + = stbsp__period ;
if ( ( l - dp ) > ( stbsp__uint32 ) pr ) l = pr + dp ;
2016-12-05 13:57:06 +03:00
while ( n < l ) { * s + + = sn [ n ] ; + + n ; }
tz = pr - ( l - dp ) ;
}
}
pr = 0 ;
// handle k,m,g,t
2016-12-05 14:48:37 +03:00
if ( fl & STBSP__METRIC_SUFFIX ) { tail [ 0 ] = 1 ; tail [ 1 ] = ' ' ; { if ( fl > > 24 ) { tail [ 2 ] = " _kmgt " [ fl > > 24 ] ; tail [ 0 ] = 2 ; } } } ;
2016-12-05 13:57:06 +03:00
flt_lead :
// get the length that we copied
2016-12-05 14:48:37 +03:00
l = ( stbsp__uint32 ) ( s - ( num + 64 ) ) ;
2016-12-05 13:57:06 +03:00
s = num + 64 ;
goto scopy ;
# endif
case ' B ' : // upper binary
h = hexu ;
goto binary ;
case ' b ' : // lower binary
h = hex ;
binary :
lead [ 0 ] = 0 ;
2016-12-05 14:48:37 +03:00
if ( fl & STBSP__LEADING_0X ) { lead [ 0 ] = 2 ; lead [ 1 ] = ' 0 ' ; lead [ 2 ] = h [ 0xb ] ; }
2016-12-05 13:57:06 +03:00
l = ( 8 < < 4 ) | ( 1 < < 8 ) ;
goto radixnum ;
case ' o ' : // octal
h = hexu ;
lead [ 0 ] = 0 ;
2016-12-05 14:48:37 +03:00
if ( fl & STBSP__LEADING_0X ) { lead [ 0 ] = 1 ; lead [ 1 ] = ' 0 ' ; }
2016-12-05 13:57:06 +03:00
l = ( 3 < < 4 ) | ( 3 < < 8 ) ;
goto radixnum ;
case ' p ' : // pointer
2016-12-05 14:48:37 +03:00
fl | = ( sizeof ( void * ) = = 8 ) ? STBSP__INTMAX : 0 ;
2016-12-05 13:57:06 +03:00
pr = sizeof ( void * ) * 2 ;
2016-12-05 14:48:37 +03:00
fl & = ~ STBSP__LEADINGZERO ; // 'p' only prints the pointer with zeros
2016-12-05 13:57:06 +03:00
// drop through to X
case ' X ' : // upper binary
h = hexu ;
goto dohexb ;
case ' x ' : // lower binary
h = hex ; dohexb :
l = ( 4 < < 4 ) | ( 4 < < 8 ) ;
lead [ 0 ] = 0 ;
2016-12-05 14:48:37 +03:00
if ( fl & STBSP__LEADING_0X ) { lead [ 0 ] = 2 ; lead [ 1 ] = ' 0 ' ; lead [ 2 ] = h [ 16 ] ; }
2016-12-05 13:57:06 +03:00
radixnum :
// get the number
2016-12-05 14:48:37 +03:00
if ( fl & STBSP__INTMAX )
n64 = va_arg ( va , stbsp__uint64 ) ;
2016-12-05 13:57:06 +03:00
else
2016-12-05 14:48:37 +03:00
n64 = va_arg ( va , stbsp__uint32 ) ;
2016-12-05 13:57:06 +03:00
2016-12-05 14:48:37 +03:00
s = num + STBSP__NUMSZ ; dp = 0 ;
2016-12-05 13:57:06 +03:00
// clear tail, and clear leading if value is zero
tail [ 0 ] = 0 ; if ( n64 = = 0 ) { lead [ 0 ] = 0 ; if ( pr = = 0 ) { l = 0 ; cs = ( ( ( l > > 4 ) & 15 ) ) < < 24 ; goto scopy ; } }
// convert to string
2016-12-05 14:48:37 +03:00
for ( ; ; ) { * - - s = h [ n64 & ( ( 1 < < ( l > > 8 ) ) - 1 ) ] ; n64 > > = ( l > > 8 ) ; if ( ! ( ( n64 ) | | ( ( stbsp__int32 ) ( ( num + STBSP__NUMSZ ) - s ) < pr ) ) ) break ; if ( fl & STBSP__TRIPLET_COMMA ) { + + l ; if ( ( l & 15 ) = = ( ( l > > 4 ) & 15 ) ) { l & = ~ 15 ; * - - s = stbsp__comma ; } } } ;
2016-12-05 13:57:06 +03:00
// get the tens and the comma pos
2016-12-05 14:48:37 +03:00
cs = ( stbsp__uint32 ) ( ( num + STBSP__NUMSZ ) - s ) + ( ( ( ( l > > 4 ) & 15 ) ) < < 24 ) ;
2016-12-05 13:57:06 +03:00
// get the length that we copied
2016-12-05 14:48:37 +03:00
l = ( stbsp__uint32 ) ( ( num + STBSP__NUMSZ ) - s ) ;
2016-12-05 13:57:06 +03:00
// copy it
goto scopy ;
case ' u ' : // unsigned
case ' i ' :
case ' d ' : // integer
// get the integer and abs it
2016-12-05 14:48:37 +03:00
if ( fl & STBSP__INTMAX )
2016-12-05 13:57:06 +03:00
{
2016-12-05 14:48:37 +03:00
stbsp__int64 i64 = va_arg ( va , stbsp__int64 ) ; n64 = ( stbsp__uint64 ) i64 ; if ( ( f [ 0 ] ! = ' u ' ) & & ( i64 < 0 ) ) { n64 = ( stbsp__uint64 ) - i64 ; fl | = STBSP__NEGATIVE ; }
2016-12-05 13:57:06 +03:00
}
else
{
2016-12-05 14:48:37 +03:00
stbsp__int32 i = va_arg ( va , stbsp__int32 ) ; n64 = ( stbsp__uint32 ) i ; if ( ( f [ 0 ] ! = ' u ' ) & & ( i < 0 ) ) { n64 = ( stbsp__uint32 ) - i ; fl | = STBSP__NEGATIVE ; }
2016-12-05 13:57:06 +03:00
}
2016-12-05 14:48:37 +03:00
# ifndef STB_SPRINTF_NOFLOAT
if ( fl & STBSP__METRIC_SUFFIX ) { if ( n64 < 1024 ) pr = 0 ; else if ( pr = = - 1 ) pr = 1 ; fv = ( double ) ( stbsp__int64 ) n64 ; goto doafloat ; }
2016-12-05 13:57:06 +03:00
# endif
// convert to string
2016-12-05 14:48:37 +03:00
s = num + STBSP__NUMSZ ; l = 0 ;
2016-12-05 13:57:06 +03:00
for ( ; ; )
{
// do in 32-bit chunks (avoid lots of 64-bit divides even with constant denominators)
char * o = s - 8 ;
2016-12-05 14:48:37 +03:00
if ( n64 > = 100000000 ) { n = ( stbsp__uint32 ) ( n64 % 100000000 ) ; n64 / = 100000000 ; } else { n = ( stbsp__uint32 ) n64 ; n64 = 0 ; }
if ( ( fl & STBSP__TRIPLET_COMMA ) = = 0 ) { while ( n ) { s - = 2 ; * ( stbsp__uint16 * ) s = * ( stbsp__uint16 * ) & stbsp__digitpair [ ( n % 100 ) * 2 ] ; n / = 100 ; } }
while ( n ) { if ( ( fl & STBSP__TRIPLET_COMMA ) & & ( l + + = = 3 ) ) { l = 0 ; * - - s = stbsp__comma ; - - o ; } else { * - - s = ( char ) ( n % 10 ) + ' 0 ' ; n / = 10 ; } }
if ( n64 = = 0 ) { if ( ( s [ 0 ] = = ' 0 ' ) & & ( s ! = ( num + STBSP__NUMSZ ) ) ) + + s ; break ; }
while ( s ! = o ) if ( ( fl & STBSP__TRIPLET_COMMA ) & & ( l + + = = 3 ) ) { l = 0 ; * - - s = stbsp__comma ; - - o ; } else { * - - s = ' 0 ' ; }
2016-12-05 13:57:06 +03:00
}
tail [ 0 ] = 0 ;
// sign
2016-12-05 14:48:37 +03:00
lead [ 0 ] = 0 ; if ( fl & STBSP__NEGATIVE ) { lead [ 0 ] = 1 ; lead [ 1 ] = ' - ' ; } else if ( fl & STBSP__LEADINGSPACE ) { lead [ 0 ] = 1 ; lead [ 1 ] = ' ' ; } else if ( fl & STBSP__LEADINGPLUS ) { lead [ 0 ] = 1 ; lead [ 1 ] = ' + ' ; } ;
2016-12-05 13:57:06 +03:00
// get the length that we copied
2016-12-05 14:48:37 +03:00
l = ( stbsp__uint32 ) ( ( num + STBSP__NUMSZ ) - s ) ; if ( l = = 0 ) { * - - s = ' 0 ' ; l = 1 ; }
2016-12-05 13:57:06 +03:00
cs = l + ( 3 < < 24 ) ;
if ( pr < 0 ) pr = 0 ;
scopy :
// get fw=leading/trailing space, pr=leading zeros
2016-12-05 14:48:37 +03:00
if ( pr < ( stbsp__int32 ) l ) pr = l ;
2016-12-05 13:57:06 +03:00
n = pr + lead [ 0 ] + tail [ 0 ] + tz ;
2016-12-05 14:48:37 +03:00
if ( fw < ( stbsp__int32 ) n ) fw = n ;
2016-12-05 13:57:06 +03:00
fw - = n ;
pr - = l ;
// handle right justify and leading zeros
2016-12-05 14:48:37 +03:00
if ( ( fl & STBSP__LEFTJUST ) = = 0 )
2016-12-05 13:57:06 +03:00
{
2016-12-05 14:48:37 +03:00
if ( fl & STBSP__LEADINGZERO ) // if leading zeros, everything is in pr
2016-12-05 13:57:06 +03:00
{
pr = ( fw > pr ) ? fw : pr ;
fw = 0 ;
}
else
{
2016-12-05 14:48:37 +03:00
fl & = ~ STBSP__TRIPLET_COMMA ; // if no leading zeros, then no commas
2016-12-05 13:57:06 +03:00
}
}
// copy the spaces and/or zeros
if ( fw + pr )
{
2016-12-05 14:48:37 +03:00
stbsp__int32 i ; stbsp__uint32 c ;
2016-12-05 13:57:06 +03:00
// copy leading spaces (or when doing %8.4d stuff)
2016-12-05 14:48:37 +03:00
if ( ( fl & STBSP__LEFTJUST ) = = 0 ) while ( fw > 0 ) { stbsp__cb_buf_clamp ( i , fw ) ; fw - = i ; while ( i ) { if ( ( ( ( stbsp__uintptr ) bf ) & 3 ) = = 0 ) break ; * bf + + = ' ' ; - - i ; } while ( i > = 4 ) { * ( stbsp__uint32 * ) bf = 0x20202020 ; bf + = 4 ; i - = 4 ; } while ( i ) { * bf + + = ' ' ; - - i ; } stbsp__chk_cb_buf ( 1 ) ; }
2016-12-05 13:57:06 +03:00
// copy leader
2016-12-05 14:48:37 +03:00
sn = lead + 1 ; while ( lead [ 0 ] ) { stbsp__cb_buf_clamp ( i , lead [ 0 ] ) ; lead [ 0 ] - = ( char ) i ; while ( i ) { * bf + + = * sn + + ; - - i ; } stbsp__chk_cb_buf ( 1 ) ; }
2016-12-05 13:57:06 +03:00
// copy leading zeros
c = cs > > 24 ; cs & = 0xffffff ;
2016-12-05 14:48:37 +03:00
cs = ( fl & STBSP__TRIPLET_COMMA ) ? ( ( stbsp__uint32 ) ( c - ( ( pr + cs ) % ( c + 1 ) ) ) ) : 0 ;
while ( pr > 0 ) { stbsp__cb_buf_clamp ( i , pr ) ; pr - = i ; if ( ( fl & STBSP__TRIPLET_COMMA ) = = 0 ) { while ( i ) { if ( ( ( ( stbsp__uintptr ) bf ) & 3 ) = = 0 ) break ; * bf + + = ' 0 ' ; - - i ; } while ( i > = 4 ) { * ( stbsp__uint32 * ) bf = 0x30303030 ; bf + = 4 ; i - = 4 ; } } while ( i ) { if ( ( fl & STBSP__TRIPLET_COMMA ) & & ( cs + + = = c ) ) { cs = 0 ; * bf + + = stbsp__comma ; } else * bf + + = ' 0 ' ; - - i ; } stbsp__chk_cb_buf ( 1 ) ; }
2016-12-05 13:57:06 +03:00
}
// copy leader if there is still one
2016-12-05 14:48:37 +03:00
sn = lead + 1 ; while ( lead [ 0 ] ) { stbsp__int32 i ; stbsp__cb_buf_clamp ( i , lead [ 0 ] ) ; lead [ 0 ] - = ( char ) i ; while ( i ) { * bf + + = * sn + + ; - - i ; } stbsp__chk_cb_buf ( 1 ) ; }
2016-12-05 13:57:06 +03:00
// copy the string
2016-12-05 14:48:37 +03:00
n = l ; while ( n ) { stbsp__int32 i ; stbsp__cb_buf_clamp ( i , n ) ; n - = i ; STBSP__UNALIGNED ( while ( i > = 4 ) { * ( stbsp__uint32 * ) bf = * ( stbsp__uint32 * ) s ; bf + = 4 ; s + = 4 ; i - = 4 ; } ) while ( i ) { * bf + + = * s + + ; - - i ; } stbsp__chk_cb_buf ( 1 ) ; }
2016-12-05 13:57:06 +03:00
// copy trailing zeros
2016-12-05 14:48:37 +03:00
while ( tz ) { stbsp__int32 i ; stbsp__cb_buf_clamp ( i , tz ) ; tz - = i ; while ( i ) { if ( ( ( ( stbsp__uintptr ) bf ) & 3 ) = = 0 ) break ; * bf + + = ' 0 ' ; - - i ; } while ( i > = 4 ) { * ( stbsp__uint32 * ) bf = 0x30303030 ; bf + = 4 ; i - = 4 ; } while ( i ) { * bf + + = ' 0 ' ; - - i ; } stbsp__chk_cb_buf ( 1 ) ; }
2016-12-05 13:57:06 +03:00
// copy tail if there is one
2016-12-05 14:48:37 +03:00
sn = tail + 1 ; while ( tail [ 0 ] ) { stbsp__int32 i ; stbsp__cb_buf_clamp ( i , tail [ 0 ] ) ; tail [ 0 ] - = ( char ) i ; while ( i ) { * bf + + = * sn + + ; - - i ; } stbsp__chk_cb_buf ( 1 ) ; }
2016-12-05 13:57:06 +03:00
// handle the left justify
2016-12-05 14:48:37 +03:00
if ( fl & STBSP__LEFTJUST ) if ( fw > 0 ) { while ( fw ) { stbsp__int32 i ; stbsp__cb_buf_clamp ( i , fw ) ; fw - = i ; while ( i ) { if ( ( ( ( stbsp__uintptr ) bf ) & 3 ) = = 0 ) break ; * bf + + = ' ' ; - - i ; } while ( i > = 4 ) { * ( stbsp__uint32 * ) bf = 0x20202020 ; bf + = 4 ; i - = 4 ; } while ( i - - ) * bf + + = ' ' ; stbsp__chk_cb_buf ( 1 ) ; } }
2016-12-05 13:57:06 +03:00
break ;
default : // unknown, just copy code
2016-12-05 14:48:37 +03:00
s = num + STBSP__NUMSZ - 1 ; * s = f [ 0 ] ;
2016-12-05 13:57:06 +03:00
l = 1 ;
fw = pr = fl = 0 ;
lead [ 0 ] = 0 ; tail [ 0 ] = 0 ; pr = 0 ; dp = 0 ; cs = 0 ;
goto scopy ;
}
+ + f ;
}
endfmt :
if ( ! callback )
* bf = 0 ;
else
2016-12-05 14:48:37 +03:00
stbsp__flush_cb ( ) ;
2016-12-05 13:57:06 +03:00
done :
return tlen + ( int ) ( bf - buf ) ;
}
// cleanup
2016-12-05 14:48:37 +03:00
# undef STBSP__LEFTJUST
# undef STBSP__LEADINGPLUS
# undef STBSP__LEADINGSPACE
# undef STBSP__LEADING_0X
# undef STBSP__LEADINGZERO
# undef STBSP__INTMAX
# undef STBSP__TRIPLET_COMMA
# undef STBSP__NEGATIVE
# undef STBSP__METRIC_SUFFIX
# undef STBSP__NUMSZ
# undef stbsp__chk_cb_bufL
# undef stbsp__chk_cb_buf
# undef stbsp__flush_cb
# undef stbsp__cb_buf_clamp
2016-12-05 13:57:06 +03:00
// ============================================================================
// wrapper functions
2016-12-05 14:48:37 +03:00
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE ( sprintf ) ( char * buf , char const * fmt , . . . )
2016-12-05 13:57:06 +03:00
{
2017-01-16 11:11:58 +03:00
int result ;
2016-12-05 13:57:06 +03:00
va_list va ;
va_start ( va , fmt ) ;
2017-01-16 11:11:58 +03:00
result = STB_SPRINTF_DECORATE ( vsprintfcb ) ( 0 , 0 , buf , fmt , va ) ;
va_end ( va ) ;
return result ;
2016-12-05 13:57:06 +03:00
}
2016-12-05 14:48:37 +03:00
typedef struct stbsp__context
2016-12-05 13:57:06 +03:00
{
char * buf ;
int count ;
2016-12-05 14:48:37 +03:00
char tmp [ STB_SPRINTF_MIN ] ;
} stbsp__context ;
2016-12-05 13:57:06 +03:00
2016-12-05 14:48:37 +03:00
static char * stbsp__clamp_callback ( char * buf , void * user , int len )
2016-12-05 13:57:06 +03:00
{
2016-12-05 14:48:37 +03:00
stbsp__context * c = ( stbsp__context * ) user ;
2016-12-05 13:57:06 +03:00
if ( len > c - > count ) len = c - > count ;
if ( len )
{
if ( buf ! = c - > buf )
{
char * s , * d , * se ;
d = c - > buf ; s = buf ; se = buf + len ;
do { * d + + = * s + + ; } while ( s < se ) ;
}
c - > buf + = len ;
c - > count - = len ;
}
if ( c - > count < = 0 ) return 0 ;
2016-12-05 14:48:37 +03:00
return ( c - > count > = STB_SPRINTF_MIN ) ? c - > buf : c - > tmp ; // go direct into buffer if you can
2016-12-05 13:57:06 +03:00
}
2016-12-05 14:48:37 +03:00
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE ( vsnprintf ) ( char * buf , int count , char const * fmt , va_list va )
2016-12-05 13:57:06 +03:00
{
2016-12-05 14:48:37 +03:00
stbsp__context c ;
2016-12-05 13:57:06 +03:00
int l ;
if ( count = = 0 )
return 0 ;
c . buf = buf ;
c . count = count ;
2016-12-05 14:48:37 +03:00
STB_SPRINTF_DECORATE ( vsprintfcb ) ( stbsp__clamp_callback , & c , stbsp__clamp_callback ( 0 , & c , 0 ) , fmt , va ) ;
2016-12-05 13:57:06 +03:00
// zero-terminate
l = ( int ) ( c . buf - buf ) ;
if ( l > = count ) // should never be greater, only equal (or less) than count
l = count - 1 ;
buf [ l ] = 0 ;
return l ;
}
2016-12-05 14:48:37 +03:00
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE ( snprintf ) ( char * buf , int count , char const * fmt , . . . )
2016-12-05 13:57:06 +03:00
{
2017-01-16 11:11:58 +03:00
int result ;
2016-12-05 13:57:06 +03:00
va_list va ;
va_start ( va , fmt ) ;
2017-01-16 11:11:58 +03:00
result = STB_SPRINTF_DECORATE ( vsnprintf ) ( buf , count , fmt , va ) ;
va_end ( va ) ;
return result ;
2016-12-05 13:57:06 +03:00
}
2016-12-05 14:48:37 +03:00
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE ( vsprintf ) ( char * buf , char const * fmt , va_list va )
2016-12-05 13:57:06 +03:00
{
2016-12-05 14:48:37 +03:00
return STB_SPRINTF_DECORATE ( vsprintfcb ) ( 0 , 0 , buf , fmt , va ) ;
2016-12-05 13:57:06 +03:00
}
// =======================================================================
// low level float utility functions
2016-12-05 14:48:37 +03:00
# ifndef STB_SPRINTF_NOFLOAT
2016-12-05 13:57:06 +03:00
2016-12-05 14:48:37 +03:00
// copies d to bits w/ strict aliasing (this compiles to nothing on /Ox)
# define STBSP__COPYFP(dest,src) { int cn; for(cn=0;cn<8;cn++) ((char*)&dest)[cn]=((char*)&src)[cn]; }
2016-12-05 13:57:06 +03:00
// get float info
2016-12-05 14:48:37 +03:00
static stbsp__int32 stbsp__real_to_parts ( stbsp__int64 * bits , stbsp__int32 * expo , double value )
2016-12-05 13:57:06 +03:00
{
double d ;
2016-12-05 14:48:37 +03:00
stbsp__int64 b = 0 ;
2016-12-05 13:57:06 +03:00
// load value and round at the frac_digits
d = value ;
2016-12-05 14:48:37 +03:00
STBSP__COPYFP ( b , d ) ;
2016-12-05 13:57:06 +03:00
2016-12-05 14:48:37 +03:00
* bits = b & ( ( ( ( stbsp__uint64 ) 1 ) < < 52 ) - 1 ) ;
* expo = ( stbsp__int32 ) ( ( ( b > > 52 ) & 2047 ) - 1023 ) ;
2016-12-05 13:57:06 +03:00
2016-12-05 14:48:37 +03:00
return ( stbsp__int32 ) ( b > > 63 ) ;
2016-12-05 13:57:06 +03:00
}
2016-12-05 14:48:37 +03:00
static double const stbsp__bot [ 23 ] = { 1e+000 , 1e+001 , 1e+002 , 1e+003 , 1e+004 , 1e+005 , 1e+006 , 1e+007 , 1e+008 , 1e+009 , 1e+010 , 1e+011 , 1e+012 , 1e+013 , 1e+014 , 1e+015 , 1e+016 , 1e+017 , 1e+018 , 1e+019 , 1e+020 , 1e+021 , 1e+022 } ;
static double const stbsp__negbot [ 22 ] = { 1e-001 , 1e-002 , 1e-003 , 1e-004 , 1e-005 , 1e-006 , 1e-007 , 1e-008 , 1e-009 , 1e-010 , 1e-011 , 1e-012 , 1e-013 , 1e-014 , 1e-015 , 1e-016 , 1e-017 , 1e-018 , 1e-019 , 1e-020 , 1e-021 , 1e-022 } ;
static double const stbsp__negboterr [ 22 ] = { - 5.551115123125783e-018 , - 2.0816681711721684e-019 , - 2.0816681711721686e-020 , - 4.7921736023859299e-021 , - 8.1803053914031305e-022 , 4.5251888174113741e-023 , 4.5251888174113739e-024 , - 2.0922560830128471e-025 , - 6.2281591457779853e-026 , - 3.6432197315497743e-027 , 6.0503030718060191e-028 , 2.0113352370744385e-029 , - 3.0373745563400371e-030 , 1.1806906454401013e-032 , - 7.7705399876661076e-032 , 2.0902213275965398e-033 , - 7.1542424054621921e-034 , - 7.1542424054621926e-035 , 2.4754073164739869e-036 , 5.4846728545790429e-037 , 9.2462547772103625e-038 , - 4.8596774326570872e-039 } ;
static double const stbsp__top [ 13 ] = { 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 } ;
static double const stbsp__negtop [ 13 ] = { 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 } ;
static double const stbsp__toperr [ 13 ] = { 8388608 , 6.8601809640529717e+028 , - 7.253143638152921e+052 , - 4.3377296974619174e+075 , - 1.5559416129466825e+098 , - 3.2841562489204913e+121 , - 3.7745893248228135e+144 , - 1.7356668416969134e+167 , - 3.8893577551088374e+190 , - 9.9566444326005119e+213 , 6.3641293062232429e+236 , - 5.2069140800249813e+259 , - 5.2504760255204387e+282 } ;
static double const stbsp__negtoperr [ 13 ] = { 3.9565301985100693e-040 , - 2.299904345391321e-063 , 3.6506201437945798e-086 , 1.1875228833981544e-109 , - 5.0644902316928607e-132 , - 6.7156837247865426e-155 , - 2.812077463003139e-178 , - 5.7778912386589953e-201 , 7.4997100559334532e-224 , - 4.6439668915134491e-247 , - 6.3691100762962136e-270 , - 9.436808465446358e-293 , 8.0970921678014997e-317 } ;
2016-12-05 13:57:06 +03:00
# if defined(_MSC_VER) && (_MSC_VER<=1200)
2016-12-05 14:48:37 +03:00
static stbsp__uint64 const stbsp__powten [ 20 ] = { 1 , 10 , 100 , 1000 , 10000 , 100000 , 1000000 , 10000000 , 100000000 , 1000000000 , 10000000000 , 100000000000 , 1000000000000 , 10000000000000 , 100000000000000 , 1000000000000000 , 10000000000000000 , 100000000000000000 , 1000000000000000000 , 10000000000000000000U } ;
# define stbsp__tento19th ((stbsp__uint64)1000000000000000000)
2016-12-05 13:57:06 +03:00
# else
2016-12-05 14:48:37 +03:00
static stbsp__uint64 const stbsp__powten [ 20 ] = { 1 , 10 , 100 , 1000 , 10000 , 100000 , 1000000 , 10000000 , 100000000 , 1000000000 , 10000000000ULL , 100000000000ULL , 1000000000000ULL , 10000000000000ULL , 100000000000000ULL , 1000000000000000ULL , 10000000000000000ULL , 100000000000000000ULL , 1000000000000000000ULL , 10000000000000000000ULL } ;
# define stbsp__tento19th (1000000000000000000ULL)
2016-12-05 13:57:06 +03:00
# endif
2016-12-05 14:48:37 +03:00
# define stbsp__ddmulthi(oh,ol,xh,yh) \
2016-12-05 13:57:06 +03:00
{ \
double ahi = 0 , alo , bhi = 0 , blo ; \
2016-12-05 14:48:37 +03:00
stbsp__int64 bt ; \
2016-12-05 13:57:06 +03:00
oh = xh * yh ; \
2016-12-05 14:48:37 +03:00
STBSP__COPYFP ( bt , xh ) ; bt & = ( ( ~ ( stbsp__uint64 ) 0 ) < < 27 ) ; STBSP__COPYFP ( ahi , bt ) ; alo = xh - ahi ; \
STBSP__COPYFP ( bt , yh ) ; bt & = ( ( ~ ( stbsp__uint64 ) 0 ) < < 27 ) ; STBSP__COPYFP ( bhi , bt ) ; blo = yh - bhi ; \
2016-12-05 13:57:06 +03:00
ol = ( ( ahi * bhi - oh ) + ahi * blo + alo * bhi ) + alo * blo ; \
}
2016-12-05 14:48:37 +03:00
# define stbsp__ddtoS64(ob,xh,xl) \
2016-12-05 13:57:06 +03:00
{ \
double ahi = 0 , alo , vh , t ; \
2016-12-05 14:48:37 +03:00
ob = ( stbsp__int64 ) ph ; \
2016-12-05 13:57:06 +03:00
vh = ( double ) ob ; \
ahi = ( xh - vh ) ; \
t = ( ahi - xh ) ; \
alo = ( xh - ( ahi - t ) ) - ( vh + t ) ; \
2016-12-05 14:48:37 +03:00
ob + = ( stbsp__int64 ) ( ahi + alo + xl ) ; \
2016-12-05 13:57:06 +03:00
}
2016-12-05 14:48:37 +03:00
# define stbsp__ddrenorm(oh,ol) { double s; s=oh+ol; ol=ol-(s-oh); oh=s; }
2016-12-05 13:57:06 +03:00
2016-12-05 14:48:37 +03:00
# define stbsp__ddmultlo(oh,ol,xh,xl,yh,yl) \
2016-12-05 13:57:06 +03:00
ol = ol + ( xh * yl + xl * yh ) ; \
2016-12-05 14:48:37 +03:00
# define stbsp__ddmultlos(oh,ol,xh,yl) \
2016-12-05 13:57:06 +03:00
ol = ol + ( xh * yl ) ; \
2016-12-05 14:48:37 +03:00
static void stbsp__raise_to_power10 ( double * ohi , double * olo , double d , stbsp__int32 power ) // power can be -323 to +350
2016-12-05 13:57:06 +03:00
{
double ph , pl ;
if ( ( power > = 0 ) & & ( power < = 22 ) )
{
2016-12-05 14:48:37 +03:00
stbsp__ddmulthi ( ph , pl , d , stbsp__bot [ power ] ) ;
2016-12-05 13:57:06 +03:00
}
else
{
2016-12-05 14:48:37 +03:00
stbsp__int32 e , et , eb ;
2016-12-05 13:57:06 +03:00
double p2h , p2l ;
e = power ; if ( power < 0 ) e = - e ;
et = ( e * 0x2c9 ) > > 14 ; /* %23 */ if ( et > 13 ) et = 13 ; eb = e - ( et * 23 ) ;
ph = d ; pl = 0.0 ;
if ( power < 0 )
{
2016-12-05 14:48:37 +03:00
if ( eb ) { - - eb ; stbsp__ddmulthi ( ph , pl , d , stbsp__negbot [ eb ] ) ; stbsp__ddmultlos ( ph , pl , d , stbsp__negboterr [ eb ] ) ; }
2016-12-05 13:57:06 +03:00
if ( et )
{
2016-12-05 14:48:37 +03:00
stbsp__ddrenorm ( ph , pl ) ;
- - et ; stbsp__ddmulthi ( p2h , p2l , ph , stbsp__negtop [ et ] ) ; stbsp__ddmultlo ( p2h , p2l , ph , pl , stbsp__negtop [ et ] , stbsp__negtoperr [ et ] ) ; ph = p2h ; pl = p2l ;
2016-12-05 13:57:06 +03:00
}
}
else
{
if ( eb )
{
e = eb ; if ( eb > 22 ) eb = 22 ; e - = eb ;
2016-12-05 14:48:37 +03:00
stbsp__ddmulthi ( ph , pl , d , stbsp__bot [ eb ] ) ;
if ( e ) { stbsp__ddrenorm ( ph , pl ) ; stbsp__ddmulthi ( p2h , p2l , ph , stbsp__bot [ e ] ) ; stbsp__ddmultlos ( p2h , p2l , stbsp__bot [ e ] , pl ) ; ph = p2h ; pl = p2l ; }
2016-12-05 13:57:06 +03:00
}
if ( et )
{
2016-12-05 14:48:37 +03:00
stbsp__ddrenorm ( ph , pl ) ;
- - et ; stbsp__ddmulthi ( p2h , p2l , ph , stbsp__top [ et ] ) ; stbsp__ddmultlo ( p2h , p2l , ph , pl , stbsp__top [ et ] , stbsp__toperr [ et ] ) ; ph = p2h ; pl = p2l ;
2016-12-05 13:57:06 +03:00
}
}
}
2016-12-05 14:48:37 +03:00
stbsp__ddrenorm ( ph , pl ) ;
2016-12-05 13:57:06 +03:00
* ohi = ph ; * olo = pl ;
}
// given a float value, returns the significant bits in bits, and the position of the
// decimal point in decimal_pos. +/-INF and NAN are specified by special values
// returned in the decimal_pos parameter.
// frac_digits is absolute normally, but if you want from first significant digits (got %g and %e), or in 0x80000000
2016-12-05 14:48:37 +03:00
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 )
2016-12-05 13:57:06 +03:00
{
double d ;
2016-12-05 14:48:37 +03:00
stbsp__int64 bits = 0 ;
stbsp__int32 expo , e , ng , tens ;
2016-12-05 13:57:06 +03:00
d = value ;
2016-12-05 14:48:37 +03:00
STBSP__COPYFP ( bits , d ) ;
expo = ( stbsp__int32 ) ( ( bits > > 52 ) & 2047 ) ;
ng = ( stbsp__int32 ) ( bits > > 63 ) ;
2016-12-05 13:57:06 +03:00
if ( ng ) d = - d ;
if ( expo = = 2047 ) // is nan or inf?
{
2016-12-05 14:48:37 +03:00
* start = ( bits & ( ( ( ( stbsp__uint64 ) 1 ) < < 52 ) - 1 ) ) ? " NaN " : " Inf " ;
* decimal_pos = STBSP__SPECIAL ;
2016-12-05 13:57:06 +03:00
* len = 3 ;
return ng ;
}
if ( expo = = 0 ) // is zero or denormal
{
if ( ( bits < < 1 ) = = 0 ) // do zero
{
* decimal_pos = 1 ;
* start = out ;
out [ 0 ] = ' 0 ' ; * len = 1 ;
return ng ;
}
// find the right expo for denormals
{
2016-12-05 14:48:37 +03:00
stbsp__int64 v = ( ( stbsp__uint64 ) 1 ) < < 51 ;
2016-12-05 13:57:06 +03:00
while ( ( bits & v ) = = 0 ) { - - expo ; v > > = 1 ; }
}
}
// find the decimal exponent as well as the decimal bits of the value
{
double ph , pl ;
// log10 estimate - very specifically tweaked to hit or undershoot by no more than 1 of log10 of all expos 1..2046
tens = expo - 1023 ; tens = ( tens < 0 ) ? ( ( tens * 617 ) / 2048 ) : ( ( ( tens * 1233 ) / 4096 ) + 1 ) ;
// move the significant bits into position and stick them into an int
2016-12-05 14:48:37 +03:00
stbsp__raise_to_power10 ( & ph , & pl , d , 18 - tens ) ;
2016-12-05 13:57:06 +03:00
// get full as much precision from double-double as possible
2016-12-05 14:48:37 +03:00
stbsp__ddtoS64 ( bits , ph , pl ) ;
2016-12-05 13:57:06 +03:00
// check if we undershot
2016-12-05 14:48:37 +03:00
if ( ( ( stbsp__uint64 ) bits ) > = stbsp__tento19th ) + + tens ;
2016-12-05 13:57:06 +03:00
}
// now do the rounding in integer land
frac_digits = ( frac_digits & 0x80000000 ) ? ( ( frac_digits & 0x7ffffff ) + 1 ) : ( tens + frac_digits ) ;
if ( ( frac_digits < 24 ) )
{
2016-12-05 14:48:37 +03:00
stbsp__uint32 dg = 1 ; if ( ( stbsp__uint64 ) bits > = stbsp__powten [ 9 ] ) dg = 10 ; while ( ( stbsp__uint64 ) bits > = stbsp__powten [ dg ] ) { + + dg ; if ( dg = = 20 ) goto noround ; }
2016-12-05 13:57:06 +03:00
if ( frac_digits < dg )
{
2016-12-05 14:48:37 +03:00
stbsp__uint64 r ;
2016-12-05 13:57:06 +03:00
// add 0.5 at the right position and round
e = dg - frac_digits ;
2016-12-05 14:48:37 +03:00
if ( ( stbsp__uint32 ) e > = 24 ) goto noround ;
r = stbsp__powten [ e ] ;
2016-12-05 13:57:06 +03:00
bits = bits + ( r / 2 ) ;
2016-12-05 14:48:37 +03:00
if ( ( stbsp__uint64 ) bits > = stbsp__powten [ dg ] ) + + tens ;
2016-12-05 13:57:06 +03:00
bits / = r ;
}
noround : ;
}
// kill long trailing runs of zeros
if ( bits )
{
2016-12-05 14:48:37 +03:00
stbsp__uint32 n ;
for ( ; ; ) { if ( bits < = 0xffffffff ) break ; if ( bits % 1000 ) goto donez ; bits / = 1000 ; }
n = ( stbsp__uint32 ) bits ;
while ( ( n % 1000 ) = = 0 ) n / = 1000 ;
bits = n ;
donez : ;
2016-12-05 13:57:06 +03:00
}
// convert to string
out + = 64 ;
e = 0 ;
for ( ; ; )
{
2016-12-05 14:48:37 +03:00
stbsp__uint32 n ;
2016-12-05 13:57:06 +03:00
char * o = out - 8 ;
// do the conversion in chunks of U32s (avoid most 64-bit divides, worth it, constant denomiators be damned)
2016-12-05 14:48:37 +03:00
if ( bits > = 100000000 ) { n = ( stbsp__uint32 ) ( bits % 100000000 ) ; bits / = 100000000 ; } else { n = ( stbsp__uint32 ) bits ; bits = 0 ; }
while ( n ) { out - = 2 ; * ( stbsp__uint16 * ) out = * ( stbsp__uint16 * ) & stbsp__digitpair [ ( n % 100 ) * 2 ] ; n / = 100 ; e + = 2 ; }
2016-12-05 13:57:06 +03:00
if ( bits = = 0 ) { if ( ( e ) & & ( out [ 0 ] = = ' 0 ' ) ) { + + out ; - - e ; } break ; }
while ( out ! = o ) { * - - out = ' 0 ' ; + + e ; }
}
* decimal_pos = tens ;
* start = out ;
* len = e ;
return ng ;
}
2016-12-05 14:48:37 +03:00
# undef stbsp__ddmulthi
# undef stbsp__ddrenorm
# undef stbsp__ddmultlo
# undef stbsp__ddmultlos
# undef STBSP__SPECIAL
# undef STBSP__COPYFP
2016-12-05 13:57:06 +03:00
2016-12-05 14:48:37 +03:00
# endif // STB_SPRINTF_NOFLOAT
2016-12-05 13:57:06 +03:00
// clean up
2016-12-05 14:48:37 +03:00
# undef stbsp__uint16
# undef stbsp__uint32
# undef stbsp__int32
# undef stbsp__uint64
# undef stbsp__int64
# undef STBSP__UNALIGNED
# endif // STB_SPRINTF_IMPLEMENTATION
2017-03-03 18:53:07 +03:00
/*
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
This software is available under 2 licenses - - choose whichever you prefer .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ALTERNATIVE A - MIT License
Copyright ( c ) 2017 Sean Barrett
Permission is hereby granted , free of charge , to any person obtaining a copy of
this software and associated documentation files ( the " Software " ) , to deal in
the Software without restriction , including without limitation the rights to
use , copy , modify , merge , publish , distribute , sublicense , and / or sell copies
of the Software , and to permit persons to whom the Software is furnished to do
so , subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software .
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ALTERNATIVE B - Public Domain ( www . unlicense . org )
This is free and unencumbered software released into the public domain .
Anyone is free to copy , modify , publish , use , compile , sell , or distribute this
software , either in source code form or as a compiled binary , for any purpose ,
commercial or non - commercial , and by any means .
In jurisdictions that recognize copyright laws , the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain . We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors . We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law .
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER IN AN
ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/