| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305 |
- /* stb_lib.h - v1.00 - http://nothings.org/stb
- no warranty is offered or implied; use this code at your own risk
- ============================================================================
- You MUST
-
- #define STB_LIB_IMPLEMENTATION
-
- in EXACTLY _one_ C or C++ file that includes this header, BEFORE the
- include, like this:
-
- #define STB_LIB_IMPLEMENTATION
- #include "stblib_files.h"
-
- All other files should just #include "stblib_files.h" without the #define.
- ============================================================================
- LICENSE
- See end of file for license information.
- CREDITS
- Written by Sean Barrett.
- Fixes:
- Philipp Wiesemann Robert Nix
- r-lyeh blackpawn
- github:Mojofreem Ryan Whitworth
- Vincent Isambart Mike Sartain
- Eugene Opalev Tim Sjostrand
- github:infatum Dave Butler
- */
- #ifndef STB_INCLUDE_STB_LIB_H
- #include <stdarg.h>
- #if defined(_WIN32) && !defined(__MINGW32__)
- #ifndef _CRT_SECURE_NO_WARNINGS
- #define _CRT_SECURE_NO_WARNINGS
- #endif
- #ifndef _CRT_NONSTDC_NO_DEPRECATE
- #define _CRT_NONSTDC_NO_DEPRECATE
- #endif
- #ifndef _CRT_NON_CONFORMING_SWPRINTFS
- #define _CRT_NON_CONFORMING_SWPRINTFS
- #endif
- #if !defined(_MSC_VER) || _MSC_VER > 1700
- #include <intrin.h> // _BitScanReverse
- #endif
- #endif
- #include <stdlib.h> // stdlib could have min/max
- #include <stdio.h> // need FILE
- #include <string.h> // stb_define_hash needs memcpy/memset
- #include <time.h> // stb_dirtree
- typedef unsigned char stb_uchar;
- typedef unsigned char stb_uint8;
- typedef unsigned int stb_uint;
- typedef unsigned short stb_uint16;
- typedef short stb_int16;
- typedef signed char stb_int8;
- #if defined(STB_USE_LONG_FOR_32_BIT_INT) || defined(STB_LONG32)
- typedef unsigned long stb_uint32;
- typedef long stb_int32;
- #else
- typedef unsigned int stb_uint32;
- typedef int stb_int32;
- #endif
- typedef char stb__testsize2_16[sizeof(stb_uint16)==2 ? 1 : -1];
- typedef char stb__testsize2_32[sizeof(stb_uint32)==4 ? 1 : -1];
- #ifdef _MSC_VER
- typedef unsigned __int64 stb_uint64;
- typedef __int64 stb_int64;
- #define STB_IMM_UINT64(literalui64) (literalui64##ui64)
- #else
- // ??
- typedef unsigned long long stb_uint64;
- typedef long long stb_int64;
- #define STB_IMM_UINT64(literalui64) (literalui64##ULL)
- #endif
- typedef char stb__testsize2_64[sizeof(stb_uint64)==8 ? 1 : -1];
- #ifdef __cplusplus
- #define STB_EXTERN extern "C"
- #else
- #define STB_EXTERN extern
- #endif
- // check for well-known debug defines
- #if defined(DEBUG) || defined(_DEBUG) || defined(DBG)
- #ifndef NDEBUG
- #define STB_DEBUG
- #endif
- #endif
- #ifdef STB_DEBUG
- #include <assert.h>
- #endif
- #endif // STB_INCLUDE_STB_LIB_H
- #ifdef STB_LIB_IMPLEMENTATION
- #include <assert.h>
- #include <stdarg.h>
- #include <stddef.h>
- #include <ctype.h>
- #include <math.h>
- #ifndef _WIN32
- #include <unistd.h>
- #else
- #include <io.h> // _mktemp
- #include <direct.h> // _rmdir
- #endif
- #include <sys/types.h> // stat()/_stat()
- #include <sys/stat.h> // stat()/_stat()
- #endif
- //////////////////////////////////////////////////////////////////////////////
- //
- // Miscellany
- //
- #ifdef _WIN32
- #define stb_stricmp(a,b) stricmp(a,b)
- #define stb_strnicmp(a,b,n) strnicmp(a,b,n)
- #else
- #define stb_stricmp(a,b) strcasecmp(a,b)
- #define stb_strnicmp(a,b,n) strncasecmp(a,b,n)
- #endif
- #ifndef STB_INCLUDE_STB_LIB_H
- STB_EXTERN void stb_fatal(char *fmt, ...);
- STB_EXTERN void stb_swap(void *p, void *q, size_t sz);
- STB_EXTERN double stb_linear_remap(double x, double x_min, double x_max,
- double out_min, double out_max);
- #define stb_arrcount(x) (sizeof(x)/sizeof((x)[0]))
- #define stb_lerp(t,a,b) ( (a) + (t) * (float) ((b)-(a)) )
- #define stb_unlerp(t,a,b) ( ((t) - (a)) / (float) ((b) - (a)) )
- #endif
- #ifdef STB_LIB_IMPLEMENTATION
- void stb_fatal(char *s, ...)
- {
- va_list a;
- va_start(a,s);
- fputs("Fatal error: ", stderr);
- vfprintf(stderr, s, a);
- va_end(a);
- fputs("\n", stderr);
- #ifdef STB_DEBUG
- #ifdef _MSC_VER
- #ifndef _WIN64
- __asm int 3; // trap to debugger!
- #else
- __debugbreak();
- #endif
- #else
- __builtin_trap();
- #endif
- #endif
- exit(1);
- }
- typedef struct { char d[4]; } stb__4;
- typedef struct { char d[8]; } stb__8;
- // optimize the small cases, though you shouldn't be calling this for those!
- void stb_swap(void *p, void *q, size_t sz)
- {
- char buffer[256];
- if (p == q) return;
- if (sz == 4) {
- stb__4 temp = * ( stb__4 *) p;
- * (stb__4 *) p = * ( stb__4 *) q;
- * (stb__4 *) q = temp;
- return;
- } else if (sz == 8) {
- stb__8 temp = * ( stb__8 *) p;
- * (stb__8 *) p = * ( stb__8 *) q;
- * (stb__8 *) q = temp;
- return;
- }
- while (sz > sizeof(buffer)) {
- stb_swap(p, q, sizeof(buffer));
- p = (char *) p + sizeof(buffer);
- q = (char *) q + sizeof(buffer);
- sz -= sizeof(buffer);
- }
- memcpy(buffer, p , sz);
- memcpy(p , q , sz);
- memcpy(q , buffer, sz);
- }
- #ifdef stb_linear_remap
- #undef stb_linear_remap
- #endif
- double stb_linear_remap(double x, double x_min, double x_max,
- double out_min, double out_max)
- {
- return stb_lerp(stb_unlerp(x,x_min,x_max),out_min,out_max);
- }
- #define stb_linear_remap(t,a,b,c,d) stb_lerp(stb_unlerp(t,a,b),c,d)
- #endif // STB_LIB_IMPLEMENTATION
- #ifndef STB_INCLUDE_STB_LIB_H
- // avoid unnecessary function call, but define function so its address can be taken
- #ifndef stb_linear_remap
- #define stb_linear_remap(t,a,b,c,d) stb_lerp(stb_unlerp(t,a,b),c,d)
- #endif
- #endif
- //////////////////////////////////////////////////////////////////////////////
- //
- // cross-platform snprintf because they keep changing that,
- // and with old compilers without vararg macros we can't write
- // a macro wrapper to fix it up
- #ifndef STB_INCLUDE_STB_LIB_H
- STB_EXTERN int stb_snprintf(char *s, size_t n, const char *fmt, ...);
- STB_EXTERN int stb_vsnprintf(char *s, size_t n, const char *fmt, va_list v);
- STB_EXTERN char *stb_sprintf(const char *fmt, ...);
- #endif
- #ifdef STB_LIB_IMPLEMENTATION
- int stb_vsnprintf(char *s, size_t n, const char *fmt, va_list v)
- {
- int res;
- #ifdef _WIN32
- // Could use "_vsnprintf_s(s, n, _TRUNCATE, fmt, v)" ?
- res = _vsnprintf(s,n,fmt,v);
- #else
- res = vsnprintf(s,n,fmt,v);
- #endif
- if (n) s[n-1] = 0;
- // Unix returns length output would require, Windows returns negative when truncated.
- return (res >= (int) n || res < 0) ? -1 : res;
- }
- int stb_snprintf(char *s, size_t n, const char *fmt, ...)
- {
- int res;
- va_list v;
- va_start(v,fmt);
- res = stb_vsnprintf(s, n, fmt, v);
- va_end(v);
- return res;
- }
- char *stb_sprintf(const char *fmt, ...)
- {
- static char buffer[1024];
- va_list v;
- va_start(v,fmt);
- stb_vsnprintf(buffer,1024,fmt,v);
- va_end(v);
- return buffer;
- }
- #endif
- //////////////////////////////////////////////////////////////////////////////
- //
- // Windows UTF8 filename handling
- //
- // Windows stupidly treats 8-bit filenames as some dopey code page,
- // rather than utf-8. If we want to use utf8 filenames, we have to
- // convert them to WCHAR explicitly and call WCHAR versions of the
- // file functions. So, ok, we do.
- #ifndef STB_INCLUDE_STB_LIB_H
- #ifdef _WIN32
- #define stb__fopen(x,y) _wfopen((const wchar_t *)stb__from_utf8(x), (const wchar_t *)stb__from_utf8_alt(y))
- #define stb__windows(x,y) x
- #else
- #define stb__fopen(x,y) fopen(x,y)
- #define stb__windows(x,y) y
- #endif
- typedef unsigned short stb__wchar;
- STB_EXTERN stb__wchar * stb_from_utf8(stb__wchar *buffer, char *str, int n);
- STB_EXTERN char * stb_to_utf8 (char *buffer, stb__wchar *str, int n);
- STB_EXTERN stb__wchar *stb__from_utf8(char *str);
- STB_EXTERN stb__wchar *stb__from_utf8_alt(char *str);
- STB_EXTERN char *stb__to_utf8(stb__wchar *str);
- #endif
- #ifdef STB_LIB_IMPLEMENTATION
- stb__wchar * stb_from_utf8(stb__wchar *buffer, char *ostr, int n)
- {
- unsigned char *str = (unsigned char *) ostr;
- stb_uint32 c;
- int i=0;
- --n;
- while (*str) {
- if (i >= n)
- return NULL;
- if (!(*str & 0x80))
- buffer[i++] = *str++;
- else if ((*str & 0xe0) == 0xc0) {
- if (*str < 0xc2) return NULL;
- c = (*str++ & 0x1f) << 6;
- if ((*str & 0xc0) != 0x80) return NULL;
- buffer[i++] = c + (*str++ & 0x3f);
- } else if ((*str & 0xf0) == 0xe0) {
- if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return NULL;
- if (*str == 0xed && str[1] > 0x9f) return NULL; // str[1] < 0x80 is checked below
- c = (*str++ & 0x0f) << 12;
- if ((*str & 0xc0) != 0x80) return NULL;
- c += (*str++ & 0x3f) << 6;
- if ((*str & 0xc0) != 0x80) return NULL;
- buffer[i++] = c + (*str++ & 0x3f);
- } else if ((*str & 0xf8) == 0xf0) {
- if (*str > 0xf4) return NULL;
- if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return NULL;
- if (*str == 0xf4 && str[1] > 0x8f) return NULL; // str[1] < 0x80 is checked below
- c = (*str++ & 0x07) << 18;
- if ((*str & 0xc0) != 0x80) return NULL;
- c += (*str++ & 0x3f) << 12;
- if ((*str & 0xc0) != 0x80) return NULL;
- c += (*str++ & 0x3f) << 6;
- if ((*str & 0xc0) != 0x80) return NULL;
- c += (*str++ & 0x3f);
- // utf-8 encodings of values used in surrogate pairs are invalid
- if ((c & 0xFFFFF800) == 0xD800) return NULL;
- if (c >= 0x10000) {
- c -= 0x10000;
- if (i + 2 > n) return NULL;
- buffer[i++] = 0xD800 | (0x3ff & (c >> 10));
- buffer[i++] = 0xDC00 | (0x3ff & (c ));
- }
- } else
- return NULL;
- }
- buffer[i] = 0;
- return buffer;
- }
- char * stb_to_utf8(char *buffer, stb__wchar *str, int n)
- {
- int i=0;
- --n;
- while (*str) {
- if (*str < 0x80) {
- if (i+1 > n) return NULL;
- buffer[i++] = (char) *str++;
- } else if (*str < 0x800) {
- if (i+2 > n) return NULL;
- buffer[i++] = 0xc0 + (*str >> 6);
- buffer[i++] = 0x80 + (*str & 0x3f);
- str += 1;
- } else if (*str >= 0xd800 && *str < 0xdc00) {
- stb_uint32 c;
- if (i+4 > n) return NULL;
- c = ((str[0] - 0xd800) << 10) + ((str[1]) - 0xdc00) + 0x10000;
- buffer[i++] = 0xf0 + (c >> 18);
- buffer[i++] = 0x80 + ((c >> 12) & 0x3f);
- buffer[i++] = 0x80 + ((c >> 6) & 0x3f);
- buffer[i++] = 0x80 + ((c ) & 0x3f);
- str += 2;
- } else if (*str >= 0xdc00 && *str < 0xe000) {
- return NULL;
- } else {
- if (i+3 > n) return NULL;
- buffer[i++] = 0xe0 + (*str >> 12);
- buffer[i++] = 0x80 + ((*str >> 6) & 0x3f);
- buffer[i++] = 0x80 + ((*str ) & 0x3f);
- str += 1;
- }
- }
- buffer[i] = 0;
- return buffer;
- }
- stb__wchar *stb__from_utf8(char *str)
- {
- static stb__wchar buffer[4096];
- return stb_from_utf8(buffer, str, 4096);
- }
- stb__wchar *stb__from_utf8_alt(char *str)
- {
- static stb__wchar buffer[4096];
- return stb_from_utf8(buffer, str, 4096);
- }
- char *stb__to_utf8(stb__wchar *str)
- {
- static char buffer[4096];
- return stb_to_utf8(buffer, str, 4096);
- }
- #endif
- //////////////////////////////////////////////////////////////////////////////
- //
- // qsort Compare Routines
- // NOT THREAD SAFE
- #ifndef STB_INCLUDE_STB_LIB_H
- STB_EXTERN int (*stb_intcmp(int offset))(const void *a, const void *b);
- STB_EXTERN int (*stb_qsort_strcmp(int offset))(const void *a, const void *b);
- STB_EXTERN int (*stb_qsort_stricmp(int offset))(const void *a, const void *b);
- STB_EXTERN int (*stb_floatcmp(int offset))(const void *a, const void *b);
- STB_EXTERN int (*stb_doublecmp(int offset))(const void *a, const void *b);
- STB_EXTERN int (*stb_ucharcmp(int offset))(const void *a, const void *b);
- STB_EXTERN int (*stb_charcmp(int offset))(const void *a, const void *b);
- #endif
- #ifdef STB_LIB_IMPLEMENTATION
- static int stb__intcmpoffset, stb__ucharcmpoffset, stb__strcmpoffset;
- static int stb__floatcmpoffset, stb__doublecmpoffset, stb__charcmpoffset;
- int stb__intcmp(const void *a, const void *b)
- {
- const int p = *(const int *) ((const char *) a + stb__intcmpoffset);
- const int q = *(const int *) ((const char *) b + stb__intcmpoffset);
- return p < q ? -1 : p > q;
- }
- int stb__ucharcmp(const void *a, const void *b)
- {
- const int p = *(const unsigned char *) ((const char *) a + stb__ucharcmpoffset);
- const int q = *(const unsigned char *) ((const char *) b + stb__ucharcmpoffset);
- return p < q ? -1 : p > q;
- }
- int stb__charcmp(const void *a, const void *b)
- {
- const int p = *(const char *) ((const char *) a + stb__ucharcmpoffset);
- const int q = *(const char *) ((const char *) b + stb__ucharcmpoffset);
- return p < q ? -1 : p > q;
- }
- int stb__floatcmp(const void *a, const void *b)
- {
- const float p = *(const float *) ((const char *) a + stb__floatcmpoffset);
- const float q = *(const float *) ((const char *) b + stb__floatcmpoffset);
- return p < q ? -1 : p > q;
- }
- int stb__doublecmp(const void *a, const void *b)
- {
- const double p = *(const double *) ((const char *) a + stb__doublecmpoffset);
- const double q = *(const double *) ((const char *) b + stb__doublecmpoffset);
- return p < q ? -1 : p > q;
- }
- int stb__qsort_strcmp(const void *a, const void *b)
- {
- const char *p = *(const char **) ((const char *) a + stb__strcmpoffset);
- const char *q = *(const char **) ((const char *) b + stb__strcmpoffset);
- return strcmp(p,q);
- }
- int stb__qsort_stricmp(const void *a, const void *b)
- {
- const char *p = *(const char **) ((const char *) a + stb__strcmpoffset);
- const char *q = *(const char **) ((const char *) b + stb__strcmpoffset);
- return stb_stricmp(p,q);
- }
- int (*stb_intcmp(int offset))(const void *, const void *)
- {
- stb__intcmpoffset = offset;
- return &stb__intcmp;
- }
- int (*stb_ucharcmp(int offset))(const void *, const void *)
- {
- stb__ucharcmpoffset = offset;
- return &stb__ucharcmp;
- }
- int (*stb_charcmp(int offset))(const void *, const void *)
- {
- stb__charcmpoffset = offset;
- return &stb__ucharcmp;
- }
- int (*stb_qsort_strcmp(int offset))(const void *, const void *)
- {
- stb__strcmpoffset = offset;
- return &stb__qsort_strcmp;
- }
- int (*stb_qsort_stricmp(int offset))(const void *, const void *)
- {
- stb__strcmpoffset = offset;
- return &stb__qsort_stricmp;
- }
- int (*stb_floatcmp(int offset))(const void *, const void *)
- {
- stb__floatcmpoffset = offset;
- return &stb__floatcmp;
- }
- int (*stb_doublecmp(int offset))(const void *, const void *)
- {
- stb__doublecmpoffset = offset;
- return &stb__doublecmp;
- }
- #endif
- //////////////////////////////////////////////////////////////////////////////
- //
- // String Processing
- //
- #ifndef STB_INCLUDE_STB_LIB_H
- #define stb_prefixi(s,t) (0==stb_strnicmp((s),(t),strlen(t)))
- enum stb_splitpath_flag
- {
- STB_PATH = 1,
- STB_FILE = 2,
- STB_EXT = 4,
- STB_PATH_FILE = STB_PATH + STB_FILE,
- STB_FILE_EXT = STB_FILE + STB_EXT,
- STB_EXT_NO_PERIOD = 8,
- };
- STB_EXTERN char * stb_skipwhite(char *s);
- STB_EXTERN char * stb_trimwhite(char *s);
- STB_EXTERN char * stb_skipnewline(char *s);
- STB_EXTERN char * stb_strncpy(char *s, char *t, int n);
- STB_EXTERN char * stb_substr(char *t, int n);
- STB_EXTERN char * stb_duplower(char *s);
- STB_EXTERN void stb_tolower (char *s);
- STB_EXTERN char * stb_strchr2 (char *s, char p1, char p2);
- STB_EXTERN char * stb_strrchr2(char *s, char p1, char p2);
- STB_EXTERN char * stb_strtok(char *output, char *src, char *delimit);
- STB_EXTERN char * stb_strtok_keep(char *output, char *src, char *delimit);
- STB_EXTERN char * stb_strtok_invert(char *output, char *src, char *allowed);
- STB_EXTERN char * stb_dupreplace(char *s, char *find, char *replace);
- STB_EXTERN void stb_replaceinplace(char *s, char *find, char *replace);
- STB_EXTERN char * stb_splitpath(char *output, char *src, int flag);
- STB_EXTERN char * stb_splitpathdup(char *src, int flag);
- STB_EXTERN char * stb_replacedir(char *output, char *src, char *dir);
- STB_EXTERN char * stb_replaceext(char *output, char *src, char *ext);
- STB_EXTERN void stb_fixpath(char *path);
- STB_EXTERN char * stb_shorten_path_readable(char *path, int max_len);
- STB_EXTERN int stb_suffix (char *s, char *t);
- STB_EXTERN int stb_suffixi(char *s, char *t);
- STB_EXTERN int stb_prefix (char *s, char *t);
- STB_EXTERN char * stb_strichr(char *s, char t);
- STB_EXTERN char * stb_stristr(char *s, char *t);
- STB_EXTERN int stb_prefix_count(char *s, char *t);
- STB_EXTERN const char * stb_plural(int n); // "s" or ""
- STB_EXTERN size_t stb_strscpy(char *d, const char *s, size_t n);
- STB_EXTERN char **stb_tokens(char *src, char *delimit, int *count);
- STB_EXTERN char **stb_tokens_nested(char *src, char *delimit, int *count, char *nest_in, char *nest_out);
- STB_EXTERN char **stb_tokens_nested_empty(char *src, char *delimit, int *count, char *nest_in, char *nest_out);
- STB_EXTERN char **stb_tokens_allowempty(char *src, char *delimit, int *count);
- STB_EXTERN char **stb_tokens_stripwhite(char *src, char *delimit, int *count);
- STB_EXTERN char **stb_tokens_withdelim(char *src, char *delimit, int *count);
- STB_EXTERN char **stb_tokens_quoted(char *src, char *delimit, int *count);
- // with 'quoted', allow delimiters to appear inside quotation marks, and don't
- // strip whitespace inside them (and we delete the quotation marks unless they
- // appear back to back, in which case they're considered escaped)
- #endif // STB_INCLUDE_STB_LIB_H
- #ifdef STB_LIB_IMPLEMENTATION
- #include <ctype.h>
- size_t stb_strscpy(char *d, const char *s, size_t n)
- {
- size_t len = strlen(s);
- if (len >= n) {
- if (n) d[0] = 0;
- return 0;
- }
- strcpy(d,s);
- return len + 1;
- }
- const char *stb_plural(int n)
- {
- return n == 1 ? "" : "s";
- }
- int stb_prefix(char *s, char *t)
- {
- while (*t)
- if (*s++ != *t++)
- return 0;
- return 1;
- }
- int stb_prefix_count(char *s, char *t)
- {
- int c=0;
- while (*t) {
- if (*s++ != *t++)
- break;
- ++c;
- }
- return c;
- }
- int stb_suffix(char *s, char *t)
- {
- size_t n = strlen(s);
- size_t m = strlen(t);
- if (m <= n)
- return 0 == strcmp(s+n-m, t);
- else
- return 0;
- }
- int stb_suffixi(char *s, char *t)
- {
- size_t n = strlen(s);
- size_t m = strlen(t);
- if (m <= n)
- return 0 == stb_stricmp(s+n-m, t);
- else
- return 0;
- }
- // originally I was using this table so that I could create known sentinel
- // values--e.g. change whitetable[0] to be true if I was scanning for whitespace,
- // and false if I was scanning for nonwhite. I don't appear to be using that
- // functionality anymore (I do for tokentable, though), so just replace it
- // with isspace()
- char *stb_skipwhite(char *s)
- {
- while (isspace((unsigned char) *s)) ++s;
- return s;
- }
- char *stb_skipnewline(char *s)
- {
- if (s[0] == '\r' || s[0] == '\n') {
- if (s[0]+s[1] == '\r' + '\n') ++s;
- ++s;
- }
- return s;
- }
- char *stb_trimwhite(char *s)
- {
- int i,n;
- s = stb_skipwhite(s);
- n = (int) strlen(s);
- for (i=n-1; i >= 0; --i)
- if (!isspace(s[i]))
- break;
- s[i+1] = 0;
- return s;
- }
- char *stb_strncpy(char *s, char *t, int n)
- {
- strncpy(s,t,n);
- s[n-1] = 0;
- return s;
- }
- char *stb_substr(char *t, int n)
- {
- char *a;
- int z = (int) strlen(t);
- if (z < n) n = z;
- a = (char *) malloc(n+1);
- strncpy(a,t,n);
- a[n] = 0;
- return a;
- }
- char *stb_duplower(char *s)
- {
- char *p = strdup(s), *q = p;
- while (*q) {
- *q = tolower(*q);
- ++q;
- }
- return p;
- }
- void stb_tolower(char *s)
- {
- while (*s) {
- *s = tolower(*s);
- ++s;
- }
- }
- char *stb_strchr2(char *s, char x, char y)
- {
- for(; *s; ++s)
- if (*s == x || *s == y)
- return s;
- return NULL;
- }
- char *stb_strrchr2(char *s, char x, char y)
- {
- char *r = NULL;
- for(; *s; ++s)
- if (*s == x || *s == y)
- r = s;
- return r;
- }
- char *stb_strichr(char *s, char t)
- {
- if (tolower(t) == toupper(t))
- return strchr(s,t);
- return stb_strchr2(s, (char) tolower(t), (char) toupper(t));
- }
- char *stb_stristr(char *s, char *t)
- {
- size_t n = strlen(t);
- char *z;
- if (n==0) return s;
- while ((z = stb_strichr(s, *t)) != NULL) {
- if (0==stb_strnicmp(z, t, n))
- return z;
- s = z+1;
- }
- return NULL;
- }
- static char *stb_strtok_raw(char *output, char *src, char *delimit, int keep, int invert)
- {
- if (invert) {
- while (*src && strchr(delimit, *src) != NULL) {
- *output++ = *src++;
- }
- } else {
- while (*src && strchr(delimit, *src) == NULL) {
- *output++ = *src++;
- }
- }
- *output = 0;
- if (keep)
- return src;
- else
- return *src ? src+1 : src;
- }
- char *stb_strtok(char *output, char *src, char *delimit)
- {
- return stb_strtok_raw(output, src, delimit, 0, 0);
- }
- char *stb_strtok_keep(char *output, char *src, char *delimit)
- {
- return stb_strtok_raw(output, src, delimit, 1, 0);
- }
- char *stb_strtok_invert(char *output, char *src, char *delimit)
- {
- return stb_strtok_raw(output, src, delimit, 1,1);
- }
- static char **stb_tokens_raw(char *src_, char *delimit, int *count,
- int stripwhite, int allow_empty, char *start, char *end)
- {
- int nested = 0;
- unsigned char *src = (unsigned char *) src_;
- static char stb_tokentable[256]; // rely on static initializion to 0
- static char stable[256],etable[256];
- char *out;
- char **result;
- int num=0;
- unsigned char *s;
- s = (unsigned char *) delimit; while (*s) stb_tokentable[*s++] = 1;
- if (start) {
- s = (unsigned char *) start; while (*s) stable[*s++] = 1;
- s = (unsigned char *) end; if (s) while (*s) stable[*s++] = 1;
- s = (unsigned char *) end; if (s) while (*s) etable[*s++] = 1;
- }
- stable[0] = 1;
- // two passes through: the first time, counting how many
- s = (unsigned char *) src;
- while (*s) {
- // state: just found delimiter
- // skip further delimiters
- if (!allow_empty) {
- stb_tokentable[0] = 0;
- while (stb_tokentable[*s])
- ++s;
- if (!*s) break;
- }
- ++num;
- // skip further non-delimiters
- stb_tokentable[0] = 1;
- if (stripwhite == 2) { // quoted strings
- while (!stb_tokentable[*s]) {
- if (*s != '"')
- ++s;
- else {
- ++s;
- if (*s == '"')
- ++s; // "" -> ", not start a string
- else {
- // begin a string
- while (*s) {
- if (s[0] == '"') {
- if (s[1] == '"') s += 2; // "" -> "
- else { ++s; break; } // terminating "
- } else
- ++s;
- }
- }
- }
- }
- } else
- while (nested || !stb_tokentable[*s]) {
- if (stable[*s]) {
- if (!*s) break;
- if (end ? etable[*s] : nested)
- --nested;
- else
- ++nested;
- }
- ++s;
- }
- if (allow_empty) {
- if (*s) ++s;
- }
- }
- // now num has the actual count... malloc our output structure
- // need space for all the strings: strings won't be any longer than
- // original input, since for every '\0' there's at least one delimiter
- result = (char **) malloc(sizeof(*result) * (num+1) + (s-src+1));
- if (result == NULL) return result;
- out = (char *) (result + (num+1));
- // second pass: copy out the data
- s = (unsigned char *) src;
- num = 0;
- nested = 0;
- while (*s) {
- char *last_nonwhite;
- // state: just found delimiter
- // skip further delimiters
- if (!allow_empty) {
- stb_tokentable[0] = 0;
- if (stripwhite)
- while (stb_tokentable[*s] || isspace(*s))
- ++s;
- else
- while (stb_tokentable[*s])
- ++s;
- } else if (stripwhite) {
- while (isspace(*s)) ++s;
- }
- if (!*s) break;
- // we're past any leading delimiters and whitespace
- result[num] = out;
- ++num;
- // copy non-delimiters
- stb_tokentable[0] = 1;
- last_nonwhite = out-1;
- if (stripwhite == 2) {
- while (!stb_tokentable[*s]) {
- if (*s != '"') {
- if (!isspace(*s)) last_nonwhite = out;
- *out++ = *s++;
- } else {
- ++s;
- if (*s == '"') {
- if (!isspace(*s)) last_nonwhite = out;
- *out++ = *s++; // "" -> ", not start string
- } else {
- // begin a quoted string
- while (*s) {
- if (s[0] == '"') {
- if (s[1] == '"') { *out++ = *s; s += 2; }
- else { ++s; break; } // terminating "
- } else
- *out++ = *s++;
- }
- last_nonwhite = out-1; // all in quotes counts as non-white
- }
- }
- }
- } else {
- while (nested || !stb_tokentable[*s]) {
- if (!isspace(*s)) last_nonwhite = out;
- if (stable[*s]) {
- if (!*s) break;
- if (end ? etable[*s] : nested)
- --nested;
- else
- ++nested;
- }
- *out++ = *s++;
- }
- }
- if (stripwhite) // rewind to last non-whitespace char
- out = last_nonwhite+1;
- *out++ = '\0';
- if (*s) ++s; // skip delimiter
- }
- s = (unsigned char *) delimit; while (*s) stb_tokentable[*s++] = 0;
- if (start) {
- s = (unsigned char *) start; while (*s) stable[*s++] = 1;
- s = (unsigned char *) end; if (s) while (*s) stable[*s++] = 1;
- s = (unsigned char *) end; if (s) while (*s) etable[*s++] = 1;
- }
- if (count != NULL) *count = num;
- result[num] = 0;
- return result;
- }
- char **stb_tokens(char *src, char *delimit, int *count)
- {
- return stb_tokens_raw(src,delimit,count,0,0,0,0);
- }
- char **stb_tokens_nested(char *src, char *delimit, int *count, char *nest_in, char *nest_out)
- {
- return stb_tokens_raw(src,delimit,count,0,0,nest_in,nest_out);
- }
- char **stb_tokens_nested_empty(char *src, char *delimit, int *count, char *nest_in, char *nest_out)
- {
- return stb_tokens_raw(src,delimit,count,0,1,nest_in,nest_out);
- }
- char **stb_tokens_allowempty(char *src, char *delimit, int *count)
- {
- return stb_tokens_raw(src,delimit,count,0,1,0,0);
- }
- char **stb_tokens_stripwhite(char *src, char *delimit, int *count)
- {
- return stb_tokens_raw(src,delimit,count,1,1,0,0);
- }
- char **stb_tokens_quoted(char *src, char *delimit, int *count)
- {
- return stb_tokens_raw(src,delimit,count,2,1,0,0);
- }
- char *stb_dupreplace(char *src, char *find, char *replace)
- {
- size_t len_find = strlen(find);
- size_t len_replace = strlen(replace);
- int count = 0;
- char *s,*p,*q;
- s = strstr(src, find);
- if (s == NULL) return strdup(src);
- do {
- ++count;
- s = strstr(s + len_find, find);
- } while (s != NULL);
- p = (char *) malloc(strlen(src) + count * (len_replace - len_find) + 1);
- if (p == NULL) return p;
- q = p;
- s = src;
- for (;;) {
- char *t = strstr(s, find);
- if (t == NULL) {
- strcpy(q,s);
- assert(strlen(p) == strlen(src) + count*(len_replace-len_find));
- return p;
- }
- memcpy(q, s, t-s);
- q += t-s;
- memcpy(q, replace, len_replace);
- q += len_replace;
- s = t + len_find;
- }
- }
- void stb_replaceinplace(char *src, char *find, char *replace)
- {
- size_t len_find = strlen(find);
- size_t len_replace = strlen(replace);
- int delta;
- char *s,*p,*q;
- delta = len_replace - len_find;
- assert(delta <= 0);
- if (delta > 0) return;
- p = strstr(src, find);
- if (p == NULL) return;
- s = q = p;
- while (*s) {
- memcpy(q, replace, len_replace);
- p += len_find;
- q += len_replace;
- s = strstr(p, find);
- if (s == NULL) s = p + strlen(p);
- memmove(q, p, s-p);
- q += s-p;
- p = s;
- }
- *q = 0;
- }
- void stb_fixpath(char *path)
- {
- for(; *path; ++path)
- if (*path == '\\')
- *path = '/';
- }
- void stb__add_section(char *buffer, char *data, int curlen, int newlen)
- {
- if (newlen < curlen) {
- int z1 = newlen >> 1, z2 = newlen-z1;
- memcpy(buffer, data, z1-1);
- buffer[z1-1] = '.';
- buffer[z1-0] = '.';
- memcpy(buffer+z1+1, data+curlen-z2+1, z2-1);
- } else
- memcpy(buffer, data, curlen);
- }
- char * stb_shorten_path_readable(char *path, int len)
- {
- static char buffer[1024];
- int n = strlen(path),n1,n2,r1,r2;
- char *s;
- if (n <= len) return path;
- if (len > 1024) return path;
- s = stb_strrchr2(path, '/', '\\');
- if (s) {
- n1 = s - path + 1;
- n2 = n - n1;
- ++s;
- } else {
- n1 = 0;
- n2 = n;
- s = path;
- }
- // now we need to reduce r1 and r2 so that they fit in len
- if (n1 < len>>1) {
- r1 = n1;
- r2 = len - r1;
- } else if (n2 < len >> 1) {
- r2 = n2;
- r1 = len - r2;
- } else {
- r1 = n1 * len / n;
- r2 = n2 * len / n;
- if (r1 < len>>2) r1 = len>>2, r2 = len-r1;
- if (r2 < len>>2) r2 = len>>2, r1 = len-r2;
- }
- assert(r1 <= n1 && r2 <= n2);
- if (n1)
- stb__add_section(buffer, path, n1, r1);
- stb__add_section(buffer+r1, s, n2, r2);
- buffer[len] = 0;
- return buffer;
- }
- static char *stb__splitpath_raw(char *buffer, char *path, int flag)
- {
- int len=0,x,y, n = (int) strlen(path), f1,f2;
- char *s = stb_strrchr2(path, '/', '\\');
- char *t = strrchr(path, '.');
- if (s && t && t < s) t = NULL;
- if (s) ++s;
- if (flag == STB_EXT_NO_PERIOD)
- flag |= STB_EXT;
- if (!(flag & (STB_PATH | STB_FILE | STB_EXT))) return NULL;
- f1 = s == NULL ? 0 : s-path; // start of filename
- f2 = t == NULL ? n : t-path; // just past end of filename
- if (flag & STB_PATH) {
- x = 0; if (f1 == 0 && flag == STB_PATH) len=2;
- } else if (flag & STB_FILE) {
- x = f1;
- } else {
- x = f2;
- if (flag & STB_EXT_NO_PERIOD)
- if (buffer[x] == '.')
- ++x;
- }
- if (flag & STB_EXT)
- y = n;
- else if (flag & STB_FILE)
- y = f2;
- else
- y = f1;
- if (buffer == NULL) {
- buffer = (char *) malloc(y-x + len + 1);
- if (!buffer) return NULL;
- }
- if (len) { strcpy(buffer, "./"); return buffer; }
- strncpy(buffer, path+x, y-x);
- buffer[y-x] = 0;
- return buffer;
- }
- char *stb_splitpath(char *output, char *src, int flag)
- {
- return stb__splitpath_raw(output, src, flag);
- }
- char *stb_splitpathdup(char *src, int flag)
- {
- return stb__splitpath_raw(NULL, src, flag);
- }
- char *stb_replacedir(char *output, char *src, char *dir)
- {
- char buffer[4096];
- stb_splitpath(buffer, src, STB_FILE | STB_EXT);
- if (dir)
- sprintf(output, "%s/%s", dir, buffer);
- else
- strcpy(output, buffer);
- return output;
- }
- char *stb_replaceext(char *output, char *src, char *ext)
- {
- char buffer[4096];
- stb_splitpath(buffer, src, STB_PATH | STB_FILE);
- if (ext)
- sprintf(output, "%s.%s", buffer, ext[0] == '.' ? ext+1 : ext);
- else
- strcpy(output, buffer);
- return output;
- }
- #endif
- //////////////////////////////////////////////////////////////////////////////
- //
- // stb_arr
- //
- // An stb_arr is directly useable as a pointer (use the actual type in your
- // definition), but when it resizes, it returns a new pointer and you can't
- // use the old one, so you have to be careful to copy-in-out as necessary.
- //
- // Use a NULL pointer as a 0-length array.
- //
- // float *my_array = NULL, *temp;
- //
- // // add elements on the end one at a time
- // stb_arr_push(my_array, 0.0f);
- // stb_arr_push(my_array, 1.0f);
- // stb_arr_push(my_array, 2.0f);
- //
- // assert(my_array[1] == 2.0f);
- //
- // // add an uninitialized element at the end, then assign it
- // *stb_arr_add(my_array) = 3.0f;
- //
- // // add three uninitialized elements at the end
- // temp = stb_arr_addn(my_array,3);
- // temp[0] = 4.0f;
- // temp[1] = 5.0f;
- // temp[2] = 6.0f;
- //
- // assert(my_array[5] == 5.0f);
- //
- // // remove the last one
- // stb_arr_pop(my_array);
- //
- // assert(stb_arr_len(my_array) == 6);
- #ifndef STB_INCLUDE_STB_LIB_H
- // simple functions written on top of other functions
- #define stb_arr_empty(a) ( stb_arr_len(a) == 0 )
- #define stb_arr_add(a) ( stb_arr_addn((a),1) )
- #define stb_arr_push(a,v) ( *stb_arr_add(a)=(v) )
- typedef struct
- {
- int len, limit;
- unsigned int signature;
- unsigned int padding; // make it a multiple of 16 so preserve alignment mod 16
- } stb__arr;
- #define stb_arr_signature 0x51bada7b // ends with 0123 in decimal
- // access the header block stored before the data
- #define stb_arrhead(a) /*lint --e(826)*/ (((stb__arr *) (a)) - 1)
- #define stb_arrhead2(a) /*lint --e(826)*/ (((stb__arr *) (a)) - 1)
- #ifdef STB_DEBUG
- #define stb_arr_check(a) assert(!a || stb_arrhead(a)->signature == stb_arr_signature)
- #define stb_arr_check2(a) assert(!a || stb_arrhead2(a)->signature == stb_arr_signature)
- #else
- #define stb_arr_check(a) ((void) 0)
- #define stb_arr_check2(a) ((void) 0)
- #endif
- // ARRAY LENGTH
- // get the array length; special case if pointer is NULL
- #define stb_arr_len(a) (a ? stb_arrhead(a)->len : 0)
- #define stb_arr_len2(a) ((stb__arr *) (a) ? stb_arrhead2(a)->len : 0)
- #define stb_arr_lastn(a) (stb_arr_len(a)-1)
- // check whether a given index is valid -- tests 0 <= i < stb_arr_len(a)
- #define stb_arr_valid(a,i) (a ? (int) (i) < stb_arrhead(a)->len : 0)
- // change the array length so is is exactly N entries long, creating
- // uninitialized entries as needed
- #define stb_arr_setlen(a,n) \
- (stb__arr_setlen((void **) &(a), sizeof(a[0]), (n)))
- // change the array length so that N is a valid index (that is, so
- // it is at least N entries long), creating uninitialized entries as needed
- #define stb_arr_makevalid(a,n) \
- (stb_arr_len(a) < (n)+1 ? stb_arr_setlen(a,(n)+1),(a) : (a))
- // remove the last element of the array, returning it
- #define stb_arr_pop(a) ((stb_arr_check(a), (a))[--stb_arrhead(a)->len])
- // access the last element in the array
- #define stb_arr_last(a) ((stb_arr_check(a), (a))[stb_arr_len(a)-1])
- // is iterator at end of list?
- #define stb_arr_end(a,i) ((i) >= &(a)[stb_arr_len(a)])
- // (internal) change the allocated length of the array
- #define stb_arr__grow(a,n) (stb_arr_check(a), stb_arrhead(a)->len += (n))
- // add N new uninitialized elements to the end of the array
- #define stb_arr__addn(a,n) /*lint --e(826)*/ \
- ((stb_arr_len(a)+(n) > stb_arrcurmax(a)) \
- ? (stb__arr_addlen((void **) &(a),sizeof(*a),(n)),0) \
- : ((stb_arr__grow(a,n), 0)))
- // add N new uninitialized elements to the end of the array, and return
- // a pointer to the first new one
- #define stb_arr_addn(a,n) (stb_arr__addn((a),n),(a)+stb_arr_len(a)-(n))
- // add N new uninitialized elements starting at index 'i'
- #define stb_arr_insertn(a,i,n) (stb__arr_insertn((void **) &(a), sizeof(*a), i, n))
- // insert an element at i
- #define stb_arr_insert(a,i,v) (stb__arr_insertn((void **) &(a), sizeof(*a), i, 1), ((a)[i] = v))
- // delete N elements from the middle starting at index 'i'
- #define stb_arr_deleten(a,i,n) (stb__arr_deleten((void **) &(a), sizeof(*a), i, n))
- // delete the i'th element
- #define stb_arr_delete(a,i) stb_arr_deleten(a,i,1)
- // delete the i'th element, swapping down from the end
- #define stb_arr_fastdelete(a,i) \
- (stb_swap(&a[i], &a[stb_arrhead(a)->len-1], sizeof(*a)), stb_arr_pop(a))
- // ARRAY STORAGE
- // get the array maximum storage; special case if NULL
- #define stb_arrcurmax(a) (a ? stb_arrhead(a)->limit : 0)
- #define stb_arrcurmax2(a) (a ? stb_arrhead2(a)->limit : 0)
- // set the maxlength of the array to n in anticipation of further growth
- #define stb_arr_setsize(a,n) (stb_arr_check(a), stb__arr_setsize((void **) &(a),sizeof((a)[0]),n))
- // make sure maxlength is large enough for at least N new allocations
- #define stb_arr_atleast(a,n) (stb_arr_len(a)+(n) > stb_arrcurmax(a) \
- ? stb_arr_setsize((a), (n)) : 0)
- // make a copy of a given array (copies contents via 'memcpy'!)
- #define stb_arr_copy(a) stb__arr_copy(a, sizeof((a)[0]))
- // compute the storage needed to store all the elements of the array
- #define stb_arr_storage(a) (stb_arr_len(a) * sizeof((a)[0]))
- #define stb_arr_for(v,arr) for((v)=(arr); (v) < (arr)+stb_arr_len(arr); ++(v))
- // IMPLEMENTATION
- STB_EXTERN void stb_arr_free_(void **p);
- STB_EXTERN void *stb__arr_copy_(void *p, int elem_size);
- STB_EXTERN void stb__arr_setsize_(void **p, int size, int limit);
- STB_EXTERN void stb__arr_setlen_(void **p, int size, int newlen);
- STB_EXTERN void stb__arr_addlen_(void **p, int size, int addlen);
- STB_EXTERN void stb__arr_deleten_(void **p, int size, int loc, int n);
- STB_EXTERN void stb__arr_insertn_(void **p, int size, int loc, int n);
- #define stb_arr_free(p) stb_arr_free_((void **) &(p))
- #ifndef STBLIB_MALLOC_WRAPPER // @Todo
- #define stb__arr_setsize stb__arr_setsize_
- #define stb__arr_setlen stb__arr_setlen_
- #define stb__arr_addlen stb__arr_addlen_
- #define stb__arr_deleten stb__arr_deleten_
- #define stb__arr_insertn stb__arr_insertn_
- #define stb__arr_copy stb__arr_copy_
- #else
- #define stb__arr_addlen(p,s,n) stb__arr_addlen_(p,s,n,__FILE__,__LINE__)
- #define stb__arr_setlen(p,s,n) stb__arr_setlen_(p,s,n,__FILE__,__LINE__)
- #define stb__arr_setsize(p,s,n) stb__arr_setsize_(p,s,n,__FILE__,__LINE__)
- #define stb__arr_deleten(p,s,i,n) stb__arr_deleten_(p,s,i,n,__FILE__,__LINE__)
- #define stb__arr_insertn(p,s,i,n) stb__arr_insertn_(p,s,i,n,__FILE__,__LINE__)
- #define stb__arr_copy(p,s) stb__arr_copy_(p,s,__FILE__,__LINE__)
- #endif
- #endif // STB_INCLUDE_STB_LIB_H
- #ifdef STB_LIB_IMPLEMENTATION
- void stb_arr_malloc(void **target, void *context)
- {
- stb__arr *q = (stb__arr *) malloc(sizeof(*q));
- q->len = q->limit = 0;
- q->signature = stb_arr_signature;
- *target = (void *) (q+1);
- }
- static void * stb__arr_malloc(int size)
- {
- return malloc(size);
- }
- void * stb__arr_copy_(void *p, int elem_size)
- {
- stb__arr *q;
- if (p == NULL) return p;
- q = (stb__arr *) malloc(sizeof(*q) + elem_size * stb_arrhead2(p)->limit);
- stb_arr_check2(p);
- memcpy(q, stb_arrhead2(p), sizeof(*q) + elem_size * stb_arrhead2(p)->len);
- return q+1;
- }
- void stb_arr_free_(void **pp)
- {
- void *p = *pp;
- stb_arr_check2(p);
- if (p) {
- stb__arr *q = stb_arrhead2(p);
- free(q);
- }
- *pp = NULL;
- }
- static void stb__arrsize_(void **pp, int size, int limit, int len)
- {
- void *p = *pp;
- stb__arr *a;
- stb_arr_check2(p);
- if (p == NULL) {
- if (len == 0 && size == 0) return;
- a = (stb__arr *) stb__arr_malloc(sizeof(*a) + size*limit);
- a->limit = limit;
- a->len = len;
- a->signature = stb_arr_signature;
- } else {
- a = stb_arrhead2(p);
- a->len = len;
- if (a->limit < limit) {
- void *p;
- if (a->limit >= 4 && limit < a->limit * 2)
- limit = a->limit * 2;
- p = realloc(a, sizeof(*a) + limit*size);
- if (p) {
- a = (stb__arr *) p;
- a->limit = limit;
- } else {
- // throw an error!
- }
- }
- }
- a->len = a->len < a->limit ? a->len : a->limit;
- *pp = a+1;
- }
- void stb__arr_setsize_(void **pp, int size, int limit)
- {
- void *p = *pp;
- stb_arr_check2(p);
- stb__arrsize_(pp, size, limit, stb_arr_len2(p));
- }
- void stb__arr_setlen_(void **pp, int size, int newlen)
- {
- void *p = *pp;
- stb_arr_check2(p);
- if (stb_arrcurmax2(p) < newlen || p == NULL) {
- stb__arrsize_(pp, size, newlen, newlen);
- } else {
- stb_arrhead2(p)->len = newlen;
- }
- }
- void stb__arr_addlen_(void **p, int size, int addlen)
- {
- stb__arr_setlen_(p, size, stb_arr_len2(*p) + addlen);
- }
- void stb__arr_insertn_(void **pp, int size, int i, int n)
- {
- void *p = *pp;
- if (n) {
- int z;
- if (p == NULL) {
- stb__arr_addlen_(pp, size, n);
- return;
- }
- z = stb_arr_len2(p);
- stb__arr_addlen_(&p, size, n);
- memmove((char *) p + (i+n)*size, (char *) p + i*size, size * (z-i));
- }
- *pp = p;
- }
- void stb__arr_deleten_(void **pp, int size, int i, int n)
- {
- void *p = *pp;
- if (n) {
- memmove((char *) p + i*size, (char *) p + (i+n)*size, size * (stb_arr_len2(p)-(i+n)));
- stb_arrhead2(p)->len -= n;
- }
- *pp = p;
- }
- #endif
- //////////////////////////////////////////////////////////////////////////////
- //
- // Hashing
- //
- // typical use for this is to make a power-of-two hash table.
- //
- // let N = size of table (2^n)
- // let H = stb_hash(str)
- // let S = stb_rehash(H) | 1
- //
- // then hash probe sequence P(i) for i=0..N-1
- // P(i) = (H + S*i) & (N-1)
- //
- // the idea is that H has 32 bits of hash information, but the
- // table has only, say, 2^20 entries so only uses 20 of the bits.
- // then by rehashing the original H we get 2^12 different probe
- // sequences for a given initial probe location. (So it's optimal
- // for 64K tables and its optimality decreases past that.)
- //
- // ok, so I've added something that generates _two separate_
- // 32-bit hashes simultaneously which should scale better to
- // very large tables.
- #ifndef STB_INCLUDE_STB_LIB_H
- STB_EXTERN unsigned int stb_hash(char *str);
- STB_EXTERN unsigned int stb_hashptr(void *p);
- STB_EXTERN unsigned int stb_hashlen(char *str, int len);
- STB_EXTERN unsigned int stb_rehash_improved(unsigned int v);
- STB_EXTERN unsigned int stb_hash_fast(void *p, int len);
- STB_EXTERN unsigned int stb_hash2(char *str, unsigned int *hash2_ptr);
- STB_EXTERN unsigned int stb_hash_number(unsigned int hash);
- #define stb_rehash(x) ((x) + ((x) >> 6) + ((x) >> 19))
- #endif // STB_INCLUDE_STB_LIB_H
- #ifdef STB_LIB_IMPLEMENTATION
- unsigned int stb_hash(char *str)
- {
- unsigned int hash = 0;
- while (*str)
- hash = (hash << 7) + (hash >> 25) + *str++;
- return hash + (hash >> 16);
- }
- unsigned int stb_hashlen(char *str, int len)
- {
- unsigned int hash = 0;
- while (len-- > 0 && *str)
- hash = (hash << 7) + (hash >> 25) + *str++;
- return hash + (hash >> 16);
- }
- unsigned int stb_hashptr(void *p)
- {
- unsigned int x = (unsigned int)(size_t) p;
- // typically lacking in low bits and high bits
- x = stb_rehash(x);
- x += x << 16;
- // pearson's shuffle
- x ^= x << 3;
- x += x >> 5;
- x ^= x << 2;
- x += x >> 15;
- x ^= x << 10;
- return stb_rehash(x);
- }
- unsigned int stb_rehash_improved(unsigned int v)
- {
- return stb_hashptr((void *)(size_t) v);
- }
- unsigned int stb_hash2(char *str, unsigned int *hash2_ptr)
- {
- unsigned int hash1 = 0x3141592c;
- unsigned int hash2 = 0x77f044ed;
- while (*str) {
- hash1 = (hash1 << 7) + (hash1 >> 25) + *str;
- hash2 = (hash2 << 11) + (hash2 >> 21) + *str;
- ++str;
- }
- *hash2_ptr = hash2 + (hash1 >> 16);
- return hash1 + (hash2 >> 16);
- }
- // Paul Hsieh hash
- #define stb__get16_slow(p) ((p)[0] + ((p)[1] << 8))
- #if defined(_MSC_VER)
- #define stb__get16(p) (*((unsigned short *) (p)))
- #else
- #define stb__get16(p) stb__get16_slow(p)
- #endif
- unsigned int stb_hash_fast(void *p, int len)
- {
- unsigned char *q = (unsigned char *) p;
- unsigned int hash = len;
- if (len <= 0 || q == NULL) return 0;
- /* Main loop */
- if (((int)(size_t) q & 1) == 0) {
- for (;len > 3; len -= 4) {
- unsigned int val;
- hash += stb__get16(q);
- val = (stb__get16(q+2) << 11);
- hash = (hash << 16) ^ hash ^ val;
- q += 4;
- hash += hash >> 11;
- }
- } else {
- for (;len > 3; len -= 4) {
- unsigned int val;
- hash += stb__get16_slow(q);
- val = (stb__get16_slow(q+2) << 11);
- hash = (hash << 16) ^ hash ^ val;
- q += 4;
- hash += hash >> 11;
- }
- }
- /* Handle end cases */
- switch (len) {
- case 3: hash += stb__get16_slow(q);
- hash ^= hash << 16;
- hash ^= q[2] << 18;
- hash += hash >> 11;
- break;
- case 2: hash += stb__get16_slow(q);
- hash ^= hash << 11;
- hash += hash >> 17;
- break;
- case 1: hash += q[0];
- hash ^= hash << 10;
- hash += hash >> 1;
- break;
- case 0: break;
- }
- /* Force "avalanching" of final 127 bits */
- hash ^= hash << 3;
- hash += hash >> 5;
- hash ^= hash << 4;
- hash += hash >> 17;
- hash ^= hash << 25;
- hash += hash >> 6;
- return hash;
- }
- unsigned int stb_hash_number(unsigned int hash)
- {
- hash ^= hash << 3;
- hash += hash >> 5;
- hash ^= hash << 4;
- hash += hash >> 17;
- hash ^= hash << 25;
- hash += hash >> 6;
- return hash;
- }
- #endif
- //////////////////////////////////////////////////////////////////////////////
- //
- // Instantiated data structures
- //
- // This is an attempt to implement a templated data structure.
- //
- // Hash table: call stb_define_hash(TYPE,N,KEY,K1,K2,HASH,VALUE)
- // TYPE -- will define a structure type containing the hash table
- // N -- the name, will prefix functions named:
- // N create
- // N destroy
- // N get
- // N set, N add, N update,
- // N remove
- // KEY -- the type of the key. 'x == y' must be valid
- // K1,K2 -- keys never used by the app, used as flags in the hashtable
- // HASH -- a piece of code ending with 'return' that hashes key 'k'
- // VALUE -- the type of the value. 'x = y' must be valid
- //
- // Note that stb_define_hash_base can be used to define more sophisticated
- // hash tables, e.g. those that make copies of the key or use special
- // comparisons (e.g. strcmp).
- #define STB_(prefix,name) stb__##prefix##name
- #define STB__(prefix,name) prefix##name
- #define STB__use(x) x
- #define STB__skip(x)
- #define stb_declare_hash(PREFIX,TYPE,N,KEY,VALUE) \
- typedef struct stb__st_##TYPE TYPE;\
- PREFIX int STB__(N, init)(TYPE *h, int count);\
- PREFIX int STB__(N, memory_usage)(TYPE *h);\
- PREFIX TYPE * STB__(N, create)(void);\
- PREFIX TYPE * STB__(N, copy)(TYPE *h);\
- PREFIX void STB__(N, destroy)(TYPE *h);\
- PREFIX int STB__(N,get_flag)(TYPE *a, KEY k, VALUE *v);\
- PREFIX VALUE STB__(N,get)(TYPE *a, KEY k);\
- PREFIX int STB__(N, set)(TYPE *a, KEY k, VALUE v);\
- PREFIX int STB__(N, add)(TYPE *a, KEY k, VALUE v);\
- PREFIX int STB__(N, update)(TYPE*a,KEY k,VALUE v);\
- PREFIX int STB__(N, remove)(TYPE *a, KEY k, VALUE *v);
- #define STB_nocopy(x) (x)
- #define STB_nodelete(x) 0
- #define STB_nofields
- #define STB_nonullvalue(x)
- #define STB_nullvalue(x) x
- #define STB_safecompare(x) x
- #define STB_nosafe(x)
- #define STB_noprefix
- #ifdef __GNUC__
- #define STB__nogcc(x)
- #else
- #define STB__nogcc(x) x
- #endif
- #define stb_define_hash_base(PREFIX,TYPE,FIELDS,N,NC,LOAD_FACTOR, \
- KEY,EMPTY,DEL,COPY,DISPOSE,SAFE, \
- VCOMPARE,CCOMPARE,HASH, \
- VALUE,HASVNULL,VNULL) \
- \
- typedef struct \
- { \
- KEY k; \
- VALUE v; \
- } STB_(N,_hashpair); \
- \
- STB__nogcc( typedef struct stb__st_##TYPE TYPE; ) \
- struct stb__st_##TYPE { \
- FIELDS \
- STB_(N,_hashpair) *table; \
- unsigned int mask; \
- int count, limit; \
- int deleted; \
- \
- int delete_threshhold; \
- int grow_threshhold; \
- int shrink_threshhold; \
- unsigned char alloced, has_empty, has_del; \
- VALUE ev; VALUE dv; \
- }; \
- \
- static unsigned int STB_(N, hash)(KEY k) \
- { \
- HASH \
- } \
- \
- PREFIX int STB__(N, init)(TYPE *h, int count) \
- { \
- int i; \
- if (count < 4) count = 4; \
- h->limit = count; \
- h->count = 0; \
- h->mask = count-1; \
- h->deleted = 0; \
- h->grow_threshhold = (int) (count * LOAD_FACTOR); \
- h->has_empty = h->has_del = 0; \
- h->alloced = 0; \
- if (count <= 64) \
- h->shrink_threshhold = 0; \
- else \
- h->shrink_threshhold = (int) (count * (LOAD_FACTOR/2.25)); \
- h->delete_threshhold = (int) (count * (1-LOAD_FACTOR)/2); \
- h->table = (STB_(N,_hashpair)*) malloc(sizeof(h->table[0]) * count); \
- if (h->table == NULL) return 0; \
- /* ideally this gets turned into a memset32 automatically */ \
- for (i=0; i < count; ++i) \
- h->table[i].k = EMPTY; \
- return 1; \
- } \
- \
- PREFIX int STB__(N, memory_usage)(TYPE *h) \
- { \
- return sizeof(*h) + h->limit * sizeof(h->table[0]); \
- } \
- \
- PREFIX TYPE * STB__(N, create)(void) \
- { \
- TYPE *h = (TYPE *) malloc(sizeof(*h)); \
- if (h) { \
- if (STB__(N, init)(h, 16)) \
- h->alloced = 1; \
- else { free(h); h=NULL; } \
- } \
- return h; \
- } \
- \
- PREFIX void STB__(N, destroy)(TYPE *a) \
- { \
- int i; \
- for (i=0; i < a->limit; ++i) \
- if (!CCOMPARE(a->table[i].k,EMPTY) && !CCOMPARE(a->table[i].k, DEL)) \
- DISPOSE(a->table[i].k); \
- free(a->table); \
- if (a->alloced) \
- free(a); \
- } \
- \
- static void STB_(N, rehash)(TYPE *a, int count); \
- \
- PREFIX int STB__(N,get_flag)(TYPE *a, KEY k, VALUE *v) \
- { \
- unsigned int h = STB_(N, hash)(k); \
- unsigned int n = h & a->mask, s; \
- if (CCOMPARE(k,EMPTY)){ if (a->has_empty) *v = a->ev; return a->has_empty;}\
- if (CCOMPARE(k,DEL)) { if (a->has_del ) *v = a->dv; return a->has_del; }\
- if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \
- SAFE(if (!CCOMPARE(a->table[n].k,DEL))) \
- if (VCOMPARE(a->table[n].k,k)) { *v = a->table[n].v; return 1; } \
- s = stb_rehash(h) | 1; \
- for(;;) { \
- n = (n + s) & a->mask; \
- if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \
- SAFE(if (CCOMPARE(a->table[n].k,DEL)) continue;) \
- if (VCOMPARE(a->table[n].k,k)) \
- { *v = a->table[n].v; return 1; } \
- } \
- } \
- \
- HASVNULL( \
- PREFIX VALUE STB__(N,get)(TYPE *a, KEY k) \
- { \
- VALUE v; \
- if (STB__(N,get_flag)(a,k,&v)) return v; \
- else return VNULL; \
- } \
- ) \
- \
- PREFIX int STB__(N,getkey)(TYPE *a, KEY k, KEY *kout) \
- { \
- unsigned int h = STB_(N, hash)(k); \
- unsigned int n = h & a->mask, s; \
- if (CCOMPARE(k,EMPTY)||CCOMPARE(k,DEL)) return 0; \
- if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \
- SAFE(if (!CCOMPARE(a->table[n].k,DEL))) \
- if (VCOMPARE(a->table[n].k,k)) { *kout = a->table[n].k; return 1; } \
- s = stb_rehash(h) | 1; \
- for(;;) { \
- n = (n + s) & a->mask; \
- if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \
- SAFE(if (CCOMPARE(a->table[n].k,DEL)) continue;) \
- if (VCOMPARE(a->table[n].k,k)) \
- { *kout = a->table[n].k; return 1; } \
- } \
- } \
- \
- static int STB_(N,addset)(TYPE *a, KEY k, VALUE v, \
- int allow_new, int allow_old, int copy) \
- { \
- unsigned int h = STB_(N, hash)(k); \
- unsigned int n = h & a->mask; \
- int b = -1; \
- if (CCOMPARE(k,EMPTY)) { \
- if (a->has_empty ? allow_old : allow_new) { \
- n=a->has_empty; a->ev = v; a->has_empty = 1; return !n; \
- } else return 0; \
- } \
- if (CCOMPARE(k,DEL)) { \
- if (a->has_del ? allow_old : allow_new) { \
- n=a->has_del; a->dv = v; a->has_del = 1; return !n; \
- } else return 0; \
- } \
- if (!CCOMPARE(a->table[n].k, EMPTY)) { \
- unsigned int s; \
- if (CCOMPARE(a->table[n].k, DEL)) \
- b = n; \
- else if (VCOMPARE(a->table[n].k,k)) { \
- if (allow_old) \
- a->table[n].v = v; \
- return !allow_new; \
- } \
- s = stb_rehash(h) | 1; \
- for(;;) { \
- n = (n + s) & a->mask; \
- if (CCOMPARE(a->table[n].k, EMPTY)) break; \
- if (CCOMPARE(a->table[n].k, DEL)) { \
- if (b < 0) b = n; \
- } else if (VCOMPARE(a->table[n].k,k)) { \
- if (allow_old) \
- a->table[n].v = v; \
- return !allow_new; \
- } \
- } \
- } \
- if (!allow_new) return 0; \
- if (b < 0) b = n; else --a->deleted; \
- a->table[b].k = copy ? COPY(k) : k; \
- a->table[b].v = v; \
- ++a->count; \
- if (a->count > a->grow_threshhold) \
- STB_(N,rehash)(a, a->limit*2); \
- return 1; \
- } \
- \
- PREFIX int STB__(N, set)(TYPE *a, KEY k, VALUE v){return STB_(N,addset)(a,k,v,1,1,1);}\
- PREFIX int STB__(N, add)(TYPE *a, KEY k, VALUE v){return STB_(N,addset)(a,k,v,1,0,1);}\
- PREFIX int STB__(N, update)(TYPE*a,KEY k,VALUE v){return STB_(N,addset)(a,k,v,0,1,1);}\
- \
- PREFIX int STB__(N, remove)(TYPE *a, KEY k, VALUE *v) \
- { \
- unsigned int h = STB_(N, hash)(k); \
- unsigned int n = h & a->mask, s; \
- if (CCOMPARE(k,EMPTY)) { if (a->has_empty) { if(v)*v = a->ev; a->has_empty=0; return 1; } return 0; } \
- if (CCOMPARE(k,DEL)) { if (a->has_del ) { if(v)*v = a->dv; a->has_del =0; return 1; } return 0; } \
- if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \
- if (SAFE(CCOMPARE(a->table[n].k,DEL) || ) !VCOMPARE(a->table[n].k,k)) { \
- s = stb_rehash(h) | 1; \
- for(;;) { \
- n = (n + s) & a->mask; \
- if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \
- SAFE(if (CCOMPARE(a->table[n].k, DEL)) continue;) \
- if (VCOMPARE(a->table[n].k,k)) break; \
- } \
- } \
- DISPOSE(a->table[n].k); \
- a->table[n].k = DEL; \
- --a->count; \
- ++a->deleted; \
- if (v != NULL) \
- *v = a->table[n].v; \
- if (a->count < a->shrink_threshhold) \
- STB_(N, rehash)(a, a->limit >> 1); \
- else if (a->deleted > a->delete_threshhold) \
- STB_(N, rehash)(a, a->limit); \
- return 1; \
- } \
- \
- PREFIX TYPE * STB__(NC, copy)(TYPE *a) \
- { \
- int i; \
- TYPE *h = (TYPE *) malloc(sizeof(*h)); \
- if (!h) return NULL; \
- if (!STB__(N, init)(h, a->limit)) { free(h); return NULL; } \
- h->count = a->count; \
- h->deleted = a->deleted; \
- h->alloced = 1; \
- h->ev = a->ev; h->dv = a->dv; \
- h->has_empty = a->has_empty; h->has_del = a->has_del; \
- memcpy(h->table, a->table, h->limit * sizeof(h->table[0])); \
- for (i=0; i < a->limit; ++i) \
- if (!CCOMPARE(h->table[i].k,EMPTY) && !CCOMPARE(h->table[i].k,DEL)) \
- h->table[i].k = COPY(h->table[i].k); \
- return h; \
- } \
- \
- static void STB_(N, rehash)(TYPE *a, int count) \
- { \
- int i; \
- TYPE b; \
- STB__(N, init)(&b, count); \
- for (i=0; i < a->limit; ++i) \
- if (!CCOMPARE(a->table[i].k,EMPTY) && !CCOMPARE(a->table[i].k,DEL)) \
- STB_(N,addset)(&b, a->table[i].k, a->table[i].v,1,1,0); \
- free(a->table); \
- a->table = b.table; \
- a->mask = b.mask; \
- a->count = b.count; \
- a->limit = b.limit; \
- a->deleted = b.deleted; \
- a->delete_threshhold = b.delete_threshhold; \
- a->grow_threshhold = b.grow_threshhold; \
- a->shrink_threshhold = b.shrink_threshhold; \
- }
- #define STB_equal(a,b) ((a) == (b))
- #define stb_define_hash(TYPE,N,KEY,EMPTY,DEL,HASH,VALUE) \
- stb_define_hash_base(STB_noprefix, TYPE,STB_nofields,N,NC,0.85f, \
- KEY,EMPTY,DEL,STB_nocopy,STB_nodelete,STB_nosafe, \
- STB_equal,STB_equal,HASH, \
- VALUE,STB_nonullvalue,0)
- #define stb_define_hash_vnull(TYPE,N,KEY,EMPTY,DEL,HASH,VALUE,VNULL) \
- stb_define_hash_base(STB_noprefix, TYPE,STB_nofields,N,NC,0.85f, \
- KEY,EMPTY,DEL,STB_nocopy,STB_nodelete,STB_nosafe, \
- STB_equal,STB_equal,HASH, \
- VALUE,STB_nullvalue,VNULL)
- //////////////////////////////////////////////////////////////////////////////
- //
- // stb_ptrmap
- //
- // An stb_ptrmap data structure is an O(1) hash table between pointers. One
- // application is to let you store "extra" data associated with pointers,
- // which is why it was originally called stb_extra.
- #ifndef STB_INCLUDE_STB_LIB_H
- stb_declare_hash(STB_EXTERN, stb_ptrmap, stb_ptrmap_, void *, void *)
- stb_declare_hash(STB_EXTERN, stb_idict, stb_idict_, stb_int32, stb_int32)
- STB_EXTERN void stb_ptrmap_delete(stb_ptrmap *e, void (*free_func)(void *));
- STB_EXTERN stb_ptrmap *stb_ptrmap_new(void);
- STB_EXTERN stb_idict * stb_idict_new_size(unsigned int size);
- STB_EXTERN void stb_idict_remove_all(stb_idict *e);
- #endif // STB_INCLUDE_STB_LIB_H
- #ifdef STB_LIB_IMPLEMENTATION
- #define STB_EMPTY ((void *) 2)
- #define STB_EDEL ((void *) 6)
- stb_define_hash_base(STB_noprefix,stb_ptrmap, STB_nofields, stb_ptrmap_,stb_ptrmap_,0.85f,
- void *,STB_EMPTY,STB_EDEL,STB_nocopy,STB_nodelete,STB_nosafe,
- STB_equal,STB_equal,return stb_hashptr(k);,
- void *,STB_nullvalue,NULL)
- stb_ptrmap *stb_ptrmap_new(void)
- {
- return stb_ptrmap_create();
- }
- void stb_ptrmap_delete(stb_ptrmap *e, void (*free_func)(void *))
- {
- int i;
- if (free_func)
- for (i=0; i < e->limit; ++i)
- if (e->table[i].k != STB_EMPTY && e->table[i].k != STB_EDEL) {
- if (free_func == free)
- free(e->table[i].v); // allow STB_MALLOC_WRAPPER to operate
- else
- free_func(e->table[i].v);
- }
- stb_ptrmap_destroy(e);
- }
- // extra fields needed for stua_dict
- #define STB_IEMPTY ((int) 1)
- #define STB_IDEL ((int) 3)
- stb_define_hash_base(STB_noprefix, stb_idict, STB_nofields, stb_idict_,stb_idict_,0.85f,
- stb_int32,STB_IEMPTY,STB_IDEL,STB_nocopy,STB_nodelete,STB_nosafe,
- STB_equal,STB_equal,
- return stb_rehash_improved(k);,stb_int32,STB_nonullvalue,0)
- stb_idict * stb_idict_new_size(unsigned int size)
- {
- stb_idict *e = (stb_idict *) malloc(sizeof(*e));
- if (e) {
- // round up to power of 2
- while ((size & (size-1)) != 0) // while more than 1 bit is set
- size += (size & ~(size-1)); // add the lowest set bit
- stb_idict_init(e, size);
- e->alloced = 1;
- }
- return e;
- }
- void stb_idict_remove_all(stb_idict *e)
- {
- int n;
- for (n=0; n < e->limit; ++n)
- e->table[n].k = STB_IEMPTY;
- e->has_empty = e->has_del = 0;
- }
- #endif
- //////////////////////////////////////////////////////////////////////////////
- //
- // SDICT: Hash Table for Strings (symbol table)
- //
- // if "use_arena=1", then strings will be copied
- // into blocks and never freed until the sdict is freed;
- // otherwise they're malloc()ed and free()d on the fly.
- // (specify use_arena=1 if you never stb_sdict_remove)
- #ifndef STB_INCLUDE_STB_LIB_H
- stb_declare_hash(STB_EXTERN, stb_sdict, stb_sdict_, char *, void *)
- STB_EXTERN stb_sdict * stb_sdict_new(void);
- STB_EXTERN stb_sdict * stb_sdict_copy(stb_sdict*);
- STB_EXTERN void stb_sdict_delete(stb_sdict *);
- STB_EXTERN void * stb_sdict_change(stb_sdict *, char *str, void *p);
- STB_EXTERN int stb_sdict_count(stb_sdict *d);
- STB_EXTERN int stb_sdict_internal_limit(stb_sdict *d);
- STB_EXTERN char * stb_sdict_internal_key(stb_sdict *d, int n);
- STB_EXTERN void * stb_sdict_internal_value(stb_sdict *d, int n);
- #define stb_sdict_for(d,i,q,z) \
- for(i=0; i < stb_sdict_internal_limit(d) ? (q=stb_sdict_internal_key(d,i),z=stb_sdict_internal_value(d,i),1) : 0; ++i) \
- if (q==NULL||q==(void *) 1);else // reversed makes macro friendly
- #endif // STB_INCLUDE_STB_LIB_H
- #ifdef STB_LIB_IMPLEMENTATION
- // if in same translation unit, for speed, don't call accessors
- #undef stb_sdict_for
- #define stb_sdict_for(d,i,q,z) \
- for(i=0; i < (d)->limit ? (q=(d)->table[i].k,z=(d)->table[i].v,1) : 0; ++i) \
- if (q==NULL||q==(void *) 1);else // reversed makes macro friendly
- //#define STB_DEL ((void *) 1)
- #define STB_SDEL ((char *) 1)
- stb_define_hash_base(STB_noprefix, stb_sdict, STB_nofields, stb_sdict_,stb_sdictinternal_, 0.85f,
- char *, NULL, STB_SDEL, strdup, free,
- STB_safecompare, !strcmp, STB_equal, return stb_hash(k);,
- void *, STB_nullvalue, NULL)
- int stb_sdict_count(stb_sdict *a)
- {
- return a->count;
- }
- int stb_sdict_internal_limit(stb_sdict *a)
- {
- return a->limit;
- }
- char* stb_sdict_internal_key(stb_sdict *a, int n)
- {
- return a->table[n].k;
- }
- void* stb_sdict_internal_value(stb_sdict *a, int n)
- {
- return a->table[n].v;
- }
- stb_sdict * stb_sdict_new(void)
- {
- stb_sdict *d = stb_sdict_create();
- if (d == NULL) return NULL;
- return d;
- }
- stb_sdict* stb_sdict_copy(stb_sdict *old)
- {
- return stb_sdictinternal_copy(old);
- }
- void stb_sdict_delete(stb_sdict *d)
- {
- stb_sdict_destroy(d);
- }
- void * stb_sdict_change(stb_sdict *d, char *str, void *p)
- {
- void *q = stb_sdict_get(d, str);
- stb_sdict_set(d, str, p);
- return q;
- }
- #endif
- //////////////////////////////////////////////////////////////////////////////
- //
- // File Processing
- //
- #ifndef STB_INCLUDE_STB_LIB_H
- #ifdef _MSC_VER
- #define stb_rename(x,y) _wrename((const wchar_t *)stb__from_utf8(x), (const wchar_t *)stb__from_utf8_alt(y))
- #define stb_mktemp _mktemp
- #else
- #define stb_mktemp mktemp
- #define stb_rename rename
- #endif
- #define stb_filec (char *) stb_file
- #define stb_fileu (unsigned char *) stb_file
- STB_EXTERN void * stb_file(char *filename, size_t *length);
- STB_EXTERN size_t stb_filelen(FILE *f);
- STB_EXTERN int stb_filewrite(char *filename, void *data, size_t length);
- STB_EXTERN int stb_filewritestr(char *filename, char *data);
- STB_EXTERN char ** stb_stringfile(char *filename, int *len);
- STB_EXTERN char * stb_fgets(char *buffer, int buflen, FILE *f);
- STB_EXTERN char * stb_fgets_malloc(FILE *f);
- STB_EXTERN int stb_fexists(char *filename);
- STB_EXTERN int stb_fcmp(char *s1, char *s2);
- STB_EXTERN int stb_feq(char *s1, char *s2);
- STB_EXTERN time_t stb_ftimestamp(char *filename);
- STB_EXTERN int stb_fullpath(char *abs, int abs_size, char *rel);
- STB_EXTERN int stb_copyfile(char *src, char *dest);
- STB_EXTERN int stb_fread(void *data, size_t len, size_t count, void *f);
- STB_EXTERN int stb_fwrite(void *data, size_t len, size_t count, void *f);
- #endif // STB_INCLUDE_STB_LIB_H
- #ifdef STB_LIB_IMPLEMENTATION
- #if defined(_MSC_VER) || defined(__MINGW32__)
- #define stb__stat _stat
- #else
- #define stb__stat stat
- #endif
- int stb_fexists(char *filename)
- {
- struct stb__stat buf;
- return stb__windows(
- _wstat((const wchar_t *)stb__from_utf8(filename), &buf),
- stat(filename,&buf)
- ) == 0;
- }
- time_t stb_ftimestamp(char *filename)
- {
- struct stb__stat buf;
- if (stb__windows(
- _wstat((const wchar_t *)stb__from_utf8(filename), &buf),
- stat(filename,&buf)
- ) == 0)
- {
- return buf.st_mtime;
- } else {
- return 0;
- }
- }
- size_t stb_filelen(FILE *f)
- {
- size_t len, pos;
- pos = ftell(f);
- fseek(f, 0, SEEK_END);
- len = ftell(f);
- fseek(f, pos, SEEK_SET);
- return len;
- }
- void *stb_file(char *filename, size_t *length)
- {
- FILE *f = stb__fopen(filename, "rb");
- char *buffer;
- size_t len, len2;
- if (!f) return NULL;
- len = stb_filelen(f);
- buffer = (char *) malloc(len+2); // nul + extra
- len2 = fread(buffer, 1, len, f);
- if (len2 == len) {
- if (length) *length = len;
- buffer[len] = 0;
- } else {
- free(buffer);
- buffer = NULL;
- }
- fclose(f);
- return buffer;
- }
- int stb_filewrite(char *filename, void *data, size_t length)
- {
- FILE *f = stb__fopen(filename, "wb");
- if (f) {
- unsigned char *data_ptr = (unsigned char *) data;
- size_t remaining = length;
- while (remaining > 0) {
- size_t len2 = remaining > 65536 ? 65536 : remaining;
- size_t len3 = fwrite(data_ptr, 1, len2, f);
- if (len2 != len3) {
- fprintf(stderr, "Failed while writing %s\n", filename);
- break;
- }
- remaining -= len2;
- data_ptr += len2;
- }
- fclose(f);
- }
- return f != NULL;
- }
- int stb_filewritestr(char *filename, char *data)
- {
- return stb_filewrite(filename, data, strlen(data));
- }
- char ** stb_stringfile(char *filename, int *plen)
- {
- FILE *f = stb__fopen(filename, "rb");
- char *buffer, **list=NULL, *s;
- size_t len, count, i;
- if (!f) return NULL;
- len = stb_filelen(f);
- buffer = (char *) malloc(len+1);
- len = fread(buffer, 1, len, f);
- buffer[len] = 0;
- fclose(f);
- // two passes through: first time count lines, second time set them
- for (i=0; i < 2; ++i) {
- s = buffer;
- if (i == 1)
- list[0] = s;
- count = 1;
- while (*s) {
- if (*s == '\n' || *s == '\r') {
- // detect if both cr & lf are together
- int crlf = (s[0] + s[1]) == ('\n' + '\r');
- if (i == 1) *s = 0;
- if (crlf) ++s;
- if (s[1]) { // it's not over yet
- if (i == 1) list[count] = s+1;
- ++count;
- }
- }
- ++s;
- }
- if (i == 0) {
- list = (char **) malloc(sizeof(*list) * (count+1) + len+1);
- if (!list) return NULL;
- list[count] = 0;
- // recopy the file so there's just a single allocation to free
- memcpy(&list[count+1], buffer, len+1);
- free(buffer);
- buffer = (char *) &list[count+1];
- if (plen) *plen = count;
- }
- }
- return list;
- }
- char * stb_fgets(char *buffer, int buflen, FILE *f)
- {
- char *p;
- buffer[0] = 0;
- p = fgets(buffer, buflen, f);
- if (p) {
- int n = strlen(p)-1;
- if (n >= 0)
- if (p[n] == '\n')
- p[n] = 0;
- }
- return p;
- }
- char * stb_fgets_malloc(FILE *f)
- {
- // avoid reallocing for small strings
- char quick_buffer[800];
- quick_buffer[sizeof(quick_buffer)-2] = 0;
- if (!fgets(quick_buffer, sizeof(quick_buffer), f))
- return NULL;
- if (quick_buffer[sizeof(quick_buffer)-2] == 0) {
- int n = strlen(quick_buffer);
- if (n > 0 && quick_buffer[n-1] == '\n')
- quick_buffer[n-1] = 0;
- return strdup(quick_buffer);
- } else {
- char *p;
- char *a = strdup(quick_buffer);
- int len = sizeof(quick_buffer)-1;
- while (!feof(f)) {
- if (a[len-1] == '\n') break;
- a = (char *) realloc(a, len*2);
- p = &a[len];
- p[len-2] = 0;
- if (!fgets(p, len, f))
- break;
- if (p[len-2] == 0) {
- len += strlen(p);
- break;
- }
- len = len + (len-1);
- }
- if (a[len-1] == '\n')
- a[len-1] = 0;
- return a;
- }
- }
- int stb_fullpath(char *abs, int abs_size, char *rel)
- {
- #ifdef _MSC_VER
- return _fullpath(abs, rel, abs_size) != NULL;
- #else
- if (rel[0] == '/' || rel[0] == '~') {
- if ((int) strlen(rel) >= abs_size)
- return 0;
- strcpy(abs,rel);
- return 1;
- } else {
- int n;
- getcwd(abs, abs_size);
- n = strlen(abs);
- if (n+(int) strlen(rel)+2 <= abs_size) {
- abs[n] = '/';
- strcpy(abs+n+1, rel);
- return 1;
- } else {
- return 0;
- }
- }
- #endif
- }
- static int stb_fcmp_core(FILE *f, FILE *g)
- {
- char buf1[1024],buf2[1024];
- int n1,n2, res=0;
- while (1) {
- n1 = fread(buf1, 1, sizeof(buf1), f);
- n2 = fread(buf2, 1, sizeof(buf2), g);
- res = memcmp(buf1,buf2,n1 < n2 ? n1 : n2);
- if (res)
- break;
- if (n1 != n2) {
- res = n1 < n2 ? -1 : 1;
- break;
- }
- if (n1 == 0)
- break;
- }
- fclose(f);
- fclose(g);
- return res;
- }
- int stb_fcmp(char *s1, char *s2)
- {
- FILE *f = stb__fopen(s1, "rb");
- FILE *g = stb__fopen(s2, "rb");
- if (f == NULL || g == NULL) {
- if (f) fclose(f);
- if (g) {
- fclose(g);
- return 1;
- }
- return f != NULL;
- }
- return stb_fcmp_core(f,g);
- }
- int stb_feq(char *s1, char *s2)
- {
- FILE *f = stb__fopen(s1, "rb");
- FILE *g = stb__fopen(s2, "rb");
- if (f == NULL || g == NULL) {
- if (f) fclose(f);
- if (g) fclose(g);
- return f == g;
- }
- // feq is faster because it shortcuts if they're different length
- if (stb_filelen(f) != stb_filelen(g)) {
- fclose(f);
- fclose(g);
- return 0;
- }
- return !stb_fcmp_core(f,g);
- }
- int stb_copyfile(char *src, char *dest)
- {
- char raw_buffer[1024];
- char *buffer;
- int buf_size = 65536;
- FILE *f, *g;
- // if file already exists at destination, do nothing
- if (stb_feq(src, dest)) return 1;
- // open file
- f = stb__fopen(src, "rb");
- if (f == NULL) return 0;
- // open file for writing
- g = stb__fopen(dest, "wb");
- if (g == NULL) {
- fclose(f);
- return 0;
- }
- buffer = (char *) malloc(buf_size);
- if (buffer == NULL) {
- buffer = raw_buffer;
- buf_size = sizeof(raw_buffer);
- }
- while (!feof(f)) {
- int n = fread(buffer, 1, buf_size, f);
- if (n != 0)
- fwrite(buffer, 1, n, g);
- }
- fclose(f);
- if (buffer != raw_buffer)
- free(buffer);
- fclose(g);
- return 1;
- }
- #define stb_fgetc(f) ((unsigned char) fgetc(f))
- #if 0
- // strip the trailing '/' or '\\' from a directory so we can refer to it
- // as a file for _stat()
- char *stb_strip_final_slash(char *t)
- {
- if (t[0]) {
- char *z = t + strlen(t) - 1;
- // *z is the last character
- if (*z == '\\' || *z == '/')
- if (z != t+2 || t[1] != ':') // but don't strip it if it's e.g. "c:/"
- *z = 0;
- if (*z == '\\')
- *z = '/'; // canonicalize to make sure it matches db
- }
- return t;
- }
- char *stb_strip_final_slash_regardless(char *t)
- {
- if (t[0]) {
- char *z = t + strlen(t) - 1;
- // *z is the last character
- if (*z == '\\' || *z == '/')
- *z = 0;
- if (*z == '\\')
- *z = '/'; // canonicalize to make sure it matches db
- }
- return t;
- }
- #endif
- #endif
- //////////////////////////////////////////////////////////////////////////////
- //
- // Portable directory reading
- //
- #ifndef STB_INCLUDE_STB_LIB_H
- STB_EXTERN char **stb_readdir_files (char *dir);
- STB_EXTERN char **stb_readdir_files_mask(char *dir, char *wild);
- STB_EXTERN char **stb_readdir_subdirs(char *dir);
- STB_EXTERN char **stb_readdir_subdirs_mask(char *dir, char *wild);
- STB_EXTERN void stb_readdir_free (char **files);
- STB_EXTERN char **stb_readdir_recursive(char *dir, char *filespec);
- STB_EXTERN void stb_delete_directory_recursive(char *dir);
- // forward declare for implementation
- STB_EXTERN int stb_wildmatchi(char *expr, char *candidate);
- #endif // STB_INCLUDE_STB_LIB_H
- #ifdef STB_LIB_IMPLEMENTATION
- #ifdef _MSC_VER
- #include <io.h>
- #else
- #include <unistd.h>
- #include <dirent.h>
- #endif
- void stb_readdir_free(char **files)
- {
- char **f2 = files;
- int i;
- for (i=0; i < stb_arr_len(f2); ++i)
- free(f2[i]);
- stb_arr_free(f2);
- }
- static int isdotdirname(char *name)
- {
- if (name[0] == '.')
- return (name[1] == '.') ? !name[2] : !name[1];
- return 0;
- }
- static char **readdir_raw(char *dir, int return_subdirs, char *mask)
- {
- char **results = NULL;
- char buffer[4096], with_slash[4096];
- size_t n;
- #ifdef _MSC_VER
- stb__wchar *ws;
- struct _wfinddata_t data;
- #ifdef _WIN64
- const intptr_t none = -1;
- intptr_t z;
- #else
- const long none = -1;
- long z;
- #endif
- #else // !_MSC_VER
- const DIR *none = NULL;
- DIR *z;
- #endif
- n = stb_strscpy(buffer,dir,sizeof(buffer));
- if (!n || n >= sizeof(buffer))
- return NULL;
- stb_fixpath(buffer);
- n--;
- if (n > 0 && (buffer[n-1] != '/')) {
- buffer[n++] = '/';
- }
- buffer[n] = 0;
- if (!stb_strscpy(with_slash,buffer,sizeof(with_slash)))
- return NULL;
- #ifdef _MSC_VER
- if (!stb_strscpy(buffer+n,"*.*",sizeof(buffer)-n))
- return NULL;
- ws = stb__from_utf8(buffer);
- z = _wfindfirst((const wchar_t *)ws, &data);
- #else
- z = opendir(dir);
- #endif
- if (z != none) {
- int nonempty = 1;
- #ifndef _MSC_VER
- struct dirent *data = readdir(z);
- nonempty = (data != NULL);
- #endif
- if (nonempty) {
- do {
- int is_subdir;
- #ifdef _MSC_VER
- char *name = stb__to_utf8((stb__wchar *)data.name);
- if (name == NULL) {
- fprintf(stderr, "%s to convert '%S' to %s!\n", "Unable", data.name, "utf8");
- continue;
- }
- is_subdir = !!(data.attrib & _A_SUBDIR);
- #else
- char *name = data->d_name;
- if (!stb_strscpy(buffer+n,name,sizeof(buffer)-n))
- break;
- // Could follow DT_LNK, but would need to check for recursive links.
- is_subdir = !!(data->d_type & DT_DIR);
- #endif
- if (is_subdir == return_subdirs) {
- if (!is_subdir || !isdotdirname(name)) {
- if (!mask || stb_wildmatchi(mask, name)) {
- char buffer[4096],*p=buffer;
- if ( stb_snprintf(buffer, sizeof(buffer), "%s%s", with_slash, name) < 0 )
- break;
- if (buffer[0] == '.' && buffer[1] == '/')
- p = buffer+2;
- stb_arr_push(results, strdup(p));
- }
- }
- }
- }
- #ifdef _MSC_VER
- while (0 == _wfindnext(z, &data));
- #else
- while ((data = readdir(z)) != NULL);
- #endif
- }
- #ifdef _MSC_VER
- _findclose(z);
- #else
- closedir(z);
- #endif
- }
- return results;
- }
- char **stb_readdir_files (char *dir) { return readdir_raw(dir, 0, NULL); }
- char **stb_readdir_subdirs(char *dir) { return readdir_raw(dir, 1, NULL); }
- char **stb_readdir_files_mask(char *dir, char *wild) { return readdir_raw(dir, 0, wild); }
- char **stb_readdir_subdirs_mask(char *dir, char *wild) { return readdir_raw(dir, 1, wild); }
- int stb__rec_max=0x7fffffff;
- static char **stb_readdir_rec(char **sofar, char *dir, char *filespec)
- {
- char **files;
- char ** dirs;
- char **p;
- if (stb_arr_len(sofar) >= stb__rec_max) return sofar;
- files = stb_readdir_files_mask(dir, filespec);
- stb_arr_for(p, files) {
- stb_arr_push(sofar, strdup(*p));
- if (stb_arr_len(sofar) >= stb__rec_max) break;
- }
- stb_readdir_free(files);
- if (stb_arr_len(sofar) >= stb__rec_max) return sofar;
- dirs = stb_readdir_subdirs(dir);
- stb_arr_for(p, dirs)
- sofar = stb_readdir_rec(sofar, *p, filespec);
- stb_readdir_free(dirs);
- return sofar;
- }
- char **stb_readdir_recursive(char *dir, char *filespec)
- {
- return stb_readdir_rec(NULL, dir, filespec);
- }
- void stb_delete_directory_recursive(char *dir)
- {
- char **list = stb_readdir_subdirs(dir);
- int i;
- for (i=0; i < stb_arr_len(list); ++i)
- stb_delete_directory_recursive(list[i]);
- stb_arr_free(list);
- list = stb_readdir_files(dir);
- for (i=0; i < stb_arr_len(list); ++i)
- if (!remove(list[i])) {
- // on windows, try again after making it writeable; don't ALWAYS
- // do this first since that would be slow in the normal case
- #ifdef _MSC_VER
- _chmod(list[i], _S_IWRITE);
- remove(list[i]);
- #endif
- }
- stb_arr_free(list);
- stb__windows(_rmdir,rmdir)(dir);
- }
- #endif
- //////////////////////////////////////////////////////////////////////////////
- //
- // Checksums: CRC-32, ADLER32, SHA-1
- //
- // CRC-32 and ADLER32 allow streaming blocks
- // SHA-1 requires either a complete buffer, max size 2^32 - 73
- // or it can checksum directly from a file, max 2^61
- #ifndef STB_INCLUDE_STB_LIB_H
- #define STB_ADLER32_SEED 1
- #define STB_CRC32_SEED 0 // note that we logical NOT this in the code
- STB_EXTERN stb_uint stb_adler32 (stb_uint adler32, stb_uchar *buffer, stb_uint buflen);
- STB_EXTERN stb_uint stb_crc32_block(stb_uint crc32 , stb_uchar *buffer, stb_uint buflen);
- STB_EXTERN stb_uint stb_crc32 ( stb_uchar *buffer, stb_uint buflen);
- STB_EXTERN void stb_sha1( unsigned char output[20], stb_uchar *buffer, unsigned int len);
- STB_EXTERN int stb_sha1_file(unsigned char output[20], char *file);
- #endif // STB_INCLUDE_STB_LIB_H
- #ifdef STB_LIB_IMPLEMENTATION
- stb_uint stb_crc32_block(stb_uint crc, unsigned char *buffer, stb_uint len)
- {
- static stb_uint crc_table[256];
- stb_uint i,j,s;
- crc = ~crc;
- if (crc_table[1] == 0)
- for(i=0; i < 256; i++) {
- for (s=i, j=0; j < 8; ++j)
- s = (s >> 1) ^ (s & 1 ? 0xedb88320 : 0);
- crc_table[i] = s;
- }
- for (i=0; i < len; ++i)
- crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
- return ~crc;
- }
- stb_uint stb_crc32(unsigned char *buffer, stb_uint len)
- {
- return stb_crc32_block(0, buffer, len);
- }
- stb_uint stb_adler32(stb_uint adler32, stb_uchar *buffer, stb_uint buflen)
- {
- const unsigned long ADLER_MOD = 65521;
- unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16;
- unsigned long blocklen, i;
- blocklen = buflen % 5552;
- while (buflen) {
- for (i=0; i + 7 < blocklen; i += 8) {
- s1 += buffer[0], s2 += s1;
- s1 += buffer[1], s2 += s1;
- s1 += buffer[2], s2 += s1;
- s1 += buffer[3], s2 += s1;
- s1 += buffer[4], s2 += s1;
- s1 += buffer[5], s2 += s1;
- s1 += buffer[6], s2 += s1;
- s1 += buffer[7], s2 += s1;
- buffer += 8;
- }
- for (; i < blocklen; ++i)
- s1 += *buffer++, s2 += s1;
- s1 %= ADLER_MOD, s2 %= ADLER_MOD;
- buflen -= blocklen;
- blocklen = 5552;
- }
- return (s2 << 16) + s1;
- }
- #define stb__big32(c) (((c)[0]<<24) + (c)[1]*65536 + (c)[2]*256 + (c)[3])
- static void stb__sha1(stb_uchar *chunk, stb_uint h[5])
- {
- int i;
- stb_uint a,b,c,d,e;
- stb_uint w[80];
- for (i=0; i < 16; ++i)
- w[i] = stb__big32(&chunk[i*4]);
- for (i=16; i < 80; ++i) {
- stb_uint t;
- t = w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16];
- w[i] = (t + t) | (t >> 31);
- }
- a = h[0];
- b = h[1];
- c = h[2];
- d = h[3];
- e = h[4];
- #define STB__SHA1(k,f) \
- { \
- stb_uint temp = (a << 5) + (a >> 27) + (f) + e + (k) + w[i]; \
- e = d; \
- d = c; \
- c = (b << 30) + (b >> 2); \
- b = a; \
- a = temp; \
- }
- i=0;
- for (; i < 20; ++i) STB__SHA1(0x5a827999, d ^ (b & (c ^ d)) );
- for (; i < 40; ++i) STB__SHA1(0x6ed9eba1, b ^ c ^ d );
- for (; i < 60; ++i) STB__SHA1(0x8f1bbcdc, (b & c) + (d & (b ^ c)) );
- for (; i < 80; ++i) STB__SHA1(0xca62c1d6, b ^ c ^ d );
- #undef STB__SHA1
- h[0] += a;
- h[1] += b;
- h[2] += c;
- h[3] += d;
- h[4] += e;
- }
- void stb_sha1(stb_uchar output[20], stb_uchar *buffer, stb_uint len)
- {
- unsigned char final_block[128];
- stb_uint end_start, final_len, j;
- int i;
- stb_uint h[5];
- h[0] = 0x67452301;
- h[1] = 0xefcdab89;
- h[2] = 0x98badcfe;
- h[3] = 0x10325476;
- h[4] = 0xc3d2e1f0;
- // we need to write padding to the last one or two
- // blocks, so build those first into 'final_block'
- // we have to write one special byte, plus the 8-byte length
- // compute the block where the data runs out
- end_start = len & ~63;
- // compute the earliest we can encode the length
- if (((len+9) & ~63) == end_start) {
- // it all fits in one block, so fill a second-to-last block
- end_start -= 64;
- }
- final_len = end_start + 128;
- // now we need to copy the data in
- assert(end_start + 128 >= len+9);
- assert(end_start < len || len < 64-9);
- j = 0;
- if (end_start > len)
- j = (stb_uint) - (int) end_start;
- for (; end_start + j < len; ++j)
- final_block[j] = buffer[end_start + j];
- final_block[j++] = 0x80;
- while (j < 128-5) // 5 byte length, so write 4 extra padding bytes
- final_block[j++] = 0;
- // big-endian size
- final_block[j++] = len >> 29;
- final_block[j++] = len >> 21;
- final_block[j++] = len >> 13;
- final_block[j++] = len >> 5;
- final_block[j++] = len << 3;
- assert(j == 128 && end_start + j == final_len);
- for (j=0; j < final_len; j += 64) { // 512-bit chunks
- if (j+64 >= end_start+64)
- stb__sha1(&final_block[j - end_start], h);
- else
- stb__sha1(&buffer[j], h);
- }
- for (i=0; i < 5; ++i) {
- output[i*4 + 0] = h[i] >> 24;
- output[i*4 + 1] = h[i] >> 16;
- output[i*4 + 2] = h[i] >> 8;
- output[i*4 + 3] = h[i] >> 0;
- }
- }
- int stb_sha1_file(stb_uchar output[20], char *file)
- {
- int i;
- stb_uint64 length=0;
- unsigned char buffer[128];
- FILE *f = stb__fopen(file, "rb");
- stb_uint h[5];
- if (f == NULL) return 0; // file not found
- h[0] = 0x67452301;
- h[1] = 0xefcdab89;
- h[2] = 0x98badcfe;
- h[3] = 0x10325476;
- h[4] = 0xc3d2e1f0;
- for(;;) {
- int n = fread(buffer, 1, 64, f);
- if (n == 64) {
- stb__sha1(buffer, h);
- length += n;
- } else {
- int block = 64;
- length += n;
- buffer[n++] = 0x80;
- // if there isn't enough room for the length, double the block
- if (n + 8 > 64)
- block = 128;
- // pad to end
- memset(buffer+n, 0, block-8-n);
- i = block - 8;
- buffer[i++] = (stb_uchar) (length >> 53);
- buffer[i++] = (stb_uchar) (length >> 45);
- buffer[i++] = (stb_uchar) (length >> 37);
- buffer[i++] = (stb_uchar) (length >> 29);
- buffer[i++] = (stb_uchar) (length >> 21);
- buffer[i++] = (stb_uchar) (length >> 13);
- buffer[i++] = (stb_uchar) (length >> 5);
- buffer[i++] = (stb_uchar) (length << 3);
- assert(i == block);
- stb__sha1(buffer, h);
- if (block == 128)
- stb__sha1(buffer+64, h);
- else
- assert(block == 64);
- break;
- }
- }
- fclose(f);
- for (i=0; i < 5; ++i) {
- output[i*4 + 0] = h[i] >> 24;
- output[i*4 + 1] = h[i] >> 16;
- output[i*4 + 2] = h[i] >> 8;
- output[i*4 + 3] = h[i] >> 0;
- }
- return 1;
- }
- #endif // STB_LIB_IMPLEMENTATION
- //////////////////////////////////////////////////////////////////////////////
- //
- // Random Numbers via Meresenne Twister or LCG
- //
- #ifndef STB_INCLUDE_STB_LIB_H
- STB_EXTERN unsigned long stb_srandLCG(unsigned long seed);
- STB_EXTERN unsigned long stb_randLCG(void);
- STB_EXTERN double stb_frandLCG(void);
- STB_EXTERN void stb_srand(unsigned long seed);
- STB_EXTERN unsigned long stb_rand(void);
- STB_EXTERN double stb_frand(void);
- STB_EXTERN void stb_shuffle(void *p, size_t n, size_t sz,
- unsigned long seed);
- STB_EXTERN void stb_reverse(void *p, size_t n, size_t sz);
- STB_EXTERN unsigned long stb_randLCG_explicit(unsigned long seed);
- #endif // STB_INCLUDE_STB_LIB_H
- #ifdef STB_LIB_IMPLEMENTATION
- unsigned long stb_randLCG_explicit(unsigned long seed)
- {
- return seed * 2147001325 + 715136305;
- }
- static unsigned long stb__rand_seed=0;
- unsigned long stb_srandLCG(unsigned long seed)
- {
- unsigned long previous = stb__rand_seed;
- stb__rand_seed = seed;
- return previous;
- }
- unsigned long stb_randLCG(void)
- {
- stb__rand_seed = stb__rand_seed * 2147001325 + 715136305; // BCPL generator
- // shuffle non-random bits to the middle, and xor to decorrelate with seed
- return 0x31415926 ^ ((stb__rand_seed >> 16) + (stb__rand_seed << 16));
- }
- double stb_frandLCG(void)
- {
- return stb_randLCG() / ((double) (1 << 16) * (1 << 16));
- }
- void stb_shuffle(void *p, size_t n, size_t sz, unsigned long seed)
- {
- char *a;
- unsigned long old_seed;
- int i;
- if (seed)
- old_seed = stb_srandLCG(seed);
- a = (char *) p + (n-1) * sz;
- for (i=n; i > 1; --i) {
- int j = stb_randLCG() % i;
- stb_swap(a, (char *) p + j * sz, sz);
- a -= sz;
- }
- if (seed)
- stb_srandLCG(old_seed);
- }
- void stb_reverse(void *p, size_t n, size_t sz)
- {
- int i,j = n-1;
- for (i=0; i < j; ++i,--j) {
- stb_swap((char *) p + i * sz, (char *) p + j * sz, sz);
- }
- }
- // public domain Mersenne Twister by Michael Brundage
- #define STB__MT_LEN 624
- int stb__mt_index = STB__MT_LEN*sizeof(unsigned long)+1;
- unsigned long stb__mt_buffer[STB__MT_LEN];
- void stb_srand(unsigned long seed)
- {
- int i;
- unsigned long old = stb_srandLCG(seed);
- for (i = 0; i < STB__MT_LEN; i++)
- stb__mt_buffer[i] = stb_randLCG();
- stb_srandLCG(old);
- stb__mt_index = STB__MT_LEN*sizeof(unsigned long);
- }
- #define STB__MT_IA 397
- #define STB__MT_IB (STB__MT_LEN - STB__MT_IA)
- #define STB__UPPER_MASK 0x80000000
- #define STB__LOWER_MASK 0x7FFFFFFF
- #define STB__MATRIX_A 0x9908B0DF
- #define STB__TWIST(b,i,j) ((b)[i] & STB__UPPER_MASK) | ((b)[j] & STB__LOWER_MASK)
- #define STB__MAGIC(s) (((s)&1)*STB__MATRIX_A)
- unsigned long stb_rand()
- {
- unsigned long * b = stb__mt_buffer;
- int idx = stb__mt_index;
- unsigned long s,r;
- int i;
-
- if (idx >= STB__MT_LEN*sizeof(unsigned long)) {
- if (idx > STB__MT_LEN*sizeof(unsigned long))
- stb_srand(0);
- idx = 0;
- i = 0;
- for (; i < STB__MT_IB; i++) {
- s = STB__TWIST(b, i, i+1);
- b[i] = b[i + STB__MT_IA] ^ (s >> 1) ^ STB__MAGIC(s);
- }
- for (; i < STB__MT_LEN-1; i++) {
- s = STB__TWIST(b, i, i+1);
- b[i] = b[i - STB__MT_IB] ^ (s >> 1) ^ STB__MAGIC(s);
- }
-
- s = STB__TWIST(b, STB__MT_LEN-1, 0);
- b[STB__MT_LEN-1] = b[STB__MT_IA-1] ^ (s >> 1) ^ STB__MAGIC(s);
- }
- stb__mt_index = idx + sizeof(unsigned long);
-
- r = *(unsigned long *)((unsigned char *)b + idx);
-
- r ^= (r >> 11);
- r ^= (r << 7) & 0x9D2C5680;
- r ^= (r << 15) & 0xEFC60000;
- r ^= (r >> 18);
-
- return r;
- }
- double stb_frand(void)
- {
- return stb_rand() / ((double) (1 << 16) * (1 << 16));
- }
- #endif
- //////////////////////////////////////////////////////////////////////////////
- //
- // wildcards and regexping
- //
- #ifndef STB_INCLUDE_STB_LIB_H
- STB_EXTERN int stb_wildmatch (char *expr, char *candidate);
- STB_EXTERN int stb_wildmatchi(char *expr, char *candidate);
- STB_EXTERN int stb_wildfind (char *expr, char *candidate);
- STB_EXTERN int stb_wildfindi (char *expr, char *candidate);
- #endif // STB_INCLUDE_STB_LIB_H
- #ifdef STB_LIB_IMPLEMENTATION
- static int stb__match_qstring(char *candidate, char *qstring, int qlen, int insensitive)
- {
- int i;
- if (insensitive) {
- for (i=0; i < qlen; ++i)
- if (qstring[i] == '?') {
- if (!candidate[i]) return 0;
- } else
- if (tolower(qstring[i]) != tolower(candidate[i]))
- return 0;
- } else {
- for (i=0; i < qlen; ++i)
- if (qstring[i] == '?') {
- if (!candidate[i]) return 0;
- } else
- if (qstring[i] != candidate[i])
- return 0;
- }
- return 1;
- }
- static int stb__find_qstring(char *candidate, char *qstring, int qlen, int insensitive)
- {
- char c;
- int offset=0;
- while (*qstring == '?') {
- ++qstring;
- --qlen;
- ++candidate;
- if (qlen == 0) return 0;
- if (*candidate == 0) return -1;
- }
- c = *qstring++;
- --qlen;
- if (insensitive) c = tolower(c);
- while (candidate[offset]) {
- if (c == (insensitive ? tolower(candidate[offset]) : candidate[offset]))
- if (stb__match_qstring(candidate+offset+1, qstring, qlen, insensitive))
- return offset;
- ++offset;
- }
- return -1;
- }
- int stb__wildmatch_raw2(char *expr, char *candidate, int search, int insensitive)
- {
- int where=0;
- int start = -1;
-
- if (!search) {
- // parse to first '*'
- if (*expr != '*')
- start = 0;
- while (*expr != '*') {
- if (!*expr)
- return *candidate == 0 ? 0 : -1;
- if (*expr == '?') {
- if (!*candidate) return -1;
- } else {
- if (insensitive) {
- if (tolower(*candidate) != tolower(*expr))
- return -1;
- } else
- if (*candidate != *expr)
- return -1;
- }
- ++candidate, ++expr, ++where;
- }
- } else {
- // 0-length search string
- if (!*expr)
- return 0;
- }
- assert(search || *expr == '*');
- if (!search)
- ++expr;
- // implicit '*' at this point
-
- while (*expr) {
- int o=0;
- // combine redundant * characters
- while (expr[0] == '*') ++expr;
- // ok, at this point, expr[-1] == '*',
- // and expr[0] != '*'
- if (!expr[0]) return start >= 0 ? start : 0;
- // now find next '*'
- o = 0;
- while (expr[o] != '*') {
- if (expr[o] == 0)
- break;
- ++o;
- }
- // if no '*', scan to end, then match at end
- if (expr[o] == 0 && !search) {
- int z;
- for (z=0; z < o; ++z)
- if (candidate[z] == 0)
- return -1;
- while (candidate[z])
- ++z;
- // ok, now check if they match
- if (stb__match_qstring(candidate+z-o, expr, o, insensitive))
- return start >= 0 ? start : 0;
- return -1;
- } else {
- // if yes '*', then do stb__find_qmatch on the intervening chars
- int n = stb__find_qstring(candidate, expr, o, insensitive);
- if (n < 0)
- return -1;
- if (start < 0)
- start = where + n;
- expr += o;
- candidate += n+o;
- }
- if (*expr == 0) {
- assert(search);
- return start;
- }
- assert(*expr == '*');
- ++expr;
- }
- return start >= 0 ? start : 0;
- }
- int stb__wildmatch_raw(char *expr, char *candidate, int search, int insensitive)
- {
- char buffer[256];
- // handle multiple search strings
- char *s = strchr(expr, ';');
- char *last = expr;
- while (s) {
- int z;
- // need to allow for non-writeable strings... assume they're small
- if (s - last < 256) {
- stb_strncpy(buffer, last, s-last+1);
- z = stb__wildmatch_raw2(buffer, candidate, search, insensitive);
- } else {
- *s = 0;
- z = stb__wildmatch_raw2(last, candidate, search, insensitive);
- *s = ';';
- }
- if (z >= 0) return z;
- last = s+1;
- s = strchr(last, ';');
- }
- return stb__wildmatch_raw2(last, candidate, search, insensitive);
- }
- int stb_wildmatch(char *expr, char *candidate)
- {
- return stb__wildmatch_raw(expr, candidate, 0,0) >= 0;
- }
- int stb_wildmatchi(char *expr, char *candidate)
- {
- return stb__wildmatch_raw(expr, candidate, 0,1) >= 0;
- }
- int stb_wildfind(char *expr, char *candidate)
- {
- return stb__wildmatch_raw(expr, candidate, 1,0);
- }
- int stb_wildfindi(char *expr, char *candidate)
- {
- return stb__wildmatch_raw(expr, candidate, 1,1);
- }
- #undef STB_LIB_IMPLEMENTATION
- #endif // STB_LIB_IMPLEMENTATION
- #ifndef STB_INCLUDE_STB_LIB_H
- #define STB_INCLUDE_STB_LIB_H
- #undef STB_EXTERN
- #endif
- /*
- ------------------------------------------------------------------------------
- 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.
- ------------------------------------------------------------------------------
- */
|