diff --git a/stb_sprintf.h b/stb_sprintf.h index 540d13e..0ed30a0 100644 --- a/stb_sprintf.h +++ b/stb_sprintf.h @@ -8,6 +8,7 @@ // Contributors (bugfixes): // github:d26435 // github:trex78 +// Jari Komppa (SI suffixes) // // LICENSE: // @@ -99,8 +100,11 @@ 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. +tera and then printed, so "%$d" 1000 is "1.0 k", "%$.2d" 2536000 is +"2.53 M", etc. For byte values, use two $:s, like "%$$d" to turn +2536000 to "2.42 Mi". If you prefer JEDEC suffixes to SI ones, use three +$:s: "%$$$d" -> "2.42 M". To remove the space between the number and the +suffix, add "_" specifier: "%_$d" -> "2.53M". In addition to octal and hexadecimal conversions, you can print integers in binary: "%b" for 256 would print 100. @@ -222,6 +226,35 @@ STBSP__PUBLICDEF void STB_SPRINTF_DECORATE( set_separators )( char pcomma, char stbsp__comma=pcomma; } +#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 +#define STBSP__METRIC_NOSPACE 1024 +#define STBSP__METRIC_1024 2048 +#define STBSP__METRIC_JEDEC 4096 + +static void stbsp__lead_sign(stbsp__uint32 fl, char *sign) +{ + sign[0] = 0; + if (fl&STBSP__NEGATIVE) { + sign[0]=1; + sign[1]='-'; + } else if (fl&STBSP__LEADINGSPACE) { + sign[0]=1; + sign[1]=' '; + } else if (fl&STBSP__LEADINGPLUS) { + sign[0]=1; + sign[1]='+'; + } +} + STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsprintfcb )( STBSP_SPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va ) { static char hex[]="0123456789abcdefxp"; @@ -236,17 +269,6 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsprintfcb )( STBSP_SPRINTFCB * callb { 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 - // macros for the callback buffer stuff #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); } } @@ -296,8 +318,26 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsprintfcb )( STBSP_SPRINTFCB * callb case '#': fl|=STBSP__LEADING_0X; ++f; continue; // if we have thousand commas case '\'': fl|=STBSP__TRIPLET_COMMA; ++f; continue; - // if we have kilo marker - case '$': fl|=STBSP__METRIC_SUFFIX; ++f; continue; + // if we have kilo marker (none->kilo->kibi->jedec) + case '$': + if (fl&STBSP__METRIC_SUFFIX) + { + if (fl&STBSP__METRIC_1024) + { + fl|=STBSP__METRIC_JEDEC; + } + else + { + fl|=STBSP__METRIC_1024; + } + } + else + { + fl|=STBSP__METRIC_SUFFIX; + } + ++f; continue; + // if we don't want space between metric suffix and number + case '_': fl|=STBSP__METRIC_NOSPACE; ++f; continue; // if we have leading zero case '0': fl|=STBSP__LEADINGZERO; ++f; goto flags_done; default: goto flags_done; @@ -416,8 +456,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsprintfcb )( STBSP_SPRINTFCB * callb s = num+64; - // sign - 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]='+'; }; + stbsp__lead_sign(fl, lead); if (dp==-1023) dp=(n64)?-1022:0; else n64|=(((stbsp__uint64)1)<<52); n64<<=(64-56); @@ -491,7 +530,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsprintfcb )( STBSP_SPRINTFCB * callb fl |= STBSP__NEGATIVE; doexpfromg: tail[0]=0; - 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]='+'; }; + stbsp__lead_sign(fl, lead); if ( dp == STBSP__SPECIAL ) { s=(char*)sn; cs=0; pr=0; goto scopy; } s=num+64; // handle leading chars @@ -522,15 +561,20 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsprintfcb )( STBSP_SPRINTFCB * callb fv = va_arg(va,double); doafloat: // do kilos - if (fl&STBSP__METRIC_SUFFIX) {while(fl<0x4000000) { if ((fv<1024.0) && (fv>-1024.0)) break; fv/=1024.0; fl+=0x1000000; }} + if (fl&STBSP__METRIC_SUFFIX) + { + double divisor; + divisor=1000.0f; + if (fl&STBSP__METRIC_1024) divisor = 1024.0; + while(fl<0x4000000) { if ((fv-divisor)) break; fv/=divisor; fl+=0x1000000; } + } if (pr==-1) pr=6; // default is 6 // read the double into a string if ( stbsp__real_to_str( &sn, &l, num, &dp, fv, pr ) ) fl |= STBSP__NEGATIVE; dofloatfromg: tail[0]=0; - // sign - 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]='+'; }; + stbsp__lead_sign(fl, lead); if ( dp == STBSP__SPECIAL ) { s=(char*)sn; cs=0; pr=0; goto scopy; } s=num+64; @@ -575,7 +619,32 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsprintfcb )( STBSP_SPRINTFCB * callb pr = 0; // handle k,m,g,t - if (fl&STBSP__METRIC_SUFFIX) { tail[0]=1; tail[1]=' '; { if (fl>>24) { tail[2]="_kmgt"[fl>>24]; tail[0]=2; } } }; + if (fl&STBSP__METRIC_SUFFIX) + { + char idx; + idx=1; + if (fl&STBSP__METRIC_NOSPACE) + idx=0; + tail[0]=idx; + tail[1]=' '; + { + if (fl>>24) + { // SI kilo is 'k', JEDEC and SI kibits are 'K'. + if (fl&STBSP__METRIC_1024) + tail[idx+1]="_KMGT"[fl>>24]; + else + tail[idx+1]="_kMGT"[fl>>24]; + idx++; + // If printing kibits and not in jedec, add the 'i'. + if (fl&STBSP__METRIC_1024&&!(fl&STBSP__METRIC_JEDEC)) + { + tail[idx+1]='i'; + idx++; + } + tail[0]=idx; + } + } + }; flt_lead: // get the length that we copied @@ -669,8 +738,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsprintfcb )( STBSP_SPRINTFCB * callb } tail[0]=0; - // sign - 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]='+'; }; + stbsp__lead_sign(fl, lead); // get the length that we copied l = (stbsp__uint32) ( (num+STBSP__NUMSZ) - s ); if ( l == 0 ) { *--s='0'; l = 1; }