DOSBox-X
|
00001 /* stb.h - v2.35 - Sean's Tool Box -- public domain -- http://nothings.org/stb.h 00002 no warranty is offered or implied; use this code at your own risk 00003 00004 This is a single header file with a bunch of useful utilities 00005 for getting stuff done in C/C++. 00006 00007 Documentation: http://nothings.org/stb/stb_h.html 00008 Unit tests: http://nothings.org/stb/stb.c 00009 00010 ============================================================================ 00011 You MUST 00012 00013 #define STB_DEFINE 00014 00015 in EXACTLY _one_ C or C++ file that includes this header, BEFORE the 00016 include, like this: 00017 00018 #define STB_DEFINE 00019 #include "stb.h" 00020 00021 All other files should just #include "stb.h" without the #define. 00022 ============================================================================ 00023 00024 Version History 00025 00026 2.36 various fixes 00027 2.35 fix clang-cl issues with swprintf 00028 2.34 fix warnings 00029 2.33 more fixes to random numbers 00030 2.32 stb_intcmprev, stb_uidict, fix random numbers on Linux 00031 2.31 stb_ucharcmp 00032 2.30 MinGW fix 00033 2.29 attempt to fix use of swprintf() 00034 2.28 various new functionality 00035 2.27 test _WIN32 not WIN32 in STB_THREADS 00036 2.26 various warning & bugfixes 00037 2.25 various warning & bugfixes 00038 2.24 various warning & bugfixes 00039 2.23 fix 2.22 00040 2.22 64-bit fixes from '!='; fix stb_sdict_copy() to have preferred name 00041 2.21 utf-8 decoder rejects "overlong" encodings; attempted 64-bit improvements 00042 2.20 fix to hash "copy" function--reported by someone with handle "!=" 00043 2.19 ??? 00044 2.18 stb_readdir_subdirs_mask 00045 2.17 stb_cfg_dir 00046 2.16 fix stb_bgio_, add stb_bgio_stat(); begin a streaming wrapper 00047 2.15 upgraded hash table template to allow: 00048 - aggregate keys (explicit comparison func for EMPTY and DEL keys) 00049 - "static" implementations (so they can be culled if unused) 00050 2.14 stb_mprintf 00051 2.13 reduce identifiable strings in STB_NO_STB_STRINGS 00052 2.12 fix STB_ONLY -- lots of uint32s, TRUE/FALSE things had crept in 00053 2.11 fix bug in stb_dirtree_get() which caused "c://path" sorts of stuff 00054 2.10 STB_F(), STB_I() inline constants (also KI,KU,KF,KD) 00055 2.09 stb_box_face_vertex_axis_side 00056 2.08 bugfix stb_trimwhite() 00057 2.07 colored printing in windows (why are we in 1985?) 00058 2.06 comparison functions are now functions-that-return-functions and 00059 accept a struct-offset as a parameter (not thread-safe) 00060 2.05 compile and pass tests under Linux (but no threads); thread cleanup 00061 2.04 stb_cubic_bezier_1d, smoothstep, avoid dependency on registry 00062 2.03 ? 00063 2.02 remove integrated documentation 00064 2.01 integrate various fixes; stb_force_uniprocessor 00065 2.00 revised stb_dupe to use multiple hashes 00066 1.99 stb_charcmp 00067 1.98 stb_arr_deleten, stb_arr_insertn 00068 1.97 fix stb_newell_normal() 00069 1.96 stb_hash_number() 00070 1.95 hack stb__rec_max; clean up recursion code to use new functions 00071 1.94 stb_dirtree; rename stb_extra to stb_ptrmap 00072 1.93 stb_sem_new() API cleanup (no blockflag-starts blocked; use 'extra') 00073 1.92 stb_threadqueue--multi reader/writer queue, fixed size or resizeable 00074 1.91 stb_bgio_* for reading disk asynchronously 00075 1.90 stb_mutex uses CRITICAL_REGION; new stb_sync primitive for thread 00076 joining; workqueue supports stb_sync instead of stb_semaphore 00077 1.89 support ';' in constant-string wildcards; stb_mutex wrapper (can 00078 implement with EnterCriticalRegion eventually) 00079 1.88 portable threading API (only for win32 so far); worker thread queue 00080 1.87 fix wildcard handling in stb_readdir_recursive 00081 1.86 support ';' in wildcards 00082 1.85 make stb_regex work with non-constant strings; 00083 beginnings of stb_introspect() 00084 1.84 (forgot to make notes) 00085 1.83 whoops, stb_keep_if_different wasn't deleting the temp file 00086 1.82 bring back stb_compress from stb_file.h for cmirror 00087 1.81 various bugfixes, STB_FASTMALLOC_INIT inits FASTMALLOC in release 00088 1.80 stb_readdir returns utf8; write own utf8-utf16 because lib was wrong 00089 1.79 stb_write 00090 1.78 calloc() support for malloc wrapper, STB_FASTMALLOC 00091 1.77 STB_FASTMALLOC 00092 1.76 STB_STUA - Lua-like language; (stb_image, stb_csample, stb_bilinear) 00093 1.75 alloc/free array of blocks; stb_hheap bug; a few stb_ps_ funcs; 00094 hash*getkey, hash*copy; stb_bitset; stb_strnicmp; bugfix stb_bst 00095 1.74 stb_replaceinplace; use stdlib C function to convert utf8 to UTF-16 00096 1.73 fix performance bug & leak in stb_ischar (C++ port lost a 'static') 00097 1.72 remove stb_block, stb_block_manager, stb_decompress (to stb_file.h) 00098 1.71 stb_trimwhite, stb_tokens_nested, etc. 00099 1.70 back out 1.69 because it might problemize mixed builds; stb_filec() 00100 1.69 (stb_file returns 'char *' in C++) 00101 1.68 add a special 'tree root' data type for stb_bst; stb_arr_end 00102 1.67 full C++ port. (stb_block_manager) 00103 1.66 stb_newell_normal 00104 1.65 stb_lex_item_wild -- allow wildcard items which MUST match entirely 00105 1.64 stb_data 00106 1.63 stb_log_name 00107 1.62 stb_define_sort; C++ cleanup 00108 1.61 stb_hash_fast -- Paul Hsieh's hash function (beats Bob Jenkins'?) 00109 1.60 stb_delete_directory_recursive 00110 1.59 stb_readdir_recursive 00111 1.58 stb_bst variant with parent pointer for O(1) iteration, not O(log N) 00112 1.57 replace LCG random with Mersenne Twister (found a public domain one) 00113 1.56 stb_perfect_hash, stb_ischar, stb_regex 00114 1.55 new stb_bst API allows multiple BSTs per node (e.g. secondary keys) 00115 1.54 bugfix: stb_define_hash, stb_wildmatch, regexp 00116 1.53 stb_define_hash; recoded stb_extra, stb_sdict use it 00117 1.52 stb_rand_define, stb_bst, stb_reverse 00118 1.51 fix 'stb_arr_setlen(NULL, 0)' 00119 1.50 stb_wordwrap 00120 1.49 minor improvements to enable the scripting language 00121 1.48 better approach for stb_arr using stb_malloc; more invasive, clearer 00122 1.47 stb_lex (lexes stb.h at 1.5ML/s on 3Ghz P4; 60/70% of optimal/flex) 00123 1.46 stb_wrapper_*, STB_MALLOC_WRAPPER 00124 1.45 lightly tested DFA acceleration of regexp searching 00125 1.44 wildcard matching & searching; regexp matching & searching 00126 1.43 stb_temp 00127 1.42 allow stb_arr to use stb_malloc/realloc; note this is global 00128 1.41 make it compile in C++; (disable stb_arr in C++) 00129 1.40 stb_dupe tweak; stb_swap; stb_substr 00130 1.39 stb_dupe; improve stb_file_max to be less stupid 00131 1.38 stb_sha1_file: generate sha1 for file, even > 4GB 00132 1.37 stb_file_max; partial support for utf8 filenames in Windows 00133 1.36 remove STB__NO_PREFIX - poor interaction with IDE, not worth it 00134 streamline stb_arr to make it separately publishable 00135 1.35 bugfixes for stb_sdict, stb_malloc(0), stristr 00136 1.34 (streaming interfaces for stb_compress) 00137 1.33 stb_alloc; bug in stb_getopt; remove stb_overflow 00138 1.32 (stb_compress returns, smaller&faster; encode window & 64-bit len) 00139 1.31 stb_prefix_count 00140 1.30 (STB__NO_PREFIX - remove stb_ prefixes for personal projects) 00141 1.29 stb_fput_varlen64, etc. 00142 1.28 stb_sha1 00143 1.27 ? 00144 1.26 stb_extra 00145 1.25 ? 00146 1.24 stb_copyfile 00147 1.23 stb_readdir 00148 1.22 ? 00149 1.21 ? 00150 1.20 ? 00151 1.19 ? 00152 1.18 ? 00153 1.17 ? 00154 1.16 ? 00155 1.15 stb_fixpath, stb_splitpath, stb_strchr2 00156 1.14 stb_arr 00157 1.13 ?stb, stb_log, stb_fatal 00158 1.12 ?stb_hash2 00159 1.11 miniML 00160 1.10 stb_crc32, stb_adler32 00161 1.09 stb_sdict 00162 1.08 stb_bitreverse, stb_ispow2, stb_big32 00163 stb_fopen, stb_fput_varlen, stb_fput_ranged 00164 stb_fcmp, stb_feq 00165 1.07 (stb_encompress) 00166 1.06 stb_compress 00167 1.05 stb_tokens, (stb_hheap) 00168 1.04 stb_rand 00169 1.03 ?(s-strings) 00170 1.02 ?stb_filelen, stb_tokens 00171 1.01 stb_tolower 00172 1.00 stb_hash, stb_intcmp 00173 stb_file, stb_stringfile, stb_fgets 00174 stb_prefix, stb_strlower, stb_strtok 00175 stb_image 00176 (stb_array), (stb_arena) 00177 00178 Parenthesized items have since been removed. 00179 00180 LICENSE 00181 00182 See end of file for license information. 00183 00184 CREDITS 00185 00186 Written by Sean Barrett. 00187 00188 Fixes: 00189 Philipp Wiesemann 00190 Robert Nix 00191 r-lyeh 00192 blackpawn 00193 github:Mojofreem 00194 Ryan Whitworth 00195 Vincent Isambart 00196 Mike Sartain 00197 Eugene Opalev 00198 Tim Sjostrand 00199 github:infatum 00200 Dave Butler (Croepha) 00201 Ethan Lee (flibitijibibo) 00202 Brian Collins 00203 */ 00204 00205 #include <stdarg.h> 00206 00207 #ifndef STB__INCLUDE_STB_H 00208 #define STB__INCLUDE_STB_H 00209 00210 #define STB_VERSION 1 00211 00212 #ifdef STB_INTROSPECT 00213 #define STB_DEFINE 00214 #endif 00215 00216 #ifdef STB_DEFINE_THREADS 00217 #ifndef STB_DEFINE 00218 #define STB_DEFINE 00219 #endif 00220 #ifndef STB_THREADS 00221 #define STB_THREADS 00222 #endif 00223 #endif 00224 00225 #if defined(_WIN32) && !defined(__MINGW32__) 00226 #ifndef _CRT_SECURE_NO_WARNINGS 00227 #define _CRT_SECURE_NO_WARNINGS 00228 #endif 00229 #ifndef _CRT_NONSTDC_NO_DEPRECATE 00230 #define _CRT_NONSTDC_NO_DEPRECATE 00231 #endif 00232 #ifndef _CRT_NON_CONFORMING_SWPRINTFS 00233 #define _CRT_NON_CONFORMING_SWPRINTFS 00234 #endif 00235 #if !defined(_MSC_VER) || _MSC_VER > 1700 00236 #include <intrin.h> // _BitScanReverse 00237 #endif 00238 #endif 00239 00240 #include <stdlib.h> // stdlib could have min/max 00241 #include <stdio.h> // need FILE 00242 #include <string.h> // stb_define_hash needs memcpy/memset 00243 #include <time.h> // stb_dirtree 00244 #ifdef __MINGW32__ 00245 #include <fcntl.h> // O_RDWR 00246 #endif 00247 00248 #ifdef STB_PERSONAL 00249 typedef int Bool; 00250 #define False 0 00251 #define True 1 00252 #endif 00253 00254 #ifdef STB_MALLOC_WRAPPER_PAGED 00255 #define STB_MALLOC_WRAPPER_DEBUG 00256 #endif 00257 #ifdef STB_MALLOC_WRAPPER_DEBUG 00258 #define STB_MALLOC_WRAPPER 00259 #endif 00260 #ifdef STB_MALLOC_WRAPPER_FASTMALLOC 00261 #define STB_FASTMALLOC 00262 #define STB_MALLOC_WRAPPER 00263 #endif 00264 00265 #ifdef STB_FASTMALLOC 00266 #ifndef _WIN32 00267 #undef STB_FASTMALLOC 00268 #endif 00269 #endif 00270 00271 #ifdef STB_DEFINE 00272 #include <assert.h> 00273 #include <stdarg.h> 00274 #include <stddef.h> 00275 #include <ctype.h> 00276 #include <math.h> 00277 #ifndef _WIN32 00278 #include <unistd.h> 00279 #else 00280 #include <io.h> // _mktemp 00281 #include <direct.h> // _rmdir 00282 #endif 00283 #include <sys/types.h> // stat()/_stat() 00284 #include <sys/stat.h> // stat()/_stat() 00285 #endif 00286 00287 #define stb_min(a,b) ((a) < (b) ? (a) : (b)) 00288 #define stb_max(a,b) ((a) > (b) ? (a) : (b)) 00289 00290 #ifndef STB_ONLY 00291 #if !defined(__cplusplus) && !defined(min) && !defined(max) 00292 #define min(x,y) stb_min(x,y) 00293 #define max(x,y) stb_max(x,y) 00294 #endif 00295 00296 #ifndef M_PI 00297 #define M_PI 3.14159265358979323846f 00298 #endif 00299 00300 #ifndef TRUE 00301 #define TRUE 1 00302 #define FALSE 0 00303 #endif 00304 00305 #ifndef deg2rad 00306 #define deg2rad(a) ((a)*(M_PI/180)) 00307 #endif 00308 #ifndef rad2deg 00309 #define rad2deg(a) ((a)*(180/M_PI)) 00310 #endif 00311 00312 #ifndef swap 00313 #ifndef __cplusplus 00314 #define swap(TYPE,a,b) \ 00315 do { TYPE stb__t; stb__t = (a); (a) = (b); (b) = stb__t; } while (0) 00316 #endif 00317 #endif 00318 00319 typedef unsigned char uint8 ; 00320 typedef signed char int8 ; 00321 typedef unsigned short uint16; 00322 typedef signed short int16; 00323 #if defined(STB_USE_LONG_FOR_32_BIT_INT) || defined(STB_LONG32) 00324 typedef unsigned long uint32; 00325 typedef signed long int32; 00326 #else 00327 typedef unsigned int uint32; 00328 typedef signed int int32; 00329 #endif 00330 00331 typedef unsigned char uchar ; 00332 typedef unsigned short ushort; 00333 typedef unsigned int uint ; 00334 typedef unsigned long ulong ; 00335 00336 // produce compile errors if the sizes aren't right 00337 typedef char stb__testsize16[sizeof(int16)==2]; 00338 typedef char stb__testsize32[sizeof(int32)==4]; 00339 #endif 00340 00341 #ifndef STB_TRUE 00342 #define STB_TRUE 1 00343 #define STB_FALSE 0 00344 #endif 00345 00346 // if we're STB_ONLY, can't rely on uint32 or even uint, so all the 00347 // variables we'll use herein need typenames prefixed with 'stb': 00348 typedef unsigned char stb_uchar; 00349 typedef unsigned char stb_uint8; 00350 typedef unsigned int stb_uint; 00351 typedef unsigned short stb_uint16; 00352 typedef short stb_int16; 00353 typedef signed char stb_int8; 00354 #if defined(STB_USE_LONG_FOR_32_BIT_INT) || defined(STB_LONG32) 00355 typedef unsigned long stb_uint32; 00356 typedef long stb_int32; 00357 #else 00358 typedef unsigned int stb_uint32; 00359 typedef int stb_int32; 00360 #endif 00361 typedef char stb__testsize2_16[sizeof(stb_uint16)==2 ? 1 : -1]; 00362 typedef char stb__testsize2_32[sizeof(stb_uint32)==4 ? 1 : -1]; 00363 00364 #ifdef _MSC_VER 00365 typedef unsigned __int64 stb_uint64; 00366 typedef __int64 stb_int64; 00367 #define STB_IMM_UINT64(literalui64) (literalui64##ui64) 00368 #define STB_IMM_INT64(literali64) (literali64##i64) 00369 #else 00370 // ?? 00371 typedef unsigned long long stb_uint64; 00372 typedef long long stb_int64; 00373 #define STB_IMM_UINT64(literalui64) (literalui64##ULL) 00374 #define STB_IMM_INT64(literali64) (literali64##LL) 00375 #endif 00376 typedef char stb__testsize2_64[sizeof(stb_uint64)==8 ? 1 : -1]; 00377 00378 // add platform-specific ways of checking for sizeof(char*) == 8, 00379 // and make those define STB_PTR64 00380 #if defined(_WIN64) || defined(__x86_64__) || defined(__ia64__) || defined(__LP64__) 00381 #define STB_PTR64 00382 #endif 00383 00384 #ifdef STB_PTR64 00385 typedef char stb__testsize2_ptr[sizeof(char *) == 8]; 00386 typedef stb_uint64 stb_uinta; 00387 typedef stb_int64 stb_inta; 00388 #else 00389 typedef char stb__testsize2_ptr[sizeof(char *) == 4]; 00390 typedef stb_uint32 stb_uinta; 00391 typedef stb_int32 stb_inta; 00392 #endif 00393 typedef char stb__testsize2_uinta[sizeof(stb_uinta)==sizeof(char*) ? 1 : -1]; 00394 00395 // if so, we should define an int type that is the pointer size. until then, 00396 // we'll have to make do with this (which is not the same at all!) 00397 00398 typedef union 00399 { 00400 unsigned int i; 00401 void * p; 00402 } stb_uintptr; 00403 00404 00405 #ifdef __cplusplus 00406 #define STB_EXTERN extern "C" 00407 #else 00408 #define STB_EXTERN extern 00409 #endif 00410 00411 // check for well-known debug defines 00412 #if defined(DEBUG) || defined(_DEBUG) || defined(DBG) 00413 #ifndef NDEBUG 00414 #define STB_DEBUG 00415 #endif 00416 #endif 00417 00418 #ifdef STB_DEBUG 00419 #include <assert.h> 00420 #endif 00421 00423 // 00424 // C library function platform handling 00425 // 00426 00427 #ifdef STB_DEFINE 00428 00429 #if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__) 00430 static FILE * stb_p_fopen(const char *filename, const char *mode) 00431 { 00432 FILE *f; 00433 if (0 == fopen_s(&f, filename, mode)) 00434 return f; 00435 else 00436 return NULL; 00437 } 00438 static FILE * stb_p_wfopen(const wchar_t *filename, const wchar_t *mode) 00439 { 00440 FILE *f; 00441 if (0 == _wfopen_s(&f, filename, mode)) 00442 return f; 00443 else 00444 return NULL; 00445 } 00446 static char *stb_p_strcpy_s(char *a, size_t size, const char *b) 00447 { 00448 strcpy_s(a,size,b); 00449 return a; 00450 } 00451 static char *stb_p_strncpy_s(char *a, size_t size, const char *b, size_t count) 00452 { 00453 strncpy_s(a,size,b,count); 00454 return a; 00455 } 00456 #define stb_p_mktemp(s) (_mktemp_s(s, strlen(s)+1) == 0) 00457 #define stb_p_sprintf sprintf_s 00458 #define stb_p_size(x) ,(x) 00459 #else 00460 #define stb_p_fopen fopen 00461 #define stb_p_wfopen _wfopen 00462 #define stb_p_strcpy_s(a,s,b) strcpy(a,b) 00463 #define stb_p_strncpy_s(a,s,b,c) strncpy(a,b,c) 00464 #define stb_p_mktemp(s) (mktemp(s) != NULL) 00465 00466 #define stb_p_sprintf sprintf 00467 #define stb_p_size(x) 00468 #endif 00469 00470 #if defined(_WIN32) 00471 #define stb_p_vsnprintf _vsnprintf 00472 #else 00473 #define stb_p_vsnprintf vsnprintf 00474 #endif 00475 #endif // STB_DEFINE 00476 00477 #if defined(_WIN32) && (_MSC_VER >= 1300) 00478 #define stb_p_stricmp _stricmp 00479 #define stb_p_strnicmp _strnicmp 00480 #define stb_p_strdup _strdup 00481 #else 00482 #define stb_p_strdup strdup 00483 #define stb_p_stricmp stricmp 00484 #define stb_p_strnicmp strnicmp 00485 #endif 00486 00487 STB_EXTERN void stb_wrapper_malloc(void *newp, size_t sz, char *file, int line); 00488 STB_EXTERN void stb_wrapper_free(void *oldp, char *file, int line); 00489 STB_EXTERN void stb_wrapper_realloc(void *oldp, void *newp, size_t sz, char *file, int line); 00490 STB_EXTERN void stb_wrapper_calloc(size_t num, size_t sz, char *file, int line); 00491 STB_EXTERN void stb_wrapper_listall(void (*func)(void *ptr, size_t sz, char *file, int line)); 00492 STB_EXTERN void stb_wrapper_dump(char *filename); 00493 STB_EXTERN size_t stb_wrapper_allocsize(void *oldp); 00494 STB_EXTERN void stb_wrapper_check(void *oldp); 00495 00496 #ifdef STB_DEFINE 00497 // this is a special function used inside malloc wrapper 00498 // to do allocations that aren't tracked (to avoid 00499 // reentrancy). Of course if someone _else_ wraps realloc, 00500 // this breaks, but if they're doing that AND the malloc 00501 // wrapper they need to explicitly check for reentrancy. 00502 // 00503 // only define realloc_raw() and we do realloc(NULL,sz) 00504 // for malloc() and realloc(p,0) for free(). 00505 static void * stb__realloc_raw(void *p, int sz) 00506 { 00507 if (p == NULL) return malloc(sz); 00508 if (sz == 0) { free(p); return NULL; } 00509 return realloc(p,sz); 00510 } 00511 #endif 00512 00513 #ifdef _WIN32 00514 STB_EXTERN void * stb_smalloc(size_t sz); 00515 STB_EXTERN void stb_sfree(void *p); 00516 STB_EXTERN void * stb_srealloc(void *p, size_t sz); 00517 STB_EXTERN void * stb_scalloc(size_t n, size_t sz); 00518 STB_EXTERN char * stb_sstrdup(char *s); 00519 #endif 00520 00521 #ifdef STB_FASTMALLOC 00522 #define malloc stb_smalloc 00523 #define free stb_sfree 00524 #define realloc stb_srealloc 00525 #define strdup stb_sstrdup 00526 #define calloc stb_scalloc 00527 #endif 00528 00529 #ifndef STB_MALLOC_ALLCHECK 00530 #define stb__check(p) 1 00531 #else 00532 #ifndef STB_MALLOC_WRAPPER 00533 #error STB_MALLOC_ALLCHECK requires STB_MALLOC_WRAPPER 00534 #else 00535 #define stb__check(p) stb_mcheck(p) 00536 #endif 00537 #endif 00538 00539 #ifdef STB_MALLOC_WRAPPER 00540 STB_EXTERN void * stb__malloc(size_t, char *, int); 00541 STB_EXTERN void * stb__realloc(void *, size_t, char *, int); 00542 STB_EXTERN void * stb__calloc(size_t n, size_t s, char *, int); 00543 STB_EXTERN void stb__free(void *, char *file, int); 00544 STB_EXTERN char * stb__strdup(char *s, char *file, int); 00545 STB_EXTERN void stb_malloc_checkall(void); 00546 STB_EXTERN void stb_malloc_check_counter(int init_delay, int rep_delay); 00547 #ifndef STB_MALLOC_WRAPPER_DEBUG 00548 #define stb_mcheck(p) 1 00549 #else 00550 STB_EXTERN int stb_mcheck(void *); 00551 #endif 00552 00553 00554 #ifdef STB_DEFINE 00555 00556 #ifdef STB_MALLOC_WRAPPER_DEBUG 00557 #define STB__PAD 32 00558 #define STB__BIAS 16 00559 #define STB__SIG 0x51b01234 00560 #define STB__FIXSIZE(sz) (((sz+3) & ~3) + STB__PAD) 00561 #define STB__ptr(x,y) ((char *) (x) + (y)) 00562 #else 00563 #define STB__ptr(x,y) (x) 00564 #define STB__FIXSIZE(sz) (sz) 00565 #endif 00566 00567 #ifdef STB_MALLOC_WRAPPER_DEBUG 00568 int stb_mcheck(void *p) 00569 { 00570 unsigned int sz; 00571 if (p == NULL) return 1; 00572 p = ((char *) p) - STB__BIAS; 00573 sz = * (unsigned int *) p; 00574 assert(* (unsigned int *) STB__ptr(p,4) == STB__SIG); 00575 assert(* (unsigned int *) STB__ptr(p,8) == STB__SIG); 00576 assert(* (unsigned int *) STB__ptr(p,12) == STB__SIG); 00577 assert(* (unsigned int *) STB__ptr(p,sz-4) == STB__SIG+1); 00578 assert(* (unsigned int *) STB__ptr(p,sz-8) == STB__SIG+1); 00579 assert(* (unsigned int *) STB__ptr(p,sz-12) == STB__SIG+1); 00580 assert(* (unsigned int *) STB__ptr(p,sz-16) == STB__SIG+1); 00581 stb_wrapper_check(STB__ptr(p, STB__BIAS)); 00582 return 1; 00583 } 00584 00585 static void stb__check2(void *p, size_t sz, char *file, int line) 00586 { 00587 stb_mcheck(p); 00588 } 00589 00590 void stb_malloc_checkall(void) 00591 { 00592 stb_wrapper_listall(stb__check2); 00593 } 00594 #else 00595 void stb_malloc_checkall(void) { } 00596 #endif 00597 00598 static int stb__malloc_wait=(1 << 30), stb__malloc_next_wait = (1 << 30), stb__malloc_iter; 00599 void stb_malloc_check_counter(int init_delay, int rep_delay) 00600 { 00601 stb__malloc_wait = init_delay; 00602 stb__malloc_next_wait = rep_delay; 00603 } 00604 00605 void stb_mcheck_all(void) 00606 { 00607 #ifdef STB_MALLOC_WRAPPER_DEBUG 00608 ++stb__malloc_iter; 00609 if (--stb__malloc_wait <= 0) { 00610 stb_malloc_checkall(); 00611 stb__malloc_wait = stb__malloc_next_wait; 00612 } 00613 #endif 00614 } 00615 00616 #ifdef STB_MALLOC_WRAPPER_PAGED 00617 #define STB__WINDOWS_PAGE (1 << 12) 00618 #ifndef _WINDOWS_ 00619 STB_EXTERN __declspec(dllimport) void * __stdcall VirtualAlloc(void *p, unsigned long size, unsigned long type, unsigned long protect); 00620 STB_EXTERN __declspec(dllimport) int __stdcall VirtualFree(void *p, unsigned long size, unsigned long freetype); 00621 #endif 00622 #endif 00623 00624 static void *stb__malloc_final(size_t sz) 00625 { 00626 #ifdef STB_MALLOC_WRAPPER_PAGED 00627 size_t aligned = (sz + STB__WINDOWS_PAGE - 1) & ~(STB__WINDOWS_PAGE-1); 00628 char *p = VirtualAlloc(NULL, aligned + STB__WINDOWS_PAGE, 0x2000, 0x04); // RESERVE, READWRITE 00629 if (p == NULL) return p; 00630 VirtualAlloc(p, aligned, 0x1000, 0x04); // COMMIT, READWRITE 00631 return p; 00632 #else 00633 return malloc(sz); 00634 #endif 00635 } 00636 00637 static void stb__free_final(void *p) 00638 { 00639 #ifdef STB_MALLOC_WRAPPER_PAGED 00640 VirtualFree(p, 0, 0x8000); // RELEASE 00641 #else 00642 free(p); 00643 #endif 00644 } 00645 00646 int stb__malloc_failure; 00647 #ifdef STB_MALLOC_WRAPPER_PAGED 00648 static void *stb__realloc_final(void *p, size_t sz, size_t old_sz) 00649 { 00650 void *q = stb__malloc_final(sz); 00651 if (q == NULL) 00652 return ++stb__malloc_failure, q; 00653 // @TODO: deal with p being smaller! 00654 memcpy(q, p, sz < old_sz ? sz : old_sz); 00655 stb__free_final(p); 00656 return q; 00657 } 00658 #endif 00659 00660 void stb__free(void *p, char *file, int line) 00661 { 00662 stb_mcheck_all(); 00663 if (!p) return; 00664 #ifdef STB_MALLOC_WRAPPER_DEBUG 00665 stb_mcheck(p); 00666 #endif 00667 stb_wrapper_free(p,file,line); 00668 #ifdef STB_MALLOC_WRAPPER_DEBUG 00669 p = STB__ptr(p,-STB__BIAS); 00670 * (unsigned int *) STB__ptr(p,0) = 0xdeadbeef; 00671 * (unsigned int *) STB__ptr(p,4) = 0xdeadbeef; 00672 * (unsigned int *) STB__ptr(p,8) = 0xdeadbeef; 00673 * (unsigned int *) STB__ptr(p,12) = 0xdeadbeef; 00674 #endif 00675 stb__free_final(p); 00676 } 00677 00678 void * stb__malloc(size_t sz, char *file, int line) 00679 { 00680 void *p; 00681 stb_mcheck_all(); 00682 if (sz == 0) return NULL; 00683 p = stb__malloc_final(STB__FIXSIZE(sz)); 00684 if (p == NULL) p = stb__malloc_final(STB__FIXSIZE(sz)); 00685 if (p == NULL) p = stb__malloc_final(STB__FIXSIZE(sz)); 00686 if (p == NULL) { 00687 ++stb__malloc_failure; 00688 #ifdef STB_MALLOC_WRAPPER_DEBUG 00689 stb_malloc_checkall(); 00690 #endif 00691 return p; 00692 } 00693 #ifdef STB_MALLOC_WRAPPER_DEBUG 00694 * (int *) STB__ptr(p,0) = STB__FIXSIZE(sz); 00695 * (unsigned int *) STB__ptr(p,4) = STB__SIG; 00696 * (unsigned int *) STB__ptr(p,8) = STB__SIG; 00697 * (unsigned int *) STB__ptr(p,12) = STB__SIG; 00698 * (unsigned int *) STB__ptr(p,STB__FIXSIZE(sz)-4) = STB__SIG+1; 00699 * (unsigned int *) STB__ptr(p,STB__FIXSIZE(sz)-8) = STB__SIG+1; 00700 * (unsigned int *) STB__ptr(p,STB__FIXSIZE(sz)-12) = STB__SIG+1; 00701 * (unsigned int *) STB__ptr(p,STB__FIXSIZE(sz)-16) = STB__SIG+1; 00702 p = STB__ptr(p, STB__BIAS); 00703 #endif 00704 stb_wrapper_malloc(p,sz,file,line); 00705 return p; 00706 } 00707 00708 void * stb__realloc(void *p, size_t sz, char *file, int line) 00709 { 00710 void *q; 00711 00712 stb_mcheck_all(); 00713 if (p == NULL) return stb__malloc(sz,file,line); 00714 if (sz == 0 ) { stb__free(p,file,line); return NULL; } 00715 00716 #ifdef STB_MALLOC_WRAPPER_DEBUG 00717 stb_mcheck(p); 00718 p = STB__ptr(p,-STB__BIAS); 00719 #endif 00720 #ifdef STB_MALLOC_WRAPPER_PAGED 00721 { 00722 size_t n = stb_wrapper_allocsize(STB__ptr(p,STB__BIAS)); 00723 if (!n) 00724 stb_wrapper_check(STB__ptr(p,STB__BIAS)); 00725 q = stb__realloc_final(p, STB__FIXSIZE(sz), STB__FIXSIZE(n)); 00726 } 00727 #else 00728 q = realloc(p, STB__FIXSIZE(sz)); 00729 #endif 00730 if (q == NULL) 00731 return ++stb__malloc_failure, q; 00732 #ifdef STB_MALLOC_WRAPPER_DEBUG 00733 * (int *) STB__ptr(q,0) = STB__FIXSIZE(sz); 00734 * (unsigned int *) STB__ptr(q,4) = STB__SIG; 00735 * (unsigned int *) STB__ptr(q,8) = STB__SIG; 00736 * (unsigned int *) STB__ptr(q,12) = STB__SIG; 00737 * (unsigned int *) STB__ptr(q,STB__FIXSIZE(sz)-4) = STB__SIG+1; 00738 * (unsigned int *) STB__ptr(q,STB__FIXSIZE(sz)-8) = STB__SIG+1; 00739 * (unsigned int *) STB__ptr(q,STB__FIXSIZE(sz)-12) = STB__SIG+1; 00740 * (unsigned int *) STB__ptr(q,STB__FIXSIZE(sz)-16) = STB__SIG+1; 00741 00742 q = STB__ptr(q, STB__BIAS); 00743 p = STB__ptr(p, STB__BIAS); 00744 #endif 00745 stb_wrapper_realloc(p,q,sz,file,line); 00746 return q; 00747 } 00748 00749 STB_EXTERN int stb_log2_ceil(size_t); 00750 static void *stb__calloc(size_t n, size_t sz, char *file, int line) 00751 { 00752 void *q; 00753 stb_mcheck_all(); 00754 if (n == 0 || sz == 0) return NULL; 00755 if (stb_log2_ceil(n) + stb_log2_ceil(sz) >= 32) return NULL; 00756 q = stb__malloc(n*sz, file, line); 00757 if (q) memset(q, 0, n*sz); 00758 return q; 00759 } 00760 00761 char * stb__strdup(char *s, char *file, int line) 00762 { 00763 char *p; 00764 stb_mcheck_all(); 00765 p = stb__malloc(strlen(s)+1, file, line); 00766 if (!p) return p; 00767 stb_p_strcpy_s(p, strlen(s)+1, s); 00768 return p; 00769 } 00770 #endif // STB_DEFINE 00771 00772 #ifdef STB_FASTMALLOC 00773 #undef malloc 00774 #undef realloc 00775 #undef free 00776 #undef strdup 00777 #undef calloc 00778 #endif 00779 00780 // include everything that might define these, BEFORE making macros 00781 #include <stdlib.h> 00782 #include <string.h> 00783 #include <malloc.h> 00784 00785 #define malloc(s) stb__malloc ( s, __FILE__, __LINE__) 00786 #define realloc(p,s) stb__realloc(p,s, __FILE__, __LINE__) 00787 #define calloc(n,s) stb__calloc (n,s, __FILE__, __LINE__) 00788 #define free(p) stb__free (p, __FILE__, __LINE__) 00789 #define strdup(p) stb__strdup (p, __FILE__, __LINE__) 00790 #endif 00791 00793 // 00794 // Windows pretty display 00795 // 00796 00797 STB_EXTERN void stbprint(const char *fmt, ...); 00798 STB_EXTERN char *stb_sprintf(const char *fmt, ...); 00799 STB_EXTERN char *stb_mprintf(const char *fmt, ...); 00800 STB_EXTERN int stb_snprintf(char *s, size_t n, const char *fmt, ...); 00801 STB_EXTERN int stb_vsnprintf(char *s, size_t n, const char *fmt, va_list v); 00802 00803 #ifdef STB_DEFINE 00804 int stb_vsnprintf(char *s, size_t n, const char *fmt, va_list v) 00805 { 00806 int res; 00807 #ifdef _WIN32 00808 #ifdef __STDC_WANT_SECURE_LIB__ 00809 res = _vsnprintf_s(s, n, _TRUNCATE, fmt, v); 00810 #else 00811 res = stb_p_vsnprintf(s,n,fmt,v); 00812 #endif 00813 #else 00814 res = vsnprintf(s,n,fmt,v); 00815 #endif 00816 if (n) s[n-1] = 0; 00817 // Unix returns length output would require, Windows returns negative when truncated. 00818 return (res >= (int) n || res < 0) ? -1 : res; 00819 } 00820 00821 int stb_snprintf(char *s, size_t n, const char *fmt, ...) 00822 { 00823 int res; 00824 va_list v; 00825 va_start(v,fmt); 00826 res = stb_vsnprintf(s, n, fmt, v); 00827 va_end(v); 00828 return res; 00829 } 00830 00831 char *stb_sprintf(const char *fmt, ...) 00832 { 00833 static char buffer[1024]; 00834 va_list v; 00835 va_start(v,fmt); 00836 stb_vsnprintf(buffer,1024,fmt,v); 00837 va_end(v); 00838 return buffer; 00839 } 00840 00841 char *stb_mprintf(const char *fmt, ...) 00842 { 00843 static char buffer[1024]; 00844 va_list v; 00845 va_start(v,fmt); 00846 stb_vsnprintf(buffer,1024,fmt,v); 00847 va_end(v); 00848 return stb_p_strdup(buffer); 00849 } 00850 00851 #ifdef _WIN32 00852 00853 #ifndef _WINDOWS_ 00854 STB_EXTERN __declspec(dllimport) int __stdcall WriteConsoleA(void *, const void *, unsigned int, unsigned int *, void *); 00855 STB_EXTERN __declspec(dllimport) void * __stdcall GetStdHandle(unsigned int); 00856 STB_EXTERN __declspec(dllimport) int __stdcall SetConsoleTextAttribute(void *, unsigned short); 00857 #endif 00858 00859 static void stb__print_one(void *handle, char *s, ptrdiff_t len) 00860 { 00861 if (len) 00862 if (0==WriteConsoleA(handle, s, (unsigned) len, NULL,NULL)) 00863 // if it fails, maybe redirected, so output normally... 00864 // but it's supriously reporting failure now on Win7 and later 00865 {}//fwrite(s, 1, (unsigned) len, stdout); 00866 } 00867 00868 static void stb__print(char *s) 00869 { 00870 void *handle = GetStdHandle((unsigned int) -11); // STD_OUTPUT_HANDLE 00871 int pad=0; // number of padding characters to add 00872 00873 char *t = s; 00874 while (*s) { 00875 int lpad; 00876 while (*s && *s != '{') { 00877 if (pad) { 00878 if (*s == '\r' || *s == '\n') 00879 pad = 0; 00880 else if (s[0] == ' ' && s[1] == ' ') { 00881 stb__print_one(handle, t, s-t); 00882 t = s; 00883 while (pad) { 00884 stb__print_one(handle, t, 1); 00885 --pad; 00886 } 00887 } 00888 } 00889 ++s; 00890 } 00891 if (!*s) break; 00892 stb__print_one(handle, t, s-t); 00893 if (s[1] == '{') { 00894 ++s; 00895 continue; 00896 } 00897 00898 if (s[1] == '#') { 00899 t = s+3; 00900 if (isxdigit(s[2])) 00901 if (isdigit(s[2])) 00902 SetConsoleTextAttribute(handle, s[2] - '0'); 00903 else 00904 SetConsoleTextAttribute(handle, tolower(s[2]) - 'a' + 10); 00905 else { 00906 SetConsoleTextAttribute(handle, 0x0f); 00907 t=s+2; 00908 } 00909 } else if (s[1] == '!') { 00910 SetConsoleTextAttribute(handle, 0x0c); 00911 t = s+2; 00912 } else if (s[1] == '@') { 00913 SetConsoleTextAttribute(handle, 0x09); 00914 t = s+2; 00915 } else if (s[1] == '$') { 00916 SetConsoleTextAttribute(handle, 0x0a); 00917 t = s+2; 00918 } else { 00919 SetConsoleTextAttribute(handle, 0x08); // 0,7,8,15 => shades of grey 00920 t = s+1; 00921 } 00922 00923 lpad = (int) (t-s); 00924 s = t; 00925 while (*s && *s != '}') ++s; 00926 if (!*s) break; 00927 stb__print_one(handle, t, s-t); 00928 if (s[1] == '}') { 00929 t = s+2; 00930 } else { 00931 pad += 1+lpad; 00932 t = s+1; 00933 } 00934 s=t; 00935 SetConsoleTextAttribute(handle, 0x07); 00936 } 00937 stb__print_one(handle, t, s-t); 00938 SetConsoleTextAttribute(handle, 0x07); 00939 } 00940 00941 void stbprint(const char *fmt, ...) 00942 { 00943 int res; 00944 char buffer[1024]; 00945 char *tbuf = buffer; 00946 va_list v; 00947 00948 va_start(v,fmt); 00949 res = stb_vsnprintf(buffer, sizeof(buffer), fmt, v); 00950 va_end(v); 00951 00952 if (res < 0) { 00953 tbuf = (char *) malloc(16384); 00954 va_start(v,fmt); 00955 res = stb_vsnprintf(tbuf,16384, fmt, v); 00956 va_end(v); 00957 tbuf[16383] = 0; 00958 } 00959 00960 stb__print(tbuf); 00961 00962 if (tbuf != buffer) 00963 free(tbuf); 00964 } 00965 00966 #else // _WIN32 00967 void stbprint(const char *fmt, ...) 00968 { 00969 va_list v; 00970 va_start(v,fmt); 00971 vprintf(fmt,v); 00972 va_end(v); 00973 } 00974 #endif // _WIN32 00975 #endif // STB_DEFINE 00976 00977 00978 00980 // 00981 // Windows UTF8 filename handling 00982 // 00983 // Windows stupidly treats 8-bit filenames as some dopey code page, 00984 // rather than utf-8. If we want to use utf8 filenames, we have to 00985 // convert them to WCHAR explicitly and call WCHAR versions of the 00986 // file functions. So, ok, we do. 00987 00988 00989 #ifdef _WIN32 00990 #define stb__fopen(x,y) stb_p_wfopen((const wchar_t *)stb__from_utf8(x), (const wchar_t *)stb__from_utf8_alt(y)) 00991 #define stb__windows(x,y) x 00992 #else 00993 #define stb__fopen(x,y) stb_p_fopen(x,y) 00994 #define stb__windows(x,y) y 00995 #endif 00996 00997 00998 typedef unsigned short stb__wchar; 00999 01000 STB_EXTERN stb__wchar * stb_from_utf8(stb__wchar *buffer, const char *str, int n); 01001 STB_EXTERN char * stb_to_utf8 (char *buffer, const stb__wchar *str, int n); 01002 01003 STB_EXTERN stb__wchar *stb__from_utf8(const char *str); 01004 STB_EXTERN stb__wchar *stb__from_utf8_alt(const char *str); 01005 STB_EXTERN char *stb__to_utf8(const stb__wchar *str); 01006 01007 01008 #ifdef STB_DEFINE 01009 stb__wchar * stb_from_utf8(stb__wchar *buffer, const char *ostr, int n) 01010 { 01011 unsigned char *str = (unsigned char *) ostr; 01012 stb_uint32 c; 01013 int i=0; 01014 --n; 01015 while (*str) { 01016 if (i >= n) 01017 return NULL; 01018 if (!(*str & 0x80)) 01019 buffer[i++] = *str++; 01020 else if ((*str & 0xe0) == 0xc0) { 01021 if (*str < 0xc2) return NULL; 01022 c = (*str++ & 0x1f) << 6; 01023 if ((*str & 0xc0) != 0x80) return NULL; 01024 buffer[i++] = c + (*str++ & 0x3f); 01025 } else if ((*str & 0xf0) == 0xe0) { 01026 if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return NULL; 01027 if (*str == 0xed && str[1] > 0x9f) return NULL; // str[1] < 0x80 is checked below 01028 c = (*str++ & 0x0f) << 12; 01029 if ((*str & 0xc0) != 0x80) return NULL; 01030 c += (*str++ & 0x3f) << 6; 01031 if ((*str & 0xc0) != 0x80) return NULL; 01032 buffer[i++] = c + (*str++ & 0x3f); 01033 } else if ((*str & 0xf8) == 0xf0) { 01034 if (*str > 0xf4) return NULL; 01035 if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return NULL; 01036 if (*str == 0xf4 && str[1] > 0x8f) return NULL; // str[1] < 0x80 is checked below 01037 c = (*str++ & 0x07) << 18; 01038 if ((*str & 0xc0) != 0x80) return NULL; 01039 c += (*str++ & 0x3f) << 12; 01040 if ((*str & 0xc0) != 0x80) return NULL; 01041 c += (*str++ & 0x3f) << 6; 01042 if ((*str & 0xc0) != 0x80) return NULL; 01043 c += (*str++ & 0x3f); 01044 // utf-8 encodings of values used in surrogate pairs are invalid 01045 if ((c & 0xFFFFF800) == 0xD800) return NULL; 01046 if (c >= 0x10000) { 01047 c -= 0x10000; 01048 if (i + 2 > n) return NULL; 01049 buffer[i++] = 0xD800 | (0x3ff & (c >> 10)); 01050 buffer[i++] = 0xDC00 | (0x3ff & (c )); 01051 } 01052 } else 01053 return NULL; 01054 } 01055 buffer[i] = 0; 01056 return buffer; 01057 } 01058 01059 char * stb_to_utf8(char *buffer, const stb__wchar *str, int n) 01060 { 01061 int i=0; 01062 --n; 01063 while (*str) { 01064 if (*str < 0x80) { 01065 if (i+1 > n) return NULL; 01066 buffer[i++] = (char) *str++; 01067 } else if (*str < 0x800) { 01068 if (i+2 > n) return NULL; 01069 buffer[i++] = 0xc0 + (*str >> 6); 01070 buffer[i++] = 0x80 + (*str & 0x3f); 01071 str += 1; 01072 } else if (*str >= 0xd800 && *str < 0xdc00) { 01073 stb_uint32 c; 01074 if (i+4 > n) return NULL; 01075 c = ((str[0] - 0xd800) << 10) + ((str[1]) - 0xdc00) + 0x10000; 01076 buffer[i++] = 0xf0 + (c >> 18); 01077 buffer[i++] = 0x80 + ((c >> 12) & 0x3f); 01078 buffer[i++] = 0x80 + ((c >> 6) & 0x3f); 01079 buffer[i++] = 0x80 + ((c ) & 0x3f); 01080 str += 2; 01081 } else if (*str >= 0xdc00 && *str < 0xe000) { 01082 return NULL; 01083 } else { 01084 if (i+3 > n) return NULL; 01085 buffer[i++] = 0xe0 + (*str >> 12); 01086 buffer[i++] = 0x80 + ((*str >> 6) & 0x3f); 01087 buffer[i++] = 0x80 + ((*str ) & 0x3f); 01088 str += 1; 01089 } 01090 } 01091 buffer[i] = 0; 01092 return buffer; 01093 } 01094 01095 stb__wchar *stb__from_utf8(const char *str) 01096 { 01097 static stb__wchar buffer[4096]; 01098 return stb_from_utf8(buffer, str, 4096); 01099 } 01100 01101 stb__wchar *stb__from_utf8_alt(const char *str) 01102 { 01103 static stb__wchar buffer[4096]; 01104 return stb_from_utf8(buffer, str, 4096); 01105 } 01106 01107 char *stb__to_utf8(const stb__wchar *str) 01108 { 01109 static char buffer[4096]; 01110 return stb_to_utf8(buffer, str, 4096); 01111 } 01112 01113 #endif 01114 01116 // 01117 // Miscellany 01118 // 01119 01120 STB_EXTERN void stb_fatal(const char *fmt, ...); 01121 STB_EXTERN void stb_(char *fmt, ...); 01122 STB_EXTERN void stb_append_to_file(char *file, char *fmt, ...); 01123 STB_EXTERN void stb_log(int active); 01124 STB_EXTERN void stb_log_fileline(int active); 01125 STB_EXTERN void stb_log_name(char *filename); 01126 01127 STB_EXTERN void stb_swap(void *p, void *q, size_t sz); 01128 STB_EXTERN void *stb_copy(void *p, size_t sz); 01129 STB_EXTERN void stb_pointer_array_free(void *p, int len); 01130 STB_EXTERN void **stb_array_block_alloc(int count, int blocksize); 01131 01132 #define stb_arrcount(x) (sizeof(x)/sizeof((x)[0])) 01133 01134 01135 STB_EXTERN int stb__record_fileline(const char *f, int n); 01136 01137 #ifdef STB_DEFINE 01138 01139 static char *stb__file; 01140 static int stb__line; 01141 01142 int stb__record_fileline(const char *f, int n) 01143 { 01144 stb__file = (char*) f; 01145 stb__line = n; 01146 return 0; 01147 } 01148 01149 void stb_fatal(const char *s, ...) 01150 { 01151 va_list a; 01152 if (stb__file) 01153 fprintf(stderr, "[%s:%d] ", stb__file, stb__line); 01154 va_start(a,s); 01155 fputs("Fatal error: ", stderr); 01156 vfprintf(stderr, s, a); 01157 va_end(a); 01158 fputs("\n", stderr); 01159 #ifdef STB_DEBUG 01160 #ifdef _MSC_VER 01161 #ifndef STB_PTR64 01162 __asm int 3; // trap to debugger! 01163 #else 01164 __debugbreak(); 01165 #endif 01166 #else 01167 __builtin_trap(); 01168 #endif 01169 #endif 01170 exit(1); 01171 } 01172 01173 static int stb__log_active=1, stb__log_fileline=1; 01174 01175 void stb_log(int active) 01176 { 01177 stb__log_active = active; 01178 } 01179 01180 void stb_log_fileline(int active) 01181 { 01182 stb__log_fileline = active; 01183 } 01184 01185 #ifdef STB_NO_STB_STRINGS 01186 const char *stb__log_filename = "temp.log"; 01187 #else 01188 const char *stb__log_filename = "stb.log"; 01189 #endif 01190 01191 void stb_log_name(char *s) 01192 { 01193 stb__log_filename = s; 01194 } 01195 01196 void stb_(char *s, ...) 01197 { 01198 if (stb__log_active) { 01199 FILE *f = stb_p_fopen(stb__log_filename, "a"); 01200 if (f) { 01201 va_list a; 01202 if (stb__log_fileline && stb__file) 01203 fprintf(f, "[%s:%4d] ", stb__file, stb__line); 01204 va_start(a,s); 01205 vfprintf(f, s, a); 01206 va_end(a); 01207 fputs("\n", f); 01208 fclose(f); 01209 } 01210 } 01211 } 01212 01213 void stb_append_to_file(char *filename, char *s, ...) 01214 { 01215 FILE *f = stb_p_fopen(filename, "a"); 01216 if (f) { 01217 va_list a; 01218 va_start(a,s); 01219 vfprintf(f, s, a); 01220 va_end(a); 01221 fputs("\n", f); 01222 fclose(f); 01223 } 01224 } 01225 01226 01227 typedef struct { char d[4]; } stb__4; 01228 typedef struct { char d[8]; } stb__8; 01229 01230 // optimize the small cases, though you shouldn't be calling this for those! 01231 void stb_swap(void *p, void *q, size_t sz) 01232 { 01233 char buffer[256]; 01234 if (p == q) return; 01235 if (sz == 4) { 01236 stb__4 temp = * ( stb__4 *) p; 01237 * (stb__4 *) p = * ( stb__4 *) q; 01238 * (stb__4 *) q = temp; 01239 return; 01240 } else if (sz == 8) { 01241 stb__8 temp = * ( stb__8 *) p; 01242 * (stb__8 *) p = * ( stb__8 *) q; 01243 * (stb__8 *) q = temp; 01244 return; 01245 } 01246 01247 while (sz > sizeof(buffer)) { 01248 stb_swap(p, q, sizeof(buffer)); 01249 p = (char *) p + sizeof(buffer); 01250 q = (char *) q + sizeof(buffer); 01251 sz -= sizeof(buffer); 01252 } 01253 01254 memcpy(buffer, p , sz); 01255 memcpy(p , q , sz); 01256 memcpy(q , buffer, sz); 01257 } 01258 01259 void *stb_copy(void *p, size_t sz) 01260 { 01261 void *q = malloc(sz); 01262 memcpy(q, p, sz); 01263 return q; 01264 } 01265 01266 void stb_pointer_array_free(void *q, int len) 01267 { 01268 void **p = (void **) q; 01269 int i; 01270 for (i=0; i < len; ++i) 01271 free(p[i]); 01272 } 01273 01274 void **stb_array_block_alloc(int count, int blocksize) 01275 { 01276 int i; 01277 char *p = (char *) malloc(sizeof(void *) * count + count * blocksize); 01278 void **q; 01279 if (p == NULL) return NULL; 01280 q = (void **) p; 01281 p += sizeof(void *) * count; 01282 for (i=0; i < count; ++i) 01283 q[i] = p + i * blocksize; 01284 return q; 01285 } 01286 #endif 01287 01288 #ifdef STB_DEBUG 01289 // tricky hack to allow recording FILE,LINE even in varargs functions 01290 #define STB__RECORD_FILE(x) (stb__record_fileline(__FILE__, __LINE__),(x)) 01291 #define stb_log STB__RECORD_FILE(stb_log) 01292 #define stb_ STB__RECORD_FILE(stb_) 01293 #ifndef STB_FATAL_CLEAN 01294 #define stb_fatal STB__RECORD_FILE(stb_fatal) 01295 #endif 01296 #define STB__DEBUG(x) x 01297 #else 01298 #define STB__DEBUG(x) 01299 #endif 01300 01302 // 01303 // stb_temp 01304 // 01305 01306 #define stb_temp(block, sz) stb__temp(block, sizeof(block), (sz)) 01307 01308 STB_EXTERN void * stb__temp(void *b, int b_sz, int want_sz); 01309 STB_EXTERN void stb_tempfree(void *block, void *ptr); 01310 01311 #ifdef STB_DEFINE 01312 01313 void * stb__temp(void *b, int b_sz, int want_sz) 01314 { 01315 if (b_sz >= want_sz) 01316 return b; 01317 else 01318 return malloc(want_sz); 01319 } 01320 01321 void stb_tempfree(void *b, void *p) 01322 { 01323 if (p != b) 01324 free(p); 01325 } 01326 #endif 01327 01328 01330 // 01331 // math/sampling operations 01332 // 01333 01334 01335 #define stb_lerp(t,a,b) ( (a) + (t) * (float) ((b)-(a)) ) 01336 #define stb_unlerp(t,a,b) ( ((t) - (a)) / (float) ((b) - (a)) ) 01337 01338 #define stb_clamp(x,xmin,xmax) ((x) < (xmin) ? (xmin) : (x) > (xmax) ? (xmax) : (x)) 01339 01340 STB_EXTERN void stb_newell_normal(float *normal, int num_vert, float **vert, int normalize); 01341 STB_EXTERN int stb_box_face_vertex_axis_side(int face_number, int vertex_number, int axis); 01342 STB_EXTERN void stb_linear_controller(float *curpos, float target_pos, float acc, float deacc, float dt); 01343 01344 STB_EXTERN int stb_float_eq(float x, float y, float delta, int max_ulps); 01345 STB_EXTERN int stb_is_prime(unsigned int m); 01346 STB_EXTERN unsigned int stb_power_of_two_nearest_prime(int n); 01347 01348 STB_EXTERN float stb_smoothstep(float t); 01349 STB_EXTERN float stb_cubic_bezier_1d(float t, float p0, float p1, float p2, float p3); 01350 01351 STB_EXTERN double stb_linear_remap(double x, double a, double b, 01352 double c, double d); 01353 01354 #ifdef STB_DEFINE 01355 float stb_smoothstep(float t) 01356 { 01357 return (3 - 2*t)*(t*t); 01358 } 01359 01360 float stb_cubic_bezier_1d(float t, float p0, float p1, float p2, float p3) 01361 { 01362 float it = 1-t; 01363 return it*it*it*p0 + 3*it*it*t*p1 + 3*it*t*t*p2 + t*t*t*p3; 01364 } 01365 01366 void stb_newell_normal(float *normal, int num_vert, float **vert, int normalize) 01367 { 01368 int i,j; 01369 float p; 01370 normal[0] = normal[1] = normal[2] = 0; 01371 for (i=num_vert-1,j=0; j < num_vert; i=j++) { 01372 float *u = vert[i]; 01373 float *v = vert[j]; 01374 normal[0] += (u[1] - v[1]) * (u[2] + v[2]); 01375 normal[1] += (u[2] - v[2]) * (u[0] + v[0]); 01376 normal[2] += (u[0] - v[0]) * (u[1] + v[1]); 01377 } 01378 if (normalize) { 01379 p = normal[0]*normal[0] + normal[1]*normal[1] + normal[2]*normal[2]; 01380 p = (float) (1.0 / sqrt(p)); 01381 normal[0] *= p; 01382 normal[1] *= p; 01383 normal[2] *= p; 01384 } 01385 } 01386 01387 int stb_box_face_vertex_axis_side(int face_number, int vertex_number, int axis) 01388 { 01389 static int box_vertices[6][4][3] = 01390 { 01391 { { 1,1,1 }, { 1,0,1 }, { 1,0,0 }, { 1,1,0 } }, 01392 { { 0,0,0 }, { 0,0,1 }, { 0,1,1 }, { 0,1,0 } }, 01393 { { 0,0,0 }, { 0,1,0 }, { 1,1,0 }, { 1,0,0 } }, 01394 { { 0,0,0 }, { 1,0,0 }, { 1,0,1 }, { 0,0,1 } }, 01395 { { 1,1,1 }, { 0,1,1 }, { 0,0,1 }, { 1,0,1 } }, 01396 { { 1,1,1 }, { 1,1,0 }, { 0,1,0 }, { 0,1,1 } }, 01397 }; 01398 assert(face_number >= 0 && face_number < 6); 01399 assert(vertex_number >= 0 && vertex_number < 4); 01400 assert(axis >= 0 && axis < 3); 01401 return box_vertices[face_number][vertex_number][axis]; 01402 } 01403 01404 void stb_linear_controller(float *curpos, float target_pos, float acc, float deacc, float dt) 01405 { 01406 float sign = 1, p, cp = *curpos; 01407 if (cp == target_pos) return; 01408 if (target_pos < cp) { 01409 target_pos = -target_pos; 01410 cp = -cp; 01411 sign = -1; 01412 } 01413 // first decelerate 01414 if (cp < 0) { 01415 p = cp + deacc * dt; 01416 if (p > 0) { 01417 p = 0; 01418 dt = dt - cp / deacc; 01419 if (dt < 0) dt = 0; 01420 } else { 01421 dt = 0; 01422 } 01423 cp = p; 01424 } 01425 // now accelerate 01426 p = cp + acc*dt; 01427 if (p > target_pos) p = target_pos; 01428 *curpos = p * sign; 01429 // @TODO: testing 01430 } 01431 01432 float stb_quadratic_controller(float target_pos, float curpos, float maxvel, float maxacc, float dt, float *curvel) 01433 { 01434 return 0; // @TODO 01435 } 01436 01437 int stb_float_eq(float x, float y, float delta, int max_ulps) 01438 { 01439 if (fabs(x-y) <= delta) return 1; 01440 if (abs(*(int *)&x - *(int *)&y) <= max_ulps) return 1; 01441 return 0; 01442 } 01443 01444 int stb_is_prime(unsigned int m) 01445 { 01446 unsigned int i,j; 01447 if (m < 2) return 0; 01448 if (m == 2) return 1; 01449 if (!(m & 1)) return 0; 01450 if (m % 3 == 0) return (m == 3); 01451 for (i=5; (j=i*i), j <= m && j > i; i += 6) { 01452 if (m % i == 0) return 0; 01453 if (m % (i+2) == 0) return 0; 01454 } 01455 return 1; 01456 } 01457 01458 unsigned int stb_power_of_two_nearest_prime(int n) 01459 { 01460 static signed char tab[32] = { 0,0,0,0,1,0,-1,0,1,-1,-1,3,-1,0,-1,2,1, 01461 0,2,0,-1,-4,-1,5,-1,18,-2,15,2,-1,2,0 }; 01462 if (!tab[0]) { 01463 int i; 01464 for (i=0; i < 32; ++i) 01465 tab[i] = (1 << i) + 2*tab[i] - 1; 01466 tab[1] = 2; 01467 tab[0] = 1; 01468 } 01469 if (n >= 32) return 0xfffffffb; 01470 return tab[n]; 01471 } 01472 01473 double stb_linear_remap(double x, double x_min, double x_max, 01474 double out_min, double out_max) 01475 { 01476 return stb_lerp(stb_unlerp(x,x_min,x_max),out_min,out_max); 01477 } 01478 #endif 01479 01480 // create a macro so it's faster, but you can get at the function pointer 01481 #define stb_linear_remap(t,a,b,c,d) stb_lerp(stb_unlerp(t,a,b),c,d) 01482 01483 01485 // 01486 // bit operations 01487 // 01488 01489 #define stb_big32(c) (((c)[0]<<24) + (c)[1]*65536 + (c)[2]*256 + (c)[3]) 01490 #define stb_little32(c) (((c)[3]<<24) + (c)[2]*65536 + (c)[1]*256 + (c)[0]) 01491 #define stb_big16(c) ((c)[0]*256 + (c)[1]) 01492 #define stb_little16(c) ((c)[1]*256 + (c)[0]) 01493 01494 STB_EXTERN int stb_bitcount(unsigned int a); 01495 STB_EXTERN unsigned int stb_bitreverse8(unsigned char n); 01496 STB_EXTERN unsigned int stb_bitreverse(unsigned int n); 01497 01498 STB_EXTERN int stb_is_pow2(size_t); 01499 STB_EXTERN int stb_log2_ceil(size_t); 01500 STB_EXTERN int stb_log2_floor(size_t); 01501 01502 STB_EXTERN int stb_lowbit8(unsigned int n); 01503 STB_EXTERN int stb_highbit8(unsigned int n); 01504 01505 #ifdef STB_DEFINE 01506 int stb_bitcount(unsigned int a) 01507 { 01508 a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 01509 a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 01510 a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits 01511 a = (a + (a >> 8)); // max 16 per 8 bits 01512 a = (a + (a >> 16)); // max 32 per 8 bits 01513 return a & 0xff; 01514 } 01515 01516 unsigned int stb_bitreverse8(unsigned char n) 01517 { 01518 n = ((n & 0xAA) >> 1) + ((n & 0x55) << 1); 01519 n = ((n & 0xCC) >> 2) + ((n & 0x33) << 2); 01520 return (unsigned char) ((n >> 4) + (n << 4)); 01521 } 01522 01523 unsigned int stb_bitreverse(unsigned int n) 01524 { 01525 n = ((n & 0xAAAAAAAA) >> 1) | ((n & 0x55555555) << 1); 01526 n = ((n & 0xCCCCCCCC) >> 2) | ((n & 0x33333333) << 2); 01527 n = ((n & 0xF0F0F0F0) >> 4) | ((n & 0x0F0F0F0F) << 4); 01528 n = ((n & 0xFF00FF00) >> 8) | ((n & 0x00FF00FF) << 8); 01529 return (n >> 16) | (n << 16); 01530 } 01531 01532 int stb_is_pow2(size_t n) 01533 { 01534 return (n & (n-1)) == 0; 01535 } 01536 01537 // tricky use of 4-bit table to identify 5 bit positions (note the '-1') 01538 // 3-bit table would require another tree level; 5-bit table wouldn't save one 01539 #if defined(_WIN32) && !defined(__MINGW32__) 01540 #pragma warning(push) 01541 #pragma warning(disable: 4035) // disable warning about no return value 01542 int stb_log2_floor(size_t n) 01543 { 01544 #if _MSC_VER > 1700 01545 unsigned long i; 01546 #ifdef STB_PTR64 01547 _BitScanReverse64(&i, n); 01548 #else 01549 _BitScanReverse(&i, n); 01550 #endif 01551 return i != 0 ? i : -1; 01552 #else 01553 __asm { 01554 bsr eax,n 01555 jnz done 01556 mov eax,-1 01557 } 01558 done:; 01559 #endif 01560 } 01561 #pragma warning(pop) 01562 #else 01563 int stb_log2_floor(size_t n) 01564 { 01565 static signed char log2_4[16] = { -1,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3 }; 01566 01567 #ifdef STB_PTR64 01568 if (n >= ((size_t) 1u << 32)) 01569 return stb_log2_floor(n >> 32); 01570 #endif 01571 01572 // 2 compares if n < 16, 3 compares otherwise 01573 if (n < (1U << 14)) 01574 if (n < (1U << 4)) return 0 + log2_4[n ]; 01575 else if (n < (1U << 9)) return 5 + log2_4[n >> 5]; 01576 else return 10 + log2_4[n >> 10]; 01577 else if (n < (1U << 24)) 01578 if (n < (1U << 19)) return 15 + log2_4[n >> 15]; 01579 else return 20 + log2_4[n >> 20]; 01580 else if (n < (1U << 29)) return 25 + log2_4[n >> 25]; 01581 else return 30 + log2_4[n >> 30]; 01582 } 01583 #endif 01584 01585 // define ceil from floor 01586 int stb_log2_ceil(size_t n) 01587 { 01588 if (stb_is_pow2(n)) return stb_log2_floor(n); 01589 else return 1 + stb_log2_floor(n); 01590 } 01591 01592 int stb_highbit8(unsigned int n) 01593 { 01594 return stb_log2_ceil(n&255); 01595 } 01596 01597 int stb_lowbit8(unsigned int n) 01598 { 01599 static signed char lowbit4[16] = { -1,0,1,0, 2,0,1,0, 3,0,1,0, 2,0,1,0 }; 01600 int k = lowbit4[n & 15]; 01601 if (k >= 0) return k; 01602 k = lowbit4[(n >> 4) & 15]; 01603 if (k >= 0) return k+4; 01604 return k; 01605 } 01606 #endif 01607 01608 01609 01611 // 01612 // qsort Compare Routines 01613 // 01614 01615 #ifdef _WIN32 01616 #define stb_stricmp(a,b) stb_p_stricmp(a,b) 01617 #define stb_strnicmp(a,b,n) stb_p_strnicmp(a,b,n) 01618 #else 01619 #define stb_stricmp(a,b) strcasecmp(a,b) 01620 #define stb_strnicmp(a,b,n) strncasecmp(a,b,n) 01621 #endif 01622 01623 01624 STB_EXTERN int (*stb_intcmp(int offset))(const void *a, const void *b); 01625 STB_EXTERN int (*stb_intcmprev(int offset))(const void *a, const void *b); 01626 STB_EXTERN int (*stb_qsort_strcmp(int offset))(const void *a, const void *b); 01627 STB_EXTERN int (*stb_qsort_stricmp(int offset))(const void *a, const void *b); 01628 STB_EXTERN int (*stb_floatcmp(int offset))(const void *a, const void *b); 01629 STB_EXTERN int (*stb_doublecmp(int offset))(const void *a, const void *b); 01630 STB_EXTERN int (*stb_charcmp(int offset))(const void *a, const void *b); 01631 01632 #ifdef STB_DEFINE 01633 static int stb__intcmpoffset, stb__ucharcmpoffset, stb__strcmpoffset; 01634 static int stb__floatcmpoffset, stb__doublecmpoffset; 01635 static int stb__memcmpoffset, stb__memcmpsize; 01636 01637 int stb__intcmp(const void *a, const void *b) 01638 { 01639 const int p = *(const int *) ((const char *) a + stb__intcmpoffset); 01640 const int q = *(const int *) ((const char *) b + stb__intcmpoffset); 01641 return p < q ? -1 : p > q; 01642 } 01643 01644 int stb__intcmprev(const void *a, const void *b) 01645 { 01646 const int p = *(const int *) ((const char *) a + stb__intcmpoffset); 01647 const int q = *(const int *) ((const char *) b + stb__intcmpoffset); 01648 return q < p ? -1 : q > p; 01649 } 01650 01651 int stb__ucharcmp(const void *a, const void *b) 01652 { 01653 const int p = *(const unsigned char *) ((const char *) a + stb__ucharcmpoffset); 01654 const int q = *(const unsigned char *) ((const char *) b + stb__ucharcmpoffset); 01655 return p < q ? -1 : p > q; 01656 } 01657 01658 int stb__floatcmp(const void *a, const void *b) 01659 { 01660 const float p = *(const float *) ((const char *) a + stb__floatcmpoffset); 01661 const float q = *(const float *) ((const char *) b + stb__floatcmpoffset); 01662 return p < q ? -1 : p > q; 01663 } 01664 01665 int stb__doublecmp(const void *a, const void *b) 01666 { 01667 const double p = *(const double *) ((const char *) a + stb__doublecmpoffset); 01668 const double q = *(const double *) ((const char *) b + stb__doublecmpoffset); 01669 return p < q ? -1 : p > q; 01670 } 01671 01672 int stb__qsort_strcmp(const void *a, const void *b) 01673 { 01674 const char *p = *(const char **) ((const char *) a + stb__strcmpoffset); 01675 const char *q = *(const char **) ((const char *) b + stb__strcmpoffset); 01676 return strcmp(p,q); 01677 } 01678 01679 int stb__qsort_stricmp(const void *a, const void *b) 01680 { 01681 const char *p = *(const char **) ((const char *) a + stb__strcmpoffset); 01682 const char *q = *(const char **) ((const char *) b + stb__strcmpoffset); 01683 return stb_stricmp(p,q); 01684 } 01685 01686 int stb__memcmp(const void *a, const void *b) 01687 { 01688 return memcmp((char *) a + stb__memcmpoffset, (char *) b + stb__memcmpoffset, stb__memcmpsize); 01689 } 01690 01691 int (*stb_intcmp(int offset))(const void *, const void *) 01692 { 01693 stb__intcmpoffset = offset; 01694 return &stb__intcmp; 01695 } 01696 01697 int (*stb_intcmprev(int offset))(const void *, const void *) 01698 { 01699 stb__intcmpoffset = offset; 01700 return &stb__intcmprev; 01701 } 01702 01703 int (*stb_ucharcmp(int offset))(const void *, const void *) 01704 { 01705 stb__ucharcmpoffset = offset; 01706 return &stb__ucharcmp; 01707 } 01708 01709 int (*stb_qsort_strcmp(int offset))(const void *, const void *) 01710 { 01711 stb__strcmpoffset = offset; 01712 return &stb__qsort_strcmp; 01713 } 01714 01715 int (*stb_qsort_stricmp(int offset))(const void *, const void *) 01716 { 01717 stb__strcmpoffset = offset; 01718 return &stb__qsort_stricmp; 01719 } 01720 01721 int (*stb_floatcmp(int offset))(const void *, const void *) 01722 { 01723 stb__floatcmpoffset = offset; 01724 return &stb__floatcmp; 01725 } 01726 01727 int (*stb_doublecmp(int offset))(const void *, const void *) 01728 { 01729 stb__doublecmpoffset = offset; 01730 return &stb__doublecmp; 01731 } 01732 01733 int (*stb_memcmp(int offset, int size))(const void *, const void *) 01734 { 01735 stb__memcmpoffset = offset; 01736 stb__memcmpsize = size; 01737 return &stb__memcmp; 01738 } 01739 #endif 01740 01742 // 01743 // Binary Search Toolkit 01744 // 01745 01746 typedef struct 01747 { 01748 int minval, maxval, guess; 01749 int mode, step; 01750 } stb_search; 01751 01752 STB_EXTERN int stb_search_binary(stb_search *s, int minv, int maxv, int find_smallest); 01753 STB_EXTERN int stb_search_open(stb_search *s, int minv, int find_smallest); 01754 STB_EXTERN int stb_probe(stb_search *s, int compare, int *result); // return 0 when done 01755 01756 #ifdef STB_DEFINE 01757 enum 01758 { 01759 STB_probe_binary_smallest, 01760 STB_probe_binary_largest, 01761 STB_probe_open_smallest, 01762 STB_probe_open_largest, 01763 }; 01764 01765 static int stb_probe_guess(stb_search *s, int *result) 01766 { 01767 switch(s->mode) { 01768 case STB_probe_binary_largest: 01769 if (s->minval == s->maxval) { 01770 *result = s->minval; 01771 return 0; 01772 } 01773 assert(s->minval < s->maxval); 01774 // if a < b, then a < p <= b 01775 s->guess = s->minval + (((unsigned) s->maxval - s->minval + 1) >> 1); 01776 break; 01777 01778 case STB_probe_binary_smallest: 01779 if (s->minval == s->maxval) { 01780 *result = s->minval; 01781 return 0; 01782 } 01783 assert(s->minval < s->maxval); 01784 // if a < b, then a <= p < b 01785 s->guess = s->minval + (((unsigned) s->maxval - s->minval) >> 1); 01786 break; 01787 case STB_probe_open_smallest: 01788 case STB_probe_open_largest: 01789 s->guess = s->maxval; // guess the current maxval 01790 break; 01791 } 01792 *result = s->guess; 01793 return 1; 01794 } 01795 01796 int stb_probe(stb_search *s, int compare, int *result) 01797 { 01798 switch(s->mode) { 01799 case STB_probe_open_smallest: 01800 case STB_probe_open_largest: { 01801 if (compare <= 0) { 01802 // then it lies within minval & maxval 01803 if (s->mode == STB_probe_open_smallest) 01804 s->mode = STB_probe_binary_smallest; 01805 else 01806 s->mode = STB_probe_binary_largest; 01807 } else { 01808 // otherwise, we need to probe larger 01809 s->minval = s->maxval + 1; 01810 s->maxval = s->minval + s->step; 01811 s->step += s->step; 01812 } 01813 break; 01814 } 01815 case STB_probe_binary_smallest: { 01816 // if compare < 0, then s->minval <= a < p 01817 // if compare = 0, then s->minval <= a <= p 01818 // if compare > 0, then p < a <= s->maxval 01819 if (compare <= 0) 01820 s->maxval = s->guess; 01821 else 01822 s->minval = s->guess+1; 01823 break; 01824 } 01825 case STB_probe_binary_largest: { 01826 // if compare < 0, then s->minval <= a < p 01827 // if compare = 0, then p <= a <= s->maxval 01828 // if compare > 0, then p < a <= s->maxval 01829 if (compare < 0) 01830 s->maxval = s->guess-1; 01831 else 01832 s->minval = s->guess; 01833 break; 01834 } 01835 } 01836 return stb_probe_guess(s, result); 01837 } 01838 01839 int stb_search_binary(stb_search *s, int minv, int maxv, int find_smallest) 01840 { 01841 int r; 01842 if (maxv < minv) return minv-1; 01843 s->minval = minv; 01844 s->maxval = maxv; 01845 s->mode = find_smallest ? STB_probe_binary_smallest : STB_probe_binary_largest; 01846 stb_probe_guess(s, &r); 01847 return r; 01848 } 01849 01850 int stb_search_open(stb_search *s, int minv, int find_smallest) 01851 { 01852 int r; 01853 s->step = 4; 01854 s->minval = minv; 01855 s->maxval = minv+s->step; 01856 s->mode = find_smallest ? STB_probe_open_smallest : STB_probe_open_largest; 01857 stb_probe_guess(s, &r); 01858 return r; 01859 } 01860 #endif 01861 01863 // 01864 // String Processing 01865 // 01866 01867 #define stb_prefixi(s,t) (0==stb_strnicmp((s),(t),strlen(t))) 01868 01869 enum stb_splitpath_flag 01870 { 01871 STB_PATH = 1, 01872 STB_FILE = 2, 01873 STB_EXT = 4, 01874 STB_PATH_FILE = STB_PATH + STB_FILE, 01875 STB_FILE_EXT = STB_FILE + STB_EXT, 01876 STB_EXT_NO_PERIOD = 8, 01877 }; 01878 01879 STB_EXTERN char * stb_skipwhite(char *s); 01880 STB_EXTERN char * stb_trimwhite(char *s); 01881 STB_EXTERN char * stb_skipnewline(char *s); 01882 STB_EXTERN char * stb_strncpy(char *s, char *t, int n); 01883 STB_EXTERN char * stb_substr(char *t, int n); 01884 STB_EXTERN char * stb_duplower(char *s); 01885 STB_EXTERN void stb_tolower (char *s); 01886 STB_EXTERN char * stb_strchr2 (char *s, char p1, char p2); 01887 STB_EXTERN char * stb_strrchr2(char *s, char p1, char p2); 01888 STB_EXTERN char * stb_strtok(char *output, char *src, char *delimit); 01889 STB_EXTERN char * stb_strtok_keep(char *output, char *src, char *delimit); 01890 STB_EXTERN char * stb_strtok_invert(char *output, char *src, char *allowed); 01891 STB_EXTERN char * stb_dupreplace(char *s, char *find, char *replace); 01892 STB_EXTERN void stb_replaceinplace(char *s, char *find, char *replace); 01893 STB_EXTERN char * stb_splitpath(char *output, char *src, int flag); 01894 STB_EXTERN char * stb_splitpathdup(char *src, int flag); 01895 STB_EXTERN char * stb_replacedir(char *output, char *src, char *dir); 01896 STB_EXTERN char * stb_replaceext(char *output, char *src, char *ext); 01897 STB_EXTERN void stb_fixpath(char *path); 01898 STB_EXTERN char * stb_shorten_path_readable(char *path, int max_len); 01899 STB_EXTERN int stb_suffix (char *s, char *t); 01900 STB_EXTERN int stb_suffixi(char *s, char *t); 01901 STB_EXTERN int stb_prefix (char *s, char *t); 01902 STB_EXTERN char * stb_strichr(char *s, char t); 01903 STB_EXTERN char * stb_stristr(char *s, char *t); 01904 STB_EXTERN int stb_prefix_count(char *s, char *t); 01905 STB_EXTERN const char * stb_plural(int n); // "s" or "" 01906 STB_EXTERN size_t stb_strscpy(char *d, const char *s, size_t n); 01907 01908 STB_EXTERN char **stb_tokens(char *src, char *delimit, int *count); 01909 STB_EXTERN char **stb_tokens_nested(char *src, char *delimit, int *count, char *nest_in, char *nest_out); 01910 STB_EXTERN char **stb_tokens_nested_empty(char *src, char *delimit, int *count, char *nest_in, char *nest_out); 01911 STB_EXTERN char **stb_tokens_allowempty(char *src, char *delimit, int *count); 01912 STB_EXTERN char **stb_tokens_stripwhite(char *src, char *delimit, int *count); 01913 STB_EXTERN char **stb_tokens_withdelim(char *src, char *delimit, int *count); 01914 STB_EXTERN char **stb_tokens_quoted(char *src, char *delimit, int *count); 01915 // with 'quoted', allow delimiters to appear inside quotation marks, and don't 01916 // strip whitespace inside them (and we delete the quotation marks unless they 01917 // appear back to back, in which case they're considered escaped) 01918 01919 #ifdef STB_DEFINE 01920 01921 size_t stb_strscpy(char *d, const char *s, size_t n) 01922 { 01923 size_t len = strlen(s); 01924 if (len >= n) { 01925 if (n) d[0] = 0; 01926 return 0; 01927 } 01928 stb_p_strcpy_s(d,n+1,s); 01929 return len + 1; 01930 } 01931 01932 const char *stb_plural(int n) 01933 { 01934 return n == 1 ? "" : "s"; 01935 } 01936 01937 int stb_prefix(char *s, char *t) 01938 { 01939 while (*t) 01940 if (*s++ != *t++) 01941 return STB_FALSE; 01942 return STB_TRUE; 01943 } 01944 01945 int stb_prefix_count(char *s, char *t) 01946 { 01947 int c=0; 01948 while (*t) { 01949 if (*s++ != *t++) 01950 break; 01951 ++c; 01952 } 01953 return c; 01954 } 01955 01956 int stb_suffix(char *s, char *t) 01957 { 01958 size_t n = strlen(s); 01959 size_t m = strlen(t); 01960 if (m <= n) 01961 return 0 == strcmp(s+n-m, t); 01962 else 01963 return 0; 01964 } 01965 01966 int stb_suffixi(char *s, char *t) 01967 { 01968 size_t n = strlen(s); 01969 size_t m = strlen(t); 01970 if (m <= n) 01971 return 0 == stb_stricmp(s+n-m, t); 01972 else 01973 return 0; 01974 } 01975 01976 // originally I was using this table so that I could create known sentinel 01977 // values--e.g. change whitetable[0] to be true if I was scanning for whitespace, 01978 // and false if I was scanning for nonwhite. I don't appear to be using that 01979 // functionality anymore (I do for tokentable, though), so just replace it 01980 // with isspace() 01981 char *stb_skipwhite(char *s) 01982 { 01983 while (isspace((unsigned char) *s)) ++s; 01984 return s; 01985 } 01986 01987 char *stb_skipnewline(char *s) 01988 { 01989 if (s[0] == '\r' || s[0] == '\n') { 01990 if (s[0]+s[1] == '\r' + '\n') ++s; 01991 ++s; 01992 } 01993 return s; 01994 } 01995 01996 char *stb_trimwhite(char *s) 01997 { 01998 int i,n; 01999 s = stb_skipwhite(s); 02000 n = (int) strlen(s); 02001 for (i=n-1; i >= 0; --i) 02002 if (!isspace(s[i])) 02003 break; 02004 s[i+1] = 0; 02005 return s; 02006 } 02007 02008 char *stb_strncpy(char *s, char *t, int n) 02009 { 02010 stb_p_strncpy_s(s,n+1,t,n); 02011 s[n] = 0; 02012 return s; 02013 } 02014 02015 char *stb_substr(char *t, int n) 02016 { 02017 char *a; 02018 int z = (int) strlen(t); 02019 if (z < n) n = z; 02020 a = (char *) malloc(n+1); 02021 stb_p_strncpy_s(a,n+1,t,n); 02022 a[n] = 0; 02023 return a; 02024 } 02025 02026 char *stb_duplower(char *s) 02027 { 02028 char *p = stb_p_strdup(s), *q = p; 02029 while (*q) { 02030 *q = tolower(*q); 02031 ++q; 02032 } 02033 return p; 02034 } 02035 02036 void stb_tolower(char *s) 02037 { 02038 while (*s) { 02039 *s = tolower(*s); 02040 ++s; 02041 } 02042 } 02043 02044 char *stb_strchr2(char *s, char x, char y) 02045 { 02046 for(; *s; ++s) 02047 if (*s == x || *s == y) 02048 return s; 02049 return NULL; 02050 } 02051 02052 char *stb_strrchr2(char *s, char x, char y) 02053 { 02054 char *r = NULL; 02055 for(; *s; ++s) 02056 if (*s == x || *s == y) 02057 r = s; 02058 return r; 02059 } 02060 02061 char *stb_strichr(char *s, char t) 02062 { 02063 if (tolower(t) == toupper(t)) 02064 return strchr(s,t); 02065 return stb_strchr2(s, (char) tolower(t), (char) toupper(t)); 02066 } 02067 02068 char *stb_stristr(char *s, char *t) 02069 { 02070 size_t n = strlen(t); 02071 char *z; 02072 if (n==0) return s; 02073 while ((z = stb_strichr(s, *t)) != NULL) { 02074 if (0==stb_strnicmp(z, t, n)) 02075 return z; 02076 s = z+1; 02077 } 02078 return NULL; 02079 } 02080 02081 static char *stb_strtok_raw(char *output, char *src, char *delimit, int keep, int invert) 02082 { 02083 if (invert) { 02084 while (*src && strchr(delimit, *src) != NULL) { 02085 *output++ = *src++; 02086 } 02087 } else { 02088 while (*src && strchr(delimit, *src) == NULL) { 02089 *output++ = *src++; 02090 } 02091 } 02092 *output = 0; 02093 if (keep) 02094 return src; 02095 else 02096 return *src ? src+1 : src; 02097 } 02098 02099 char *stb_strtok(char *output, char *src, char *delimit) 02100 { 02101 return stb_strtok_raw(output, src, delimit, 0, 0); 02102 } 02103 02104 char *stb_strtok_keep(char *output, char *src, char *delimit) 02105 { 02106 return stb_strtok_raw(output, src, delimit, 1, 0); 02107 } 02108 02109 char *stb_strtok_invert(char *output, char *src, char *delimit) 02110 { 02111 return stb_strtok_raw(output, src, delimit, 1,1); 02112 } 02113 02114 static char **stb_tokens_raw(char *src_, char *delimit, int *count, 02115 int stripwhite, int allow_empty, char *start, char *end) 02116 { 02117 int nested = 0; 02118 unsigned char *src = (unsigned char *) src_; 02119 static char stb_tokentable[256]; // rely on static initializion to 0 02120 static char stable[256],etable[256]; 02121 char *out; 02122 char **result; 02123 int num=0; 02124 unsigned char *s; 02125 02126 s = (unsigned char *) delimit; while (*s) stb_tokentable[*s++] = 1; 02127 if (start) { 02128 s = (unsigned char *) start; while (*s) stable[*s++] = 1; 02129 s = (unsigned char *) end; if (s) while (*s) stable[*s++] = 1; 02130 s = (unsigned char *) end; if (s) while (*s) etable[*s++] = 1; 02131 } 02132 stable[0] = 1; 02133 02134 // two passes through: the first time, counting how many 02135 s = (unsigned char *) src; 02136 while (*s) { 02137 // state: just found delimiter 02138 // skip further delimiters 02139 if (!allow_empty) { 02140 stb_tokentable[0] = 0; 02141 while (stb_tokentable[*s]) 02142 ++s; 02143 if (!*s) break; 02144 } 02145 ++num; 02146 // skip further non-delimiters 02147 stb_tokentable[0] = 1; 02148 if (stripwhite == 2) { // quoted strings 02149 while (!stb_tokentable[*s]) { 02150 if (*s != '"') 02151 ++s; 02152 else { 02153 ++s; 02154 if (*s == '"') 02155 ++s; // "" -> ", not start a string 02156 else { 02157 // begin a string 02158 while (*s) { 02159 if (s[0] == '"') { 02160 if (s[1] == '"') s += 2; // "" -> " 02161 else { ++s; break; } // terminating " 02162 } else 02163 ++s; 02164 } 02165 } 02166 } 02167 } 02168 } else 02169 while (nested || !stb_tokentable[*s]) { 02170 if (stable[*s]) { 02171 if (!*s) break; 02172 if (end ? etable[*s] : nested) 02173 --nested; 02174 else 02175 ++nested; 02176 } 02177 ++s; 02178 } 02179 if (allow_empty) { 02180 if (*s) ++s; 02181 } 02182 } 02183 // now num has the actual count... malloc our output structure 02184 // need space for all the strings: strings won't be any longer than 02185 // original input, since for every '\0' there's at least one delimiter 02186 result = (char **) malloc(sizeof(*result) * (num+1) + (s-src+1)); 02187 if (result == NULL) return result; 02188 out = (char *) (result + (num+1)); 02189 // second pass: copy out the data 02190 s = (unsigned char *) src; 02191 num = 0; 02192 nested = 0; 02193 while (*s) { 02194 char *last_nonwhite; 02195 // state: just found delimiter 02196 // skip further delimiters 02197 if (!allow_empty) { 02198 stb_tokentable[0] = 0; 02199 if (stripwhite) 02200 while (stb_tokentable[*s] || isspace(*s)) 02201 ++s; 02202 else 02203 while (stb_tokentable[*s]) 02204 ++s; 02205 } else if (stripwhite) { 02206 while (isspace(*s)) ++s; 02207 } 02208 if (!*s) break; 02209 // we're past any leading delimiters and whitespace 02210 result[num] = out; 02211 ++num; 02212 // copy non-delimiters 02213 stb_tokentable[0] = 1; 02214 last_nonwhite = out-1; 02215 if (stripwhite == 2) { 02216 while (!stb_tokentable[*s]) { 02217 if (*s != '"') { 02218 if (!isspace(*s)) last_nonwhite = out; 02219 *out++ = *s++; 02220 } else { 02221 ++s; 02222 if (*s == '"') { 02223 if (!isspace(*s)) last_nonwhite = out; 02224 *out++ = *s++; // "" -> ", not start string 02225 } else { 02226 // begin a quoted string 02227 while (*s) { 02228 if (s[0] == '"') { 02229 if (s[1] == '"') { *out++ = *s; s += 2; } 02230 else { ++s; break; } // terminating " 02231 } else 02232 *out++ = *s++; 02233 } 02234 last_nonwhite = out-1; // all in quotes counts as non-white 02235 } 02236 } 02237 } 02238 } else { 02239 while (nested || !stb_tokentable[*s]) { 02240 if (!isspace(*s)) last_nonwhite = out; 02241 if (stable[*s]) { 02242 if (!*s) break; 02243 if (end ? etable[*s] : nested) 02244 --nested; 02245 else 02246 ++nested; 02247 } 02248 *out++ = *s++; 02249 } 02250 } 02251 02252 if (stripwhite) // rewind to last non-whitespace char 02253 out = last_nonwhite+1; 02254 *out++ = '\0'; 02255 02256 if (*s) ++s; // skip delimiter 02257 } 02258 s = (unsigned char *) delimit; while (*s) stb_tokentable[*s++] = 0; 02259 if (start) { 02260 s = (unsigned char *) start; while (*s) stable[*s++] = 1; 02261 s = (unsigned char *) end; if (s) while (*s) stable[*s++] = 1; 02262 s = (unsigned char *) end; if (s) while (*s) etable[*s++] = 1; 02263 } 02264 if (count != NULL) *count = num; 02265 result[num] = 0; 02266 return result; 02267 } 02268 02269 char **stb_tokens(char *src, char *delimit, int *count) 02270 { 02271 return stb_tokens_raw(src,delimit,count,0,0,0,0); 02272 } 02273 02274 char **stb_tokens_nested(char *src, char *delimit, int *count, char *nest_in, char *nest_out) 02275 { 02276 return stb_tokens_raw(src,delimit,count,0,0,nest_in,nest_out); 02277 } 02278 02279 char **stb_tokens_nested_empty(char *src, char *delimit, int *count, char *nest_in, char *nest_out) 02280 { 02281 return stb_tokens_raw(src,delimit,count,0,1,nest_in,nest_out); 02282 } 02283 02284 char **stb_tokens_allowempty(char *src, char *delimit, int *count) 02285 { 02286 return stb_tokens_raw(src,delimit,count,0,1,0,0); 02287 } 02288 02289 char **stb_tokens_stripwhite(char *src, char *delimit, int *count) 02290 { 02291 return stb_tokens_raw(src,delimit,count,1,1,0,0); 02292 } 02293 02294 char **stb_tokens_quoted(char *src, char *delimit, int *count) 02295 { 02296 return stb_tokens_raw(src,delimit,count,2,1,0,0); 02297 } 02298 02299 char *stb_dupreplace(char *src, char *find, char *replace) 02300 { 02301 size_t len_find = strlen(find); 02302 size_t len_replace = strlen(replace); 02303 int count = 0; 02304 02305 char *s,*p,*q; 02306 02307 s = strstr(src, find); 02308 if (s == NULL) return stb_p_strdup(src); 02309 do { 02310 ++count; 02311 s = strstr(s + len_find, find); 02312 } while (s != NULL); 02313 02314 p = (char *) malloc(strlen(src) + count * (len_replace - len_find) + 1); 02315 if (p == NULL) return p; 02316 q = p; 02317 s = src; 02318 for (;;) { 02319 char *t = strstr(s, find); 02320 if (t == NULL) { 02321 stb_p_strcpy_s(q,strlen(src)+count*(len_replace-len_find)+1,s); 02322 assert(strlen(p) == strlen(src) + count*(len_replace-len_find)); 02323 return p; 02324 } 02325 memcpy(q, s, t-s); 02326 q += t-s; 02327 memcpy(q, replace, len_replace); 02328 q += len_replace; 02329 s = t + len_find; 02330 } 02331 } 02332 02333 void stb_replaceinplace(char *src, char *find, char *replace) 02334 { 02335 size_t len_find = strlen(find); 02336 size_t len_replace = strlen(replace); 02337 int delta; 02338 02339 char *s,*p,*q; 02340 02341 delta = (int) (len_replace - len_find); 02342 assert(delta <= 0); 02343 if (delta > 0) return; 02344 02345 p = strstr(src, find); 02346 if (p == NULL) return; 02347 02348 s = q = p; 02349 while (*s) { 02350 memcpy(q, replace, len_replace); 02351 p += len_find; 02352 q += len_replace; 02353 s = strstr(p, find); 02354 if (s == NULL) s = p + strlen(p); 02355 memmove(q, p, s-p); 02356 q += s-p; 02357 p = s; 02358 } 02359 *q = 0; 02360 } 02361 02362 void stb_fixpath(char *path) 02363 { 02364 for(; *path; ++path) 02365 if (*path == '\\') 02366 *path = '/'; 02367 } 02368 02369 void stb__add_section(char *buffer, char *data, ptrdiff_t curlen, ptrdiff_t newlen) 02370 { 02371 if (newlen < curlen) { 02372 ptrdiff_t z1 = newlen >> 1, z2 = newlen-z1; 02373 memcpy(buffer, data, z1-1); 02374 buffer[z1-1] = '.'; 02375 buffer[z1-0] = '.'; 02376 memcpy(buffer+z1+1, data+curlen-z2+1, z2-1); 02377 } else 02378 memcpy(buffer, data, curlen); 02379 } 02380 02381 char * stb_shorten_path_readable(char *path, int len) 02382 { 02383 static char buffer[1024]; 02384 ptrdiff_t n = strlen(path),n1,n2,r1,r2; 02385 char *s; 02386 if (n <= len) return path; 02387 if (len > 1024) return path; 02388 s = stb_strrchr2(path, '/', '\\'); 02389 if (s) { 02390 n1 = s - path + 1; 02391 n2 = n - n1; 02392 ++s; 02393 } else { 02394 n1 = 0; 02395 n2 = n; 02396 s = path; 02397 } 02398 // now we need to reduce r1 and r2 so that they fit in len 02399 if (n1 < len>>1) { 02400 r1 = n1; 02401 r2 = len - r1; 02402 } else if (n2 < len >> 1) { 02403 r2 = n2; 02404 r1 = len - r2; 02405 } else { 02406 r1 = n1 * len / n; 02407 r2 = n2 * len / n; 02408 if (r1 < len>>2) r1 = len>>2, r2 = len-r1; 02409 if (r2 < len>>2) r2 = len>>2, r1 = len-r2; 02410 } 02411 assert(r1 <= n1 && r2 <= n2); 02412 if (n1) 02413 stb__add_section(buffer, path, n1, r1); 02414 stb__add_section(buffer+r1, s, n2, r2); 02415 buffer[len] = 0; 02416 return buffer; 02417 } 02418 02419 static char *stb__splitpath_raw(char *buffer, char *path, int flag) 02420 { 02421 ptrdiff_t len=0,x,y, n = (int) strlen(path), f1,f2; 02422 char *s = stb_strrchr2(path, '/', '\\'); 02423 char *t = strrchr(path, '.'); 02424 if (s && t && t < s) t = NULL; 02425 if (s) ++s; 02426 02427 if (flag == STB_EXT_NO_PERIOD) 02428 flag |= STB_EXT; 02429 02430 if (!(flag & (STB_PATH | STB_FILE | STB_EXT))) return NULL; 02431 02432 f1 = s == NULL ? 0 : s-path; // start of filename 02433 f2 = t == NULL ? n : t-path; // just past end of filename 02434 02435 if (flag & STB_PATH) { 02436 x = 0; if (f1 == 0 && flag == STB_PATH) len=2; 02437 } else if (flag & STB_FILE) { 02438 x = f1; 02439 } else { 02440 x = f2; 02441 if (flag & STB_EXT_NO_PERIOD) 02442 if (path[x] == '.') 02443 ++x; 02444 } 02445 02446 if (flag & STB_EXT) 02447 y = n; 02448 else if (flag & STB_FILE) 02449 y = f2; 02450 else 02451 y = f1; 02452 02453 if (buffer == NULL) { 02454 buffer = (char *) malloc(y-x + len + 1); 02455 if (!buffer) return NULL; 02456 } 02457 02458 if (len) { stb_p_strcpy_s(buffer, 3, "./"); return buffer; } 02459 stb_strncpy(buffer, path+(int)x, (int)(y-x)); 02460 return buffer; 02461 } 02462 02463 char *stb_splitpath(char *output, char *src, int flag) 02464 { 02465 return stb__splitpath_raw(output, src, flag); 02466 } 02467 02468 char *stb_splitpathdup(char *src, int flag) 02469 { 02470 return stb__splitpath_raw(NULL, src, flag); 02471 } 02472 02473 char *stb_replacedir(char *output, char *src, char *dir) 02474 { 02475 char buffer[4096]; 02476 stb_splitpath(buffer, src, STB_FILE | STB_EXT); 02477 if (dir) 02478 stb_p_sprintf(output stb_p_size(9999), "%s/%s", dir, buffer); 02479 else 02480 stb_p_strcpy_s(output, sizeof(buffer), buffer); // @UNSAFE 02481 return output; 02482 } 02483 02484 char *stb_replaceext(char *output, char *src, char *ext) 02485 { 02486 char buffer[4096]; 02487 stb_splitpath(buffer, src, STB_PATH | STB_FILE); 02488 if (ext) 02489 stb_p_sprintf(output stb_p_size(9999), "%s.%s", buffer, ext[0] == '.' ? ext+1 : ext); 02490 else 02491 stb_p_strcpy_s(output, sizeof(buffer), buffer); // @UNSAFE 02492 return output; 02493 } 02494 #endif 02495 02497 // 02498 // stb_alloc - hierarchical allocator 02499 // 02500 // inspired by http://swapped.cc/halloc 02501 // 02502 // 02503 // When you alloc a given block through stb_alloc, you have these choices: 02504 // 02505 // 1. does it have a parent? 02506 // 2. can it have children? 02507 // 3. can it be freed directly? 02508 // 4. is it transferrable? 02509 // 5. what is its alignment? 02510 // 02511 // Here are interesting combinations of those: 02512 // 02513 // children free transfer alignment 02514 // arena Y Y N n/a 02515 // no-overhead, chunked N N N normal 02516 // string pool alloc N N N 1 02517 // parent-ptr, chunked Y N N normal 02518 // low-overhead, unchunked N Y Y normal 02519 // general purpose alloc Y Y Y normal 02520 // 02521 // Unchunked allocations will probably return 16-aligned pointers. If 02522 // we 16-align the results, we have room for 4 pointers. For smaller 02523 // allocations that allow finer alignment, we can reduce the pointers. 02524 // 02525 // The strategy is that given a pointer, assuming it has a header (only 02526 // the no-overhead allocations have no header), we can determine the 02527 // type of the header fields, and the number of them, by stepping backwards 02528 // through memory and looking at the tags in the bottom bits. 02529 // 02530 // Implementation strategy: 02531 // chunked allocations come from the middle of chunks, and can't 02532 // be freed. thefore they do not need to be on a sibling chain. 02533 // they may need child pointers if they have children. 02534 // 02535 // chunked, with-children 02536 // void *parent; 02537 // 02538 // unchunked, no-children -- reduced storage 02539 // void *next_sibling; 02540 // void *prev_sibling_nextp; 02541 // 02542 // unchunked, general 02543 // void *first_child; 02544 // void *next_sibling; 02545 // void *prev_sibling_nextp; 02546 // void *chunks; 02547 // 02548 // so, if we code each of these fields with different bit patterns 02549 // (actually same one for next/prev/child), then we can identify which 02550 // each one is from the last field. 02551 02552 STB_EXTERN void stb_free(void *p); 02553 STB_EXTERN void *stb_malloc_global(size_t size); 02554 STB_EXTERN void *stb_malloc(void *context, size_t size); 02555 STB_EXTERN void *stb_malloc_nofree(void *context, size_t size); 02556 STB_EXTERN void *stb_malloc_leaf(void *context, size_t size); 02557 STB_EXTERN void *stb_malloc_raw(void *context, size_t size); 02558 STB_EXTERN void *stb_realloc(void *ptr, size_t newsize); 02559 02560 STB_EXTERN void stb_reassign(void *new_context, void *ptr); 02561 STB_EXTERN void stb_malloc_validate(void *p, void *parent); 02562 02563 extern int stb_alloc_chunk_size ; 02564 extern int stb_alloc_count_free ; 02565 extern int stb_alloc_count_alloc; 02566 extern int stb_alloc_alignment ; 02567 02568 #ifdef STB_DEFINE 02569 02570 int stb_alloc_chunk_size = 65536; 02571 int stb_alloc_count_free = 0; 02572 int stb_alloc_count_alloc = 0; 02573 int stb_alloc_alignment = -16; 02574 02575 typedef struct stb__chunk 02576 { 02577 struct stb__chunk *next; 02578 int data_left; 02579 int alloc; 02580 } stb__chunk; 02581 02582 typedef struct 02583 { 02584 void * next; 02585 void ** prevn; 02586 } stb__nochildren; 02587 02588 typedef struct 02589 { 02590 void ** prevn; 02591 void * child; 02592 void * next; 02593 stb__chunk *chunks; 02594 } stb__alloc; 02595 02596 typedef struct 02597 { 02598 stb__alloc *parent; 02599 } stb__chunked; 02600 02601 #define STB__PARENT 1 02602 #define STB__CHUNKS 2 02603 02604 typedef enum 02605 { 02606 STB__nochildren = 0, 02607 STB__chunked = STB__PARENT, 02608 STB__alloc = STB__CHUNKS, 02609 02610 STB__chunk_raw = 4, 02611 } stb__alloc_type; 02612 02613 // these functions set the bottom bits of a pointer efficiently 02614 #define STB__DECODE(x,v) ((void *) ((char *) (x) - (v))) 02615 #define STB__ENCODE(x,v) ((void *) ((char *) (x) + (v))) 02616 02617 #define stb__parent(z) (stb__alloc *) STB__DECODE((z)->parent, STB__PARENT) 02618 #define stb__chunks(z) (stb__chunk *) STB__DECODE((z)->chunks, STB__CHUNKS) 02619 02620 #define stb__setparent(z,p) (z)->parent = (stb__alloc *) STB__ENCODE((p), STB__PARENT) 02621 #define stb__setchunks(z,c) (z)->chunks = (stb__chunk *) STB__ENCODE((c), STB__CHUNKS) 02622 02623 static stb__alloc stb__alloc_global = 02624 { 02625 NULL, 02626 NULL, 02627 NULL, 02628 (stb__chunk *) STB__ENCODE(NULL, STB__CHUNKS) 02629 }; 02630 02631 static stb__alloc_type stb__identify(void *p) 02632 { 02633 void **q = (void **) p; 02634 return (stb__alloc_type) ((stb_uinta) q[-1] & 3); 02635 } 02636 02637 static void *** stb__prevn(void *p) 02638 { 02639 if (stb__identify(p) == STB__alloc) { 02640 stb__alloc *s = (stb__alloc *) p - 1; 02641 return &s->prevn; 02642 } else { 02643 stb__nochildren *s = (stb__nochildren *) p - 1; 02644 return &s->prevn; 02645 } 02646 } 02647 02648 void stb_free(void *p) 02649 { 02650 if (p == NULL) return; 02651 02652 // count frees so that unit tests can see what's happening 02653 ++stb_alloc_count_free; 02654 02655 switch(stb__identify(p)) { 02656 case STB__chunked: 02657 // freeing a chunked-block with children does nothing; 02658 // they only get freed when the parent does 02659 // surely this is wrong, and it should free them immediately? 02660 // otherwise how are they getting put on the right chain? 02661 return; 02662 case STB__nochildren: { 02663 stb__nochildren *s = (stb__nochildren *) p - 1; 02664 // unlink from sibling chain 02665 *(s->prevn) = s->next; 02666 if (s->next) 02667 *stb__prevn(s->next) = s->prevn; 02668 free(s); 02669 return; 02670 } 02671 case STB__alloc: { 02672 stb__alloc *s = (stb__alloc *) p - 1; 02673 stb__chunk *c, *n; 02674 void *q; 02675 02676 // unlink from sibling chain, if any 02677 *(s->prevn) = s->next; 02678 if (s->next) 02679 *stb__prevn(s->next) = s->prevn; 02680 02681 // first free chunks 02682 c = (stb__chunk *) stb__chunks(s); 02683 while (c != NULL) { 02684 n = c->next; 02685 stb_alloc_count_free += c->alloc; 02686 free(c); 02687 c = n; 02688 } 02689 02690 // validating 02691 stb__setchunks(s,NULL); 02692 s->prevn = NULL; 02693 s->next = NULL; 02694 02695 // now free children 02696 while ((q = s->child) != NULL) { 02697 stb_free(q); 02698 } 02699 02700 // now free self 02701 free(s); 02702 return; 02703 } 02704 default: 02705 assert(0); /* NOTREACHED */ 02706 } 02707 } 02708 02709 void stb_malloc_validate(void *p, void *parent) 02710 { 02711 if (p == NULL) return; 02712 02713 switch(stb__identify(p)) { 02714 case STB__chunked: 02715 return; 02716 case STB__nochildren: { 02717 stb__nochildren *n = (stb__nochildren *) p - 1; 02718 if (n->prevn) 02719 assert(*n->prevn == p); 02720 if (n->next) { 02721 assert(*stb__prevn(n->next) == &n->next); 02722 stb_malloc_validate(n, parent); 02723 } 02724 return; 02725 } 02726 case STB__alloc: { 02727 stb__alloc *s = (stb__alloc *) p - 1; 02728 02729 if (s->prevn) 02730 assert(*s->prevn == p); 02731 02732 if (s->child) { 02733 assert(*stb__prevn(s->child) == &s->child); 02734 stb_malloc_validate(s->child, p); 02735 } 02736 02737 if (s->next) { 02738 assert(*stb__prevn(s->next) == &s->next); 02739 stb_malloc_validate(s->next, parent); 02740 } 02741 return; 02742 } 02743 default: 02744 assert(0); /* NOTREACHED */ 02745 } 02746 } 02747 02748 static void * stb__try_chunk(stb__chunk *c, int size, int align, int pre_align) 02749 { 02750 char *memblock = (char *) (c+1), *q; 02751 stb_inta iq; 02752 int start_offset; 02753 02754 // we going to allocate at the end of the chunk, not the start. confusing, 02755 // but it means we don't need both a 'limit' and a 'cur', just a 'cur'. 02756 // the block ends at: p + c->data_left 02757 // then we move back by size 02758 start_offset = c->data_left - size; 02759 02760 // now we need to check the alignment of that 02761 q = memblock + start_offset; 02762 iq = (stb_inta) q; 02763 assert(sizeof(q) == sizeof(iq)); 02764 02765 // suppose align = 2 02766 // then we need to retreat iq far enough that (iq & (2-1)) == 0 02767 // to get (iq & (align-1)) = 0 requires subtracting (iq & (align-1)) 02768 02769 start_offset -= iq & (align-1); 02770 assert(((stb_uinta) (memblock+start_offset) & (align-1)) == 0); 02771 02772 // now, if that + pre_align works, go for it! 02773 start_offset -= pre_align; 02774 02775 if (start_offset >= 0) { 02776 c->data_left = start_offset; 02777 return memblock + start_offset; 02778 } 02779 02780 return NULL; 02781 } 02782 02783 static void stb__sort_chunks(stb__alloc *src) 02784 { 02785 // of the first two chunks, put the chunk with more data left in it first 02786 stb__chunk *c = stb__chunks(src), *d; 02787 if (c == NULL) return; 02788 d = c->next; 02789 if (d == NULL) return; 02790 if (c->data_left > d->data_left) return; 02791 02792 c->next = d->next; 02793 d->next = c; 02794 stb__setchunks(src, d); 02795 } 02796 02797 static void * stb__alloc_chunk(stb__alloc *src, int size, int align, int pre_align) 02798 { 02799 void *p; 02800 stb__chunk *c = stb__chunks(src); 02801 02802 if (c && size <= stb_alloc_chunk_size) { 02803 02804 p = stb__try_chunk(c, size, align, pre_align); 02805 if (p) { ++c->alloc; return p; } 02806 02807 // try a second chunk to reduce wastage 02808 if (c->next) { 02809 p = stb__try_chunk(c->next, size, align, pre_align); 02810 if (p) { ++c->alloc; return p; } 02811 02812 // put the bigger chunk first, since the second will get buried 02813 // the upshot of this is that, until it gets allocated from, chunk #2 02814 // is always the largest remaining chunk. (could formalize 02815 // this with a heap!) 02816 stb__sort_chunks(src); 02817 c = stb__chunks(src); 02818 } 02819 } 02820 02821 // allocate a new chunk 02822 { 02823 stb__chunk *n; 02824 02825 int chunk_size = stb_alloc_chunk_size; 02826 // we're going to allocate a new chunk to put this in 02827 if (size > chunk_size) 02828 chunk_size = size; 02829 02830 assert(sizeof(*n) + pre_align <= 16); 02831 02832 // loop trying to allocate a large enough chunk 02833 // the loop is because the alignment may cause problems if it's big... 02834 // and we don't know what our chunk alignment is going to be 02835 while (1) { 02836 n = (stb__chunk *) malloc(16 + chunk_size); 02837 if (n == NULL) return NULL; 02838 02839 n->data_left = chunk_size - sizeof(*n); 02840 02841 p = stb__try_chunk(n, size, align, pre_align); 02842 if (p != NULL) { 02843 n->next = c; 02844 stb__setchunks(src, n); 02845 02846 // if we just used up the whole block immediately, 02847 // move the following chunk up 02848 n->alloc = 1; 02849 if (size == chunk_size) 02850 stb__sort_chunks(src); 02851 02852 return p; 02853 } 02854 02855 free(n); 02856 chunk_size += 16+align; 02857 } 02858 } 02859 } 02860 02861 static stb__alloc * stb__get_context(void *context) 02862 { 02863 if (context == NULL) { 02864 return &stb__alloc_global; 02865 } else { 02866 int u = stb__identify(context); 02867 // if context is chunked, grab parent 02868 if (u == STB__chunked) { 02869 stb__chunked *s = (stb__chunked *) context - 1; 02870 return stb__parent(s); 02871 } else { 02872 return (stb__alloc *) context - 1; 02873 } 02874 } 02875 } 02876 02877 static void stb__insert_alloc(stb__alloc *src, stb__alloc *s) 02878 { 02879 s->prevn = &src->child; 02880 s->next = src->child; 02881 src->child = s+1; 02882 if (s->next) 02883 *stb__prevn(s->next) = &s->next; 02884 } 02885 02886 static void stb__insert_nochild(stb__alloc *src, stb__nochildren *s) 02887 { 02888 s->prevn = &src->child; 02889 s->next = src->child; 02890 src->child = s+1; 02891 if (s->next) 02892 *stb__prevn(s->next) = &s->next; 02893 } 02894 02895 static void * malloc_base(void *context, size_t size, stb__alloc_type t, int align) 02896 { 02897 void *p; 02898 02899 stb__alloc *src = stb__get_context(context); 02900 02901 if (align <= 0) { 02902 // compute worst-case C packed alignment 02903 // e.g. a 24-byte struct is 8-aligned 02904 int align_proposed = 1 << stb_lowbit8((unsigned int) size); 02905 02906 if (align_proposed < 0) 02907 align_proposed = 4; 02908 02909 if (align_proposed == 0) { 02910 if (size == 0) 02911 align_proposed = 1; 02912 else 02913 align_proposed = 256; 02914 } 02915 02916 // a negative alignment means 'don't align any larger 02917 // than this'; so -16 means we align 1,2,4,8, or 16 02918 02919 if (align < 0) { 02920 if (align_proposed > -align) 02921 align_proposed = -align; 02922 } 02923 02924 align = align_proposed; 02925 } 02926 02927 assert(stb_is_pow2(align)); 02928 02929 // don't cause misalignment when allocating nochildren 02930 if (t == STB__nochildren && align > 8) 02931 t = STB__alloc; 02932 02933 switch (t) { 02934 case STB__alloc: { 02935 stb__alloc *s = (stb__alloc *) malloc(size + sizeof(*s)); 02936 if (s == NULL) return NULL; 02937 p = s+1; 02938 s->child = NULL; 02939 stb__insert_alloc(src, s); 02940 02941 stb__setchunks(s,NULL); 02942 break; 02943 } 02944 02945 case STB__nochildren: { 02946 stb__nochildren *s = (stb__nochildren *) malloc(size + sizeof(*s)); 02947 if (s == NULL) return NULL; 02948 p = s+1; 02949 stb__insert_nochild(src, s); 02950 break; 02951 } 02952 02953 case STB__chunk_raw: { 02954 p = stb__alloc_chunk(src, (int) size, align, 0); 02955 if (p == NULL) return NULL; 02956 break; 02957 } 02958 02959 case STB__chunked: { 02960 stb__chunked *s; 02961 if (align < sizeof(stb_uintptr)) align = sizeof(stb_uintptr); 02962 s = (stb__chunked *) stb__alloc_chunk(src, (int) size, align, sizeof(*s)); 02963 if (s == NULL) return NULL; 02964 stb__setparent(s, src); 02965 p = s+1; 02966 break; 02967 } 02968 02969 default: p = NULL; assert(0); /* NOTREACHED */ 02970 } 02971 02972 ++stb_alloc_count_alloc; 02973 return p; 02974 } 02975 02976 void *stb_malloc_global(size_t size) 02977 { 02978 return malloc_base(NULL, size, STB__alloc, stb_alloc_alignment); 02979 } 02980 02981 void *stb_malloc(void *context, size_t size) 02982 { 02983 return malloc_base(context, size, STB__alloc, stb_alloc_alignment); 02984 } 02985 02986 void *stb_malloc_nofree(void *context, size_t size) 02987 { 02988 return malloc_base(context, size, STB__chunked, stb_alloc_alignment); 02989 } 02990 02991 void *stb_malloc_leaf(void *context, size_t size) 02992 { 02993 return malloc_base(context, size, STB__nochildren, stb_alloc_alignment); 02994 } 02995 02996 void *stb_malloc_raw(void *context, size_t size) 02997 { 02998 return malloc_base(context, size, STB__chunk_raw, stb_alloc_alignment); 02999 } 03000 03001 char *stb_malloc_string(void *context, size_t size) 03002 { 03003 return (char *) malloc_base(context, size, STB__chunk_raw, 1); 03004 } 03005 03006 void *stb_realloc(void *ptr, size_t newsize) 03007 { 03008 stb__alloc_type t; 03009 03010 if (ptr == NULL) return stb_malloc(NULL, newsize); 03011 if (newsize == 0) { stb_free(ptr); return NULL; } 03012 03013 t = stb__identify(ptr); 03014 assert(t == STB__alloc || t == STB__nochildren); 03015 03016 if (t == STB__alloc) { 03017 stb__alloc *s = (stb__alloc *) ptr - 1; 03018 03019 s = (stb__alloc *) realloc(s, newsize + sizeof(*s)); 03020 if (s == NULL) return NULL; 03021 03022 ptr = s+1; 03023 03024 // update pointers 03025 (*s->prevn) = ptr; 03026 if (s->next) 03027 *stb__prevn(s->next) = &s->next; 03028 03029 if (s->child) 03030 *stb__prevn(s->child) = &s->child; 03031 03032 return ptr; 03033 } else { 03034 stb__nochildren *s = (stb__nochildren *) ptr - 1; 03035 03036 s = (stb__nochildren *) realloc(ptr, newsize + sizeof(s)); 03037 if (s == NULL) return NULL; 03038 03039 // update pointers 03040 (*s->prevn) = s+1; 03041 if (s->next) 03042 *stb__prevn(s->next) = &s->next; 03043 03044 return s+1; 03045 } 03046 } 03047 03048 void *stb_realloc_c(void *context, void *ptr, size_t newsize) 03049 { 03050 if (ptr == NULL) return stb_malloc(context, newsize); 03051 if (newsize == 0) { stb_free(ptr); return NULL; } 03052 // @TODO: verify you haven't changed contexts 03053 return stb_realloc(ptr, newsize); 03054 } 03055 03056 void stb_reassign(void *new_context, void *ptr) 03057 { 03058 stb__alloc *src = stb__get_context(new_context); 03059 03060 stb__alloc_type t = stb__identify(ptr); 03061 assert(t == STB__alloc || t == STB__nochildren); 03062 03063 if (t == STB__alloc) { 03064 stb__alloc *s = (stb__alloc *) ptr - 1; 03065 03066 // unlink from old 03067 *(s->prevn) = s->next; 03068 if (s->next) 03069 *stb__prevn(s->next) = s->prevn; 03070 03071 stb__insert_alloc(src, s); 03072 } else { 03073 stb__nochildren *s = (stb__nochildren *) ptr - 1; 03074 03075 // unlink from old 03076 *(s->prevn) = s->next; 03077 if (s->next) 03078 *stb__prevn(s->next) = s->prevn; 03079 03080 stb__insert_nochild(src, s); 03081 } 03082 } 03083 03084 #endif 03085 03086 03088 // 03089 // stb_arr 03090 // 03091 // An stb_arr is directly useable as a pointer (use the actual type in your 03092 // definition), but when it resizes, it returns a new pointer and you can't 03093 // use the old one, so you have to be careful to copy-in-out as necessary. 03094 // 03095 // Use a NULL pointer as a 0-length array. 03096 // 03097 // float *my_array = NULL, *temp; 03098 // 03099 // // add elements on the end one at a time 03100 // stb_arr_push(my_array, 0.0f); 03101 // stb_arr_push(my_array, 1.0f); 03102 // stb_arr_push(my_array, 2.0f); 03103 // 03104 // assert(my_array[1] == 2.0f); 03105 // 03106 // // add an uninitialized element at the end, then assign it 03107 // *stb_arr_add(my_array) = 3.0f; 03108 // 03109 // // add three uninitialized elements at the end 03110 // temp = stb_arr_addn(my_array,3); 03111 // temp[0] = 4.0f; 03112 // temp[1] = 5.0f; 03113 // temp[2] = 6.0f; 03114 // 03115 // assert(my_array[5] == 5.0f); 03116 // 03117 // // remove the last one 03118 // stb_arr_pop(my_array); 03119 // 03120 // assert(stb_arr_len(my_array) == 6); 03121 03122 03123 #ifdef STB_MALLOC_WRAPPER 03124 #define STB__PARAMS , char *file, int line 03125 #define STB__ARGS , file, line 03126 #else 03127 #define STB__PARAMS 03128 #define STB__ARGS 03129 #endif 03130 03131 // calling this function allocates an empty stb_arr attached to p 03132 // (whereas NULL isn't attached to anything) 03133 STB_EXTERN void stb_arr_malloc(void **target, void *context); 03134 03135 // call this function with a non-NULL value to have all successive 03136 // stbs that are created be attached to the associated parent. Note 03137 // that once a given stb_arr is non-empty, it stays attached to its 03138 // current parent, even if you call this function again. 03139 // it turns the previous value, so you can restore it 03140 STB_EXTERN void* stb_arr_malloc_parent(void *p); 03141 03142 // simple functions written on top of other functions 03143 #define stb_arr_empty(a) ( stb_arr_len(a) == 0 ) 03144 #define stb_arr_add(a) ( stb_arr_addn((a),1) ) 03145 #define stb_arr_push(a,v) ( *stb_arr_add(a)=(v) ) 03146 03147 typedef struct 03148 { 03149 int len, limit; 03150 int stb_malloc; 03151 unsigned int signature; 03152 } stb__arr; 03153 03154 #define stb_arr_signature 0x51bada7b // ends with 0123 in decimal 03155 03156 // access the header block stored before the data 03157 #define stb_arrhead(a) /*lint --e(826)*/ (((stb__arr *) (a)) - 1) 03158 #define stb_arrhead2(a) /*lint --e(826)*/ (((stb__arr *) (a)) - 1) 03159 03160 #ifdef STB_DEBUG 03161 #define stb_arr_check(a) assert(!a || stb_arrhead(a)->signature == stb_arr_signature) 03162 #define stb_arr_check2(a) assert(!a || stb_arrhead2(a)->signature == stb_arr_signature) 03163 #else 03164 #define stb_arr_check(a) ((void) 0) 03165 #define stb_arr_check2(a) ((void) 0) 03166 #endif 03167 03168 // ARRAY LENGTH 03169 03170 // get the array length; special case if pointer is NULL 03171 #define stb_arr_len(a) (a ? stb_arrhead(a)->len : 0) 03172 #define stb_arr_len2(a) ((stb__arr *) (a) ? stb_arrhead2(a)->len : 0) 03173 #define stb_arr_lastn(a) (stb_arr_len(a)-1) 03174 03175 // check whether a given index is valid -- tests 0 <= i < stb_arr_len(a) 03176 #define stb_arr_valid(a,i) (a ? (int) (i) < stb_arrhead(a)->len : 0) 03177 03178 // change the array length so is is exactly N entries long, creating 03179 // uninitialized entries as needed 03180 #define stb_arr_setlen(a,n) \ 03181 (stb__arr_setlen((void **) &(a), sizeof(a[0]), (n))) 03182 03183 // change the array length so that N is a valid index (that is, so 03184 // it is at least N entries long), creating uninitialized entries as needed 03185 #define stb_arr_makevalid(a,n) \ 03186 (stb_arr_len(a) < (n)+1 ? stb_arr_setlen(a,(n)+1),(a) : (a)) 03187 03188 // remove the last element of the array, returning it 03189 #define stb_arr_pop(a) ((stb_arr_check(a), (a))[--stb_arrhead(a)->len]) 03190 03191 // access the last element in the array 03192 #define stb_arr_last(a) ((stb_arr_check(a), (a))[stb_arr_len(a)-1]) 03193 03194 // is iterator at end of list? 03195 #define stb_arr_end(a,i) ((i) >= &(a)[stb_arr_len(a)]) 03196 03197 // (internal) change the allocated length of the array 03198 #define stb_arr__grow(a,n) (stb_arr_check(a), stb_arrhead(a)->len += (n)) 03199 03200 // add N new uninitialized elements to the end of the array 03201 #define stb_arr__addn(a,n) /*lint --e(826)*/ \ 03202 ((stb_arr_len(a)+(n) > stb_arrcurmax(a)) \ 03203 ? (stb__arr_addlen((void **) &(a),sizeof(*a),(n)),0) \ 03204 : ((stb_arr__grow(a,n), 0))) 03205 03206 // add N new uninitialized elements to the end of the array, and return 03207 // a pointer to the first new one 03208 #define stb_arr_addn(a,n) (stb_arr__addn((a),n),(a)+stb_arr_len(a)-(n)) 03209 03210 // add N new uninitialized elements starting at index 'i' 03211 #define stb_arr_insertn(a,i,n) (stb__arr_insertn((void **) &(a), sizeof(*a), (i), (n))) 03212 03213 // insert an element at i 03214 #define stb_arr_insert(a,i,v) (stb__arr_insertn((void **) &(a), sizeof(*a), (i), (1)), ((a)[i] = v)) 03215 03216 // delete N elements from the middle starting at index 'i' 03217 #define stb_arr_deleten(a,i,n) (stb__arr_deleten((void **) &(a), sizeof(*a), (i), (n))) 03218 03219 // delete the i'th element 03220 #define stb_arr_delete(a,i) stb_arr_deleten(a,i,1) 03221 03222 // delete the i'th element, swapping down from the end 03223 #define stb_arr_fastdelete(a,i) \ 03224 (stb_swap(&a[i], &a[stb_arrhead(a)->len-1], sizeof(*a)), stb_arr_pop(a)) 03225 03226 03227 // ARRAY STORAGE 03228 03229 // get the array maximum storage; special case if NULL 03230 #define stb_arrcurmax(a) (a ? stb_arrhead(a)->limit : 0) 03231 #define stb_arrcurmax2(a) (a ? stb_arrhead2(a)->limit : 0) 03232 03233 // set the maxlength of the array to n in anticipation of further growth 03234 #define stb_arr_setsize(a,n) (stb_arr_check(a), stb__arr_setsize((void **) &(a),sizeof((a)[0]),n)) 03235 03236 // make sure maxlength is large enough for at least N new allocations 03237 #define stb_arr_atleast(a,n) (stb_arr_len(a)+(n) > stb_arrcurmax(a) \ 03238 ? stb_arr_setsize((a), (n)) : 0) 03239 03240 // make a copy of a given array (copies contents via 'memcpy'!) 03241 #define stb_arr_copy(a) stb__arr_copy(a, sizeof((a)[0])) 03242 03243 // compute the storage needed to store all the elements of the array 03244 #define stb_arr_storage(a) (stb_arr_len(a) * sizeof((a)[0])) 03245 03246 #define stb_arr_for(v,arr) for((v)=(arr); (v) < (arr)+stb_arr_len(arr); ++(v)) 03247 03248 // IMPLEMENTATION 03249 03250 STB_EXTERN void stb_arr_free_(void **p); 03251 STB_EXTERN void *stb__arr_copy_(void *p, int elem_size); 03252 STB_EXTERN void stb__arr_setsize_(void **p, int size, int limit STB__PARAMS); 03253 STB_EXTERN void stb__arr_setlen_(void **p, int size, int newlen STB__PARAMS); 03254 STB_EXTERN void stb__arr_addlen_(void **p, int size, int addlen STB__PARAMS); 03255 STB_EXTERN void stb__arr_deleten_(void **p, int size, int loc, int n STB__PARAMS); 03256 STB_EXTERN void stb__arr_insertn_(void **p, int size, int loc, int n STB__PARAMS); 03257 03258 #define stb_arr_free(p) stb_arr_free_((void **) &(p)) 03259 #define stb__arr_copy stb__arr_copy_ 03260 03261 #ifndef STB_MALLOC_WRAPPER 03262 #define stb__arr_setsize stb__arr_setsize_ 03263 #define stb__arr_setlen stb__arr_setlen_ 03264 #define stb__arr_addlen stb__arr_addlen_ 03265 #define stb__arr_deleten stb__arr_deleten_ 03266 #define stb__arr_insertn stb__arr_insertn_ 03267 #else 03268 #define stb__arr_addlen(p,s,n) stb__arr_addlen_(p,s,n,__FILE__,__LINE__) 03269 #define stb__arr_setlen(p,s,n) stb__arr_setlen_(p,s,n,__FILE__,__LINE__) 03270 #define stb__arr_setsize(p,s,n) stb__arr_setsize_(p,s,n,__FILE__,__LINE__) 03271 #define stb__arr_deleten(p,s,i,n) stb__arr_deleten_(p,s,i,n,__FILE__,__LINE__) 03272 #define stb__arr_insertn(p,s,i,n) stb__arr_insertn_(p,s,i,n,__FILE__,__LINE__) 03273 #endif 03274 03275 #ifdef STB_DEFINE 03276 static void *stb__arr_context; 03277 03278 void *stb_arr_malloc_parent(void *p) 03279 { 03280 void *q = stb__arr_context; 03281 stb__arr_context = p; 03282 return q; 03283 } 03284 03285 void stb_arr_malloc(void **target, void *context) 03286 { 03287 stb__arr *q = (stb__arr *) stb_malloc(context, sizeof(*q)); 03288 q->len = q->limit = 0; 03289 q->stb_malloc = 1; 03290 q->signature = stb_arr_signature; 03291 *target = (void *) (q+1); 03292 } 03293 03294 static void * stb__arr_malloc(int size) 03295 { 03296 if (stb__arr_context) 03297 return stb_malloc(stb__arr_context, size); 03298 return malloc(size); 03299 } 03300 03301 void * stb__arr_copy_(void *p, int elem_size) 03302 { 03303 stb__arr *q; 03304 if (p == NULL) return p; 03305 q = (stb__arr *) stb__arr_malloc(sizeof(*q) + elem_size * stb_arrhead2(p)->limit); 03306 stb_arr_check2(p); 03307 memcpy(q, stb_arrhead2(p), sizeof(*q) + elem_size * stb_arrhead2(p)->len); 03308 q->stb_malloc = !!stb__arr_context; 03309 return q+1; 03310 } 03311 03312 void stb_arr_free_(void **pp) 03313 { 03314 void *p = *pp; 03315 stb_arr_check2(p); 03316 if (p) { 03317 stb__arr *q = stb_arrhead2(p); 03318 if (q->stb_malloc) 03319 stb_free(q); 03320 else 03321 free(q); 03322 } 03323 *pp = NULL; 03324 } 03325 03326 static void stb__arrsize_(void **pp, int size, int limit, int len STB__PARAMS) 03327 { 03328 void *p = *pp; 03329 stb__arr *a; 03330 stb_arr_check2(p); 03331 if (p == NULL) { 03332 if (len == 0 && size == 0) return; 03333 a = (stb__arr *) stb__arr_malloc(sizeof(*a) + size*limit); 03334 a->limit = limit; 03335 a->len = len; 03336 a->stb_malloc = !!stb__arr_context; 03337 a->signature = stb_arr_signature; 03338 } else { 03339 a = stb_arrhead2(p); 03340 a->len = len; 03341 if (a->limit < limit) { 03342 void *p; 03343 if (a->limit >= 4 && limit < a->limit * 2) 03344 limit = a->limit * 2; 03345 if (a->stb_malloc) 03346 p = stb_realloc(a, sizeof(*a) + limit*size); 03347 else 03348 #ifdef STB_MALLOC_WRAPPER 03349 p = stb__realloc(a, sizeof(*a) + limit*size, file, line); 03350 #else 03351 p = realloc(a, sizeof(*a) + limit*size); 03352 #endif 03353 if (p) { 03354 a = (stb__arr *) p; 03355 a->limit = limit; 03356 } else { 03357 // throw an error! 03358 } 03359 } 03360 } 03361 a->len = stb_min(a->len, a->limit); 03362 *pp = a+1; 03363 } 03364 03365 void stb__arr_setsize_(void **pp, int size, int limit STB__PARAMS) 03366 { 03367 void *p = *pp; 03368 stb_arr_check2(p); 03369 stb__arrsize_(pp, size, limit, stb_arr_len2(p) STB__ARGS); 03370 } 03371 03372 void stb__arr_setlen_(void **pp, int size, int newlen STB__PARAMS) 03373 { 03374 void *p = *pp; 03375 stb_arr_check2(p); 03376 if (stb_arrcurmax2(p) < newlen || p == NULL) { 03377 stb__arrsize_(pp, size, newlen, newlen STB__ARGS); 03378 } else { 03379 stb_arrhead2(p)->len = newlen; 03380 } 03381 } 03382 03383 void stb__arr_addlen_(void **p, int size, int addlen STB__PARAMS) 03384 { 03385 stb__arr_setlen_(p, size, stb_arr_len2(*p) + addlen STB__ARGS); 03386 } 03387 03388 void stb__arr_insertn_(void **pp, int size, int i, int n STB__PARAMS) 03389 { 03390 void *p = *pp; 03391 if (n) { 03392 int z; 03393 03394 if (p == NULL) { 03395 stb__arr_addlen_(pp, size, n STB__ARGS); 03396 return; 03397 } 03398 03399 z = stb_arr_len2(p); 03400 stb__arr_addlen_(&p, size, n STB__ARGS); 03401 memmove((char *) p + (i+n)*size, (char *) p + i*size, size * (z-i)); 03402 } 03403 *pp = p; 03404 } 03405 03406 void stb__arr_deleten_(void **pp, int size, int i, int n STB__PARAMS) 03407 { 03408 void *p = *pp; 03409 if (n) { 03410 memmove((char *) p + i*size, (char *) p + (i+n)*size, size * (stb_arr_len2(p)-(i+n))); 03411 stb_arrhead2(p)->len -= n; 03412 } 03413 *pp = p; 03414 } 03415 03416 #endif 03417 03419 // 03420 // Hashing 03421 // 03422 // typical use for this is to make a power-of-two hash table. 03423 // 03424 // let N = size of table (2^n) 03425 // let H = stb_hash(str) 03426 // let S = stb_rehash(H) | 1 03427 // 03428 // then hash probe sequence P(i) for i=0..N-1 03429 // P(i) = (H + S*i) & (N-1) 03430 // 03431 // the idea is that H has 32 bits of hash information, but the 03432 // table has only, say, 2^20 entries so only uses 20 of the bits. 03433 // then by rehashing the original H we get 2^12 different probe 03434 // sequences for a given initial probe location. (So it's optimal 03435 // for 64K tables and its optimality decreases past that.) 03436 // 03437 // ok, so I've added something that generates _two separate_ 03438 // 32-bit hashes simultaneously which should scale better to 03439 // very large tables. 03440 03441 03442 STB_EXTERN unsigned int stb_hash(char *str); 03443 STB_EXTERN unsigned int stb_hashptr(void *p); 03444 STB_EXTERN unsigned int stb_hashlen(char *str, int len); 03445 STB_EXTERN unsigned int stb_rehash_improved(unsigned int v); 03446 STB_EXTERN unsigned int stb_hash_fast(void *p, int len); 03447 STB_EXTERN unsigned int stb_hash2(char *str, unsigned int *hash2_ptr); 03448 STB_EXTERN unsigned int stb_hash_number(unsigned int hash); 03449 03450 #define stb_rehash(x) ((x) + ((x) >> 6) + ((x) >> 19)) 03451 03452 #ifdef STB_DEFINE 03453 unsigned int stb_hash(char *str) 03454 { 03455 unsigned int hash = 0; 03456 while (*str) 03457 hash = (hash << 7) + (hash >> 25) + *str++; 03458 return hash + (hash >> 16); 03459 } 03460 03461 unsigned int stb_hashlen(char *str, int len) 03462 { 03463 unsigned int hash = 0; 03464 while (len-- > 0 && *str) 03465 hash = (hash << 7) + (hash >> 25) + *str++; 03466 return hash + (hash >> 16); 03467 } 03468 03469 unsigned int stb_hashptr(void *p) 03470 { 03471 unsigned int x = (unsigned int)(size_t) p; 03472 03473 // typically lacking in low bits and high bits 03474 x = stb_rehash(x); 03475 x += x << 16; 03476 03477 // pearson's shuffle 03478 x ^= x << 3; 03479 x += x >> 5; 03480 x ^= x << 2; 03481 x += x >> 15; 03482 x ^= x << 10; 03483 return stb_rehash(x); 03484 } 03485 03486 unsigned int stb_rehash_improved(unsigned int v) 03487 { 03488 return stb_hashptr((void *)(size_t) v); 03489 } 03490 03491 unsigned int stb_hash2(char *str, unsigned int *hash2_ptr) 03492 { 03493 unsigned int hash1 = 0x3141592c; 03494 unsigned int hash2 = 0x77f044ed; 03495 while (*str) { 03496 hash1 = (hash1 << 7) + (hash1 >> 25) + *str; 03497 hash2 = (hash2 << 11) + (hash2 >> 21) + *str; 03498 ++str; 03499 } 03500 *hash2_ptr = hash2 + (hash1 >> 16); 03501 return hash1 + (hash2 >> 16); 03502 } 03503 03504 // Paul Hsieh hash 03505 #define stb__get16(p) ((p)[0] | ((p)[1] << 8)) 03506 03507 unsigned int stb_hash_fast(void *p, int len) 03508 { 03509 unsigned char *q = (unsigned char *) p; 03510 unsigned int hash = len; 03511 03512 if (len <= 0 || q == NULL) return 0; 03513 03514 /* Main loop */ 03515 for (;len > 3; len -= 4) { 03516 unsigned int val; 03517 hash += stb__get16(q); 03518 val = (stb__get16(q+2) << 11); 03519 hash = (hash << 16) ^ hash ^ val; 03520 q += 4; 03521 hash += hash >> 11; 03522 } 03523 03524 /* Handle end cases */ 03525 switch (len) { 03526 case 3: hash += stb__get16(q); 03527 hash ^= hash << 16; 03528 hash ^= q[2] << 18; 03529 hash += hash >> 11; 03530 break; 03531 case 2: hash += stb__get16(q); 03532 hash ^= hash << 11; 03533 hash += hash >> 17; 03534 break; 03535 case 1: hash += q[0]; 03536 hash ^= hash << 10; 03537 hash += hash >> 1; 03538 break; 03539 case 0: break; 03540 } 03541 03542 /* Force "avalanching" of final 127 bits */ 03543 hash ^= hash << 3; 03544 hash += hash >> 5; 03545 hash ^= hash << 4; 03546 hash += hash >> 17; 03547 hash ^= hash << 25; 03548 hash += hash >> 6; 03549 03550 return hash; 03551 } 03552 03553 unsigned int stb_hash_number(unsigned int hash) 03554 { 03555 hash ^= hash << 3; 03556 hash += hash >> 5; 03557 hash ^= hash << 4; 03558 hash += hash >> 17; 03559 hash ^= hash << 25; 03560 hash += hash >> 6; 03561 return hash; 03562 } 03563 03564 #endif 03565 03566 #ifdef STB_PERFECT_HASH 03567 03568 // 03569 // Perfect hashing for ints/pointers 03570 // 03571 // This is mainly useful for making faster pointer-indexed tables 03572 // that don't change frequently. E.g. for stb_ischar(). 03573 // 03574 03575 typedef struct 03576 { 03577 stb_uint32 addend; 03578 stb_uint multiplicand; 03579 stb_uint b_mask; 03580 stb_uint8 small_bmap[16]; 03581 stb_uint16 *large_bmap; 03582 03583 stb_uint table_mask; 03584 stb_uint32 *table; 03585 } stb_perfect; 03586 03587 STB_EXTERN int stb_perfect_create(stb_perfect *,unsigned int*,int n); 03588 STB_EXTERN void stb_perfect_destroy(stb_perfect *); 03589 STB_EXTERN int stb_perfect_hash(stb_perfect *, unsigned int x); 03590 extern int stb_perfect_hash_max_failures; 03591 03592 #ifdef STB_DEFINE 03593 03594 int stb_perfect_hash_max_failures; 03595 03596 int stb_perfect_hash(stb_perfect *p, unsigned int x) 03597 { 03598 stb_uint m = x * p->multiplicand; 03599 stb_uint y = x >> 16; 03600 stb_uint bv = (m >> 24) + y; 03601 stb_uint av = (m + y) >> 12; 03602 if (p->table == NULL) return -1; // uninitialized table fails 03603 bv &= p->b_mask; 03604 av &= p->table_mask; 03605 if (p->large_bmap) 03606 av ^= p->large_bmap[bv]; 03607 else 03608 av ^= p->small_bmap[bv]; 03609 return p->table[av] == x ? av : -1; 03610 } 03611 03612 static void stb__perfect_prehash(stb_perfect *p, stb_uint x, stb_uint16 *a, stb_uint16 *b) 03613 { 03614 stb_uint m = x * p->multiplicand; 03615 stb_uint y = x >> 16; 03616 stb_uint bv = (m >> 24) + y; 03617 stb_uint av = (m + y) >> 12; 03618 bv &= p->b_mask; 03619 av &= p->table_mask; 03620 *b = bv; 03621 *a = av; 03622 } 03623 03624 static unsigned long stb__perfect_rand(void) 03625 { 03626 static unsigned long stb__rand; 03627 stb__rand = stb__rand * 2147001325 + 715136305; 03628 return 0x31415926 ^ ((stb__rand >> 16) + (stb__rand << 16)); 03629 } 03630 03631 typedef struct { 03632 unsigned short count; 03633 unsigned short b; 03634 unsigned short map; 03635 unsigned short *entries; 03636 } stb__slot; 03637 03638 static int stb__slot_compare(const void *p, const void *q) 03639 { 03640 stb__slot *a = (stb__slot *) p; 03641 stb__slot *b = (stb__slot *) q; 03642 return a->count > b->count ? -1 : a->count < b->count; // sort large to small 03643 } 03644 03645 int stb_perfect_create(stb_perfect *p, unsigned int *v, int n) 03646 { 03647 unsigned int buffer1[64], buffer2[64], buffer3[64], buffer4[64], buffer5[32]; 03648 unsigned short *as = (unsigned short *) stb_temp(buffer1, sizeof(*v)*n); 03649 unsigned short *bs = (unsigned short *) stb_temp(buffer2, sizeof(*v)*n); 03650 unsigned short *entries = (unsigned short *) stb_temp(buffer4, sizeof(*entries) * n); 03651 int size = 1 << stb_log2_ceil(n), bsize=8; 03652 int failure = 0,i,j,k; 03653 03654 assert(n <= 32768); 03655 p->large_bmap = NULL; 03656 03657 for(;;) { 03658 stb__slot *bcount = (stb__slot *) stb_temp(buffer3, sizeof(*bcount) * bsize); 03659 unsigned short *bloc = (unsigned short *) stb_temp(buffer5, sizeof(*bloc) * bsize); 03660 unsigned short *e; 03661 int bad=0; 03662 03663 p->addend = stb__perfect_rand(); 03664 p->multiplicand = stb__perfect_rand() | 1; 03665 p->table_mask = size-1; 03666 p->b_mask = bsize-1; 03667 p->table = (stb_uint32 *) malloc(size * sizeof(*p->table)); 03668 03669 for (i=0; i < bsize; ++i) { 03670 bcount[i].b = i; 03671 bcount[i].count = 0; 03672 bcount[i].map = 0; 03673 } 03674 for (i=0; i < n; ++i) { 03675 stb__perfect_prehash(p, v[i], as+i, bs+i); 03676 ++bcount[bs[i]].count; 03677 } 03678 qsort(bcount, bsize, sizeof(*bcount), stb__slot_compare); 03679 e = entries; // now setup up their entries index 03680 for (i=0; i < bsize; ++i) { 03681 bcount[i].entries = e; 03682 e += bcount[i].count; 03683 bcount[i].count = 0; 03684 bloc[bcount[i].b] = i; 03685 } 03686 // now fill them out 03687 for (i=0; i < n; ++i) { 03688 int b = bs[i]; 03689 int w = bloc[b]; 03690 bcount[w].entries[bcount[w].count++] = i; 03691 } 03692 stb_tempfree(buffer5,bloc); 03693 // verify 03694 for (i=0; i < bsize; ++i) 03695 for (j=0; j < bcount[i].count; ++j) 03696 assert(bs[bcount[i].entries[j]] == bcount[i].b); 03697 memset(p->table, 0, size*sizeof(*p->table)); 03698 03699 // check if any b has duplicate a 03700 for (i=0; i < bsize; ++i) { 03701 if (bcount[i].count > 1) { 03702 for (j=0; j < bcount[i].count; ++j) { 03703 if (p->table[as[bcount[i].entries[j]]]) 03704 bad = 1; 03705 p->table[as[bcount[i].entries[j]]] = 1; 03706 } 03707 for (j=0; j < bcount[i].count; ++j) { 03708 p->table[as[bcount[i].entries[j]]] = 0; 03709 } 03710 if (bad) break; 03711 } 03712 } 03713 03714 if (!bad) { 03715 // go through the bs and populate the table, first fit 03716 for (i=0; i < bsize; ++i) { 03717 if (bcount[i].count) { 03718 // go through the candidate table[b] values 03719 for (j=0; j < size; ++j) { 03720 // go through the a values and see if they fit 03721 for (k=0; k < bcount[i].count; ++k) { 03722 int a = as[bcount[i].entries[k]]; 03723 if (p->table[(a^j)&p->table_mask]) { 03724 break; // fails 03725 } 03726 } 03727 // if succeeded, accept 03728 if (k == bcount[i].count) { 03729 bcount[i].map = j; 03730 for (k=0; k < bcount[i].count; ++k) { 03731 int a = as[bcount[i].entries[k]]; 03732 p->table[(a^j)&p->table_mask] = 1; 03733 } 03734 break; 03735 } 03736 } 03737 if (j == size) 03738 break; // no match for i'th entry, so break out in failure 03739 } 03740 } 03741 if (i == bsize) { 03742 // success... fill out map 03743 if (bsize <= 16 && size <= 256) { 03744 p->large_bmap = NULL; 03745 for (i=0; i < bsize; ++i) 03746 p->small_bmap[bcount[i].b] = (stb_uint8) bcount[i].map; 03747 } else { 03748 p->large_bmap = (unsigned short *) malloc(sizeof(*p->large_bmap) * bsize); 03749 for (i=0; i < bsize; ++i) 03750 p->large_bmap[bcount[i].b] = bcount[i].map; 03751 } 03752 03753 // initialize table to v[0], so empty slots will fail 03754 for (i=0; i < size; ++i) 03755 p->table[i] = v[0]; 03756 03757 for (i=0; i < n; ++i) 03758 if (p->large_bmap) 03759 p->table[as[i] ^ p->large_bmap[bs[i]]] = v[i]; 03760 else 03761 p->table[as[i] ^ p->small_bmap[bs[i]]] = v[i]; 03762 03763 // and now validate that none of them collided 03764 for (i=0; i < n; ++i) 03765 assert(stb_perfect_hash(p, v[i]) >= 0); 03766 03767 stb_tempfree(buffer3, bcount); 03768 break; 03769 } 03770 } 03771 free(p->table); 03772 p->table = NULL; 03773 stb_tempfree(buffer3, bcount); 03774 03775 ++failure; 03776 if (failure >= 4 && bsize < size) bsize *= 2; 03777 if (failure >= 8 && (failure & 3) == 0 && size < 4*n) { 03778 size *= 2; 03779 bsize *= 2; 03780 } 03781 if (failure == 6) { 03782 // make sure the input data is unique, so we don't infinite loop 03783 unsigned int *data = (unsigned int *) stb_temp(buffer3, n * sizeof(*data)); 03784 memcpy(data, v, sizeof(*data) * n); 03785 qsort(data, n, sizeof(*data), stb_intcmp(0)); 03786 for (i=1; i < n; ++i) { 03787 if (data[i] == data[i-1]) 03788 size = 0; // size is return value, so 0 it 03789 } 03790 stb_tempfree(buffer3, data); 03791 if (!size) break; 03792 } 03793 } 03794 03795 if (failure > stb_perfect_hash_max_failures) 03796 stb_perfect_hash_max_failures = failure; 03797 03798 stb_tempfree(buffer1, as); 03799 stb_tempfree(buffer2, bs); 03800 stb_tempfree(buffer4, entries); 03801 03802 return size; 03803 } 03804 03805 void stb_perfect_destroy(stb_perfect *p) 03806 { 03807 if (p->large_bmap) free(p->large_bmap); 03808 if (p->table ) free(p->table); 03809 p->large_bmap = NULL; 03810 p->table = NULL; 03811 p->b_mask = 0; 03812 p->table_mask = 0; 03813 } 03814 #endif 03815 03817 // 03818 // Perfect hash clients 03819 03820 STB_EXTERN int stb_ischar(char s, char *set); 03821 03822 #ifdef STB_DEFINE 03823 03824 int stb_ischar(char c, char *set) 03825 { 03826 static unsigned char bit[8] = { 1,2,4,8,16,32,64,128 }; 03827 static stb_perfect p; 03828 static unsigned char (*tables)[256]; 03829 static char ** sets = NULL; 03830 03831 int z = stb_perfect_hash(&p, (int)(size_t) set); 03832 if (z < 0) { 03833 int i,k,n,j,f; 03834 // special code that means free all existing data 03835 if (set == NULL) { 03836 stb_arr_free(sets); 03837 free(tables); 03838 tables = NULL; 03839 stb_perfect_destroy(&p); 03840 return 0; 03841 } 03842 stb_arr_push(sets, set); 03843 stb_perfect_destroy(&p); 03844 n = stb_perfect_create(&p, (unsigned int *) (char **) sets, stb_arr_len(sets)); 03845 assert(n != 0); 03846 k = (n+7) >> 3; 03847 tables = (unsigned char (*)[256]) realloc(tables, sizeof(*tables) * k); 03848 memset(tables, 0, sizeof(*tables) * k); 03849 for (i=0; i < stb_arr_len(sets); ++i) { 03850 k = stb_perfect_hash(&p, (int)(size_t) sets[i]); 03851 assert(k >= 0); 03852 n = k >> 3; 03853 f = bit[k&7]; 03854 for (j=0; !j || sets[i][j]; ++j) { 03855 tables[n][(unsigned char) sets[i][j]] |= f; 03856 } 03857 } 03858 z = stb_perfect_hash(&p, (int)(size_t) set); 03859 } 03860 return tables[z >> 3][(unsigned char) c] & bit[z & 7]; 03861 } 03862 03863 #endif 03864 #endif 03865 03867 // 03868 // Instantiated data structures 03869 // 03870 // This is an attempt to implement a templated data structure. 03871 // 03872 // Hash table: call stb_define_hash(TYPE,N,KEY,K1,K2,HASH,VALUE) 03873 // TYPE -- will define a structure type containing the hash table 03874 // N -- the name, will prefix functions named: 03875 // N create 03876 // N destroy 03877 // N get 03878 // N set, N add, N update, 03879 // N remove 03880 // KEY -- the type of the key. 'x == y' must be valid 03881 // K1,K2 -- keys never used by the app, used as flags in the hashtable 03882 // HASH -- a piece of code ending with 'return' that hashes key 'k' 03883 // VALUE -- the type of the value. 'x = y' must be valid 03884 // 03885 // Note that stb_define_hash_base can be used to define more sophisticated 03886 // hash tables, e.g. those that make copies of the key or use special 03887 // comparisons (e.g. strcmp). 03888 03889 #define STB_(prefix,name) stb__##prefix##name 03890 #define STB__(prefix,name) prefix##name 03891 #define STB__use(x) x 03892 #define STB__skip(x) 03893 03894 #define stb_declare_hash(PREFIX,TYPE,N,KEY,VALUE) \ 03895 typedef struct stb__st_##TYPE TYPE;\ 03896 PREFIX int STB__(N, init)(TYPE *h, int count);\ 03897 PREFIX int STB__(N, memory_usage)(TYPE *h);\ 03898 PREFIX TYPE * STB__(N, create)(void);\ 03899 PREFIX TYPE * STB__(N, copy)(TYPE *h);\ 03900 PREFIX void STB__(N, destroy)(TYPE *h);\ 03901 PREFIX int STB__(N,get_flag)(TYPE *a, KEY k, VALUE *v);\ 03902 PREFIX VALUE STB__(N,get)(TYPE *a, KEY k);\ 03903 PREFIX int STB__(N, set)(TYPE *a, KEY k, VALUE v);\ 03904 PREFIX int STB__(N, add)(TYPE *a, KEY k, VALUE v);\ 03905 PREFIX int STB__(N, update)(TYPE*a,KEY k,VALUE v);\ 03906 PREFIX int STB__(N, remove)(TYPE *a, KEY k, VALUE *v); 03907 03908 #define STB_nocopy(x) (x) 03909 #define STB_nodelete(x) 0 03910 #define STB_nofields 03911 #define STB_nonullvalue(x) 03912 #define STB_nullvalue(x) x 03913 #define STB_safecompare(x) x 03914 #define STB_nosafe(x) 03915 #define STB_noprefix 03916 03917 #ifdef __GNUC__ 03918 #define STB__nogcc(x) 03919 #else 03920 #define STB__nogcc(x) x 03921 #endif 03922 03923 #define stb_define_hash_base(PREFIX,TYPE,FIELDS,N,NC,LOAD_FACTOR, \ 03924 KEY,EMPTY,DEL,COPY,DISPOSE,SAFE, \ 03925 VCOMPARE,CCOMPARE,HASH, \ 03926 VALUE,HASVNULL,VNULL) \ 03927 \ 03928 typedef struct \ 03929 { \ 03930 KEY k; \ 03931 VALUE v; \ 03932 } STB_(N,_hashpair); \ 03933 \ 03934 STB__nogcc( typedef struct stb__st_##TYPE TYPE; ) \ 03935 struct stb__st_##TYPE { \ 03936 FIELDS \ 03937 STB_(N,_hashpair) *table; \ 03938 unsigned int mask; \ 03939 int count, limit; \ 03940 int deleted; \ 03941 \ 03942 int delete_threshhold; \ 03943 int grow_threshhold; \ 03944 int shrink_threshhold; \ 03945 unsigned char alloced, has_empty, has_del; \ 03946 VALUE ev; VALUE dv; \ 03947 }; \ 03948 \ 03949 static unsigned int STB_(N, hash)(KEY k) \ 03950 { \ 03951 HASH \ 03952 } \ 03953 \ 03954 PREFIX int STB__(N, init)(TYPE *h, int count) \ 03955 { \ 03956 int i; \ 03957 if (count < 4) count = 4; \ 03958 h->limit = count; \ 03959 h->count = 0; \ 03960 h->mask = count-1; \ 03961 h->deleted = 0; \ 03962 h->grow_threshhold = (int) (count * LOAD_FACTOR); \ 03963 h->has_empty = h->has_del = 0; \ 03964 h->alloced = 0; \ 03965 if (count <= 64) \ 03966 h->shrink_threshhold = 0; \ 03967 else \ 03968 h->shrink_threshhold = (int) (count * (LOAD_FACTOR/2.25)); \ 03969 h->delete_threshhold = (int) (count * (1-LOAD_FACTOR)/2); \ 03970 h->table = (STB_(N,_hashpair)*) malloc(sizeof(h->table[0]) * count); \ 03971 if (h->table == NULL) return 0; \ 03972 /* ideally this gets turned into a memset32 automatically */ \ 03973 for (i=0; i < count; ++i) \ 03974 h->table[i].k = EMPTY; \ 03975 return 1; \ 03976 } \ 03977 \ 03978 PREFIX int STB__(N, memory_usage)(TYPE *h) \ 03979 { \ 03980 return sizeof(*h) + h->limit * sizeof(h->table[0]); \ 03981 } \ 03982 \ 03983 PREFIX TYPE * STB__(N, create)(void) \ 03984 { \ 03985 TYPE *h = (TYPE *) malloc(sizeof(*h)); \ 03986 if (h) { \ 03987 if (STB__(N, init)(h, 16)) \ 03988 h->alloced = 1; \ 03989 else { free(h); h=NULL; } \ 03990 } \ 03991 return h; \ 03992 } \ 03993 \ 03994 PREFIX void STB__(N, destroy)(TYPE *a) \ 03995 { \ 03996 int i; \ 03997 for (i=0; i < a->limit; ++i) \ 03998 if (!CCOMPARE(a->table[i].k,EMPTY) && !CCOMPARE(a->table[i].k, DEL)) \ 03999 DISPOSE(a->table[i].k); \ 04000 free(a->table); \ 04001 if (a->alloced) \ 04002 free(a); \ 04003 } \ 04004 \ 04005 static void STB_(N, rehash)(TYPE *a, int count); \ 04006 \ 04007 PREFIX int STB__(N,get_flag)(TYPE *a, KEY k, VALUE *v) \ 04008 { \ 04009 unsigned int h = STB_(N, hash)(k); \ 04010 unsigned int n = h & a->mask, s; \ 04011 if (CCOMPARE(k,EMPTY)){ if (a->has_empty) *v = a->ev; return a->has_empty;}\ 04012 if (CCOMPARE(k,DEL)) { if (a->has_del ) *v = a->dv; return a->has_del; }\ 04013 if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \ 04014 SAFE(if (!CCOMPARE(a->table[n].k,DEL))) \ 04015 if (VCOMPARE(a->table[n].k,k)) { *v = a->table[n].v; return 1; } \ 04016 s = stb_rehash(h) | 1; \ 04017 for(;;) { \ 04018 n = (n + s) & a->mask; \ 04019 if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \ 04020 SAFE(if (CCOMPARE(a->table[n].k,DEL)) continue;) \ 04021 if (VCOMPARE(a->table[n].k,k)) \ 04022 { *v = a->table[n].v; return 1; } \ 04023 } \ 04024 } \ 04025 \ 04026 HASVNULL( \ 04027 PREFIX VALUE STB__(N,get)(TYPE *a, KEY k) \ 04028 { \ 04029 VALUE v; \ 04030 if (STB__(N,get_flag)(a,k,&v)) return v; \ 04031 else return VNULL; \ 04032 } \ 04033 ) \ 04034 \ 04035 PREFIX int STB__(N,getkey)(TYPE *a, KEY k, KEY *kout) \ 04036 { \ 04037 unsigned int h = STB_(N, hash)(k); \ 04038 unsigned int n = h & a->mask, s; \ 04039 if (CCOMPARE(k,EMPTY)||CCOMPARE(k,DEL)) return 0; \ 04040 if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \ 04041 SAFE(if (!CCOMPARE(a->table[n].k,DEL))) \ 04042 if (VCOMPARE(a->table[n].k,k)) { *kout = a->table[n].k; return 1; } \ 04043 s = stb_rehash(h) | 1; \ 04044 for(;;) { \ 04045 n = (n + s) & a->mask; \ 04046 if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \ 04047 SAFE(if (CCOMPARE(a->table[n].k,DEL)) continue;) \ 04048 if (VCOMPARE(a->table[n].k,k)) \ 04049 { *kout = a->table[n].k; return 1; } \ 04050 } \ 04051 } \ 04052 \ 04053 static int STB_(N,addset)(TYPE *a, KEY k, VALUE v, \ 04054 int allow_new, int allow_old, int copy) \ 04055 { \ 04056 unsigned int h = STB_(N, hash)(k); \ 04057 unsigned int n = h & a->mask; \ 04058 int b = -1; \ 04059 if (CCOMPARE(k,EMPTY)) { \ 04060 if (a->has_empty ? allow_old : allow_new) { \ 04061 n=a->has_empty; a->ev = v; a->has_empty = 1; return !n; \ 04062 } else return 0; \ 04063 } \ 04064 if (CCOMPARE(k,DEL)) { \ 04065 if (a->has_del ? allow_old : allow_new) { \ 04066 n=a->has_del; a->dv = v; a->has_del = 1; return !n; \ 04067 } else return 0; \ 04068 } \ 04069 if (!CCOMPARE(a->table[n].k, EMPTY)) { \ 04070 unsigned int s; \ 04071 if (CCOMPARE(a->table[n].k, DEL)) \ 04072 b = n; \ 04073 else if (VCOMPARE(a->table[n].k,k)) { \ 04074 if (allow_old) \ 04075 a->table[n].v = v; \ 04076 return !allow_new; \ 04077 } \ 04078 s = stb_rehash(h) | 1; \ 04079 for(;;) { \ 04080 n = (n + s) & a->mask; \ 04081 if (CCOMPARE(a->table[n].k, EMPTY)) break; \ 04082 if (CCOMPARE(a->table[n].k, DEL)) { \ 04083 if (b < 0) b = n; \ 04084 } else if (VCOMPARE(a->table[n].k,k)) { \ 04085 if (allow_old) \ 04086 a->table[n].v = v; \ 04087 return !allow_new; \ 04088 } \ 04089 } \ 04090 } \ 04091 if (!allow_new) return 0; \ 04092 if (b < 0) b = n; else --a->deleted; \ 04093 a->table[b].k = copy ? COPY(k) : k; \ 04094 a->table[b].v = v; \ 04095 ++a->count; \ 04096 if (a->count > a->grow_threshhold) \ 04097 STB_(N,rehash)(a, a->limit*2); \ 04098 return 1; \ 04099 } \ 04100 \ 04101 PREFIX int STB__(N, set)(TYPE *a, KEY k, VALUE v){return STB_(N,addset)(a,k,v,1,1,1);}\ 04102 PREFIX int STB__(N, add)(TYPE *a, KEY k, VALUE v){return STB_(N,addset)(a,k,v,1,0,1);}\ 04103 PREFIX int STB__(N, update)(TYPE*a,KEY k,VALUE v){return STB_(N,addset)(a,k,v,0,1,1);}\ 04104 \ 04105 PREFIX int STB__(N, remove)(TYPE *a, KEY k, VALUE *v) \ 04106 { \ 04107 unsigned int h = STB_(N, hash)(k); \ 04108 unsigned int n = h & a->mask, s; \ 04109 if (CCOMPARE(k,EMPTY)) { if (a->has_empty) { if(v)*v = a->ev; a->has_empty=0; return 1; } return 0; } \ 04110 if (CCOMPARE(k,DEL)) { if (a->has_del ) { if(v)*v = a->dv; a->has_del =0; return 1; } return 0; } \ 04111 if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \ 04112 if (SAFE(CCOMPARE(a->table[n].k,DEL) || ) !VCOMPARE(a->table[n].k,k)) { \ 04113 s = stb_rehash(h) | 1; \ 04114 for(;;) { \ 04115 n = (n + s) & a->mask; \ 04116 if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \ 04117 SAFE(if (CCOMPARE(a->table[n].k, DEL)) continue;) \ 04118 if (VCOMPARE(a->table[n].k,k)) break; \ 04119 } \ 04120 } \ 04121 DISPOSE(a->table[n].k); \ 04122 a->table[n].k = DEL; \ 04123 --a->count; \ 04124 ++a->deleted; \ 04125 if (v != NULL) \ 04126 *v = a->table[n].v; \ 04127 if (a->count < a->shrink_threshhold) \ 04128 STB_(N, rehash)(a, a->limit >> 1); \ 04129 else if (a->deleted > a->delete_threshhold) \ 04130 STB_(N, rehash)(a, a->limit); \ 04131 return 1; \ 04132 } \ 04133 \ 04134 PREFIX TYPE * STB__(NC, copy)(TYPE *a) \ 04135 { \ 04136 int i; \ 04137 TYPE *h = (TYPE *) malloc(sizeof(*h)); \ 04138 if (!h) return NULL; \ 04139 if (!STB__(N, init)(h, a->limit)) { free(h); return NULL; } \ 04140 h->count = a->count; \ 04141 h->deleted = a->deleted; \ 04142 h->alloced = 1; \ 04143 h->ev = a->ev; h->dv = a->dv; \ 04144 h->has_empty = a->has_empty; h->has_del = a->has_del; \ 04145 memcpy(h->table, a->table, h->limit * sizeof(h->table[0])); \ 04146 for (i=0; i < a->limit; ++i) \ 04147 if (!CCOMPARE(h->table[i].k,EMPTY) && !CCOMPARE(h->table[i].k,DEL)) \ 04148 h->table[i].k = COPY(h->table[i].k); \ 04149 return h; \ 04150 } \ 04151 \ 04152 static void STB_(N, rehash)(TYPE *a, int count) \ 04153 { \ 04154 int i; \ 04155 TYPE b; \ 04156 STB__(N, init)(&b, count); \ 04157 for (i=0; i < a->limit; ++i) \ 04158 if (!CCOMPARE(a->table[i].k,EMPTY) && !CCOMPARE(a->table[i].k,DEL)) \ 04159 STB_(N,addset)(&b, a->table[i].k, a->table[i].v,1,1,0); \ 04160 free(a->table); \ 04161 a->table = b.table; \ 04162 a->mask = b.mask; \ 04163 a->count = b.count; \ 04164 a->limit = b.limit; \ 04165 a->deleted = b.deleted; \ 04166 a->delete_threshhold = b.delete_threshhold; \ 04167 a->grow_threshhold = b.grow_threshhold; \ 04168 a->shrink_threshhold = b.shrink_threshhold; \ 04169 } 04170 04171 #define STB_equal(a,b) ((a) == (b)) 04172 04173 #define stb_define_hash(TYPE,N,KEY,EMPTY,DEL,HASH,VALUE) \ 04174 stb_define_hash_base(STB_noprefix, TYPE,STB_nofields,N,NC,0.85f, \ 04175 KEY,EMPTY,DEL,STB_nocopy,STB_nodelete,STB_nosafe, \ 04176 STB_equal,STB_equal,HASH, \ 04177 VALUE,STB_nonullvalue,0) 04178 04179 #define stb_define_hash_vnull(TYPE,N,KEY,EMPTY,DEL,HASH,VALUE,VNULL) \ 04180 stb_define_hash_base(STB_noprefix, TYPE,STB_nofields,N,NC,0.85f, \ 04181 KEY,EMPTY,DEL,STB_nocopy,STB_nodelete,STB_nosafe, \ 04182 STB_equal,STB_equal,HASH, \ 04183 VALUE,STB_nullvalue,VNULL) 04184 04186 // 04187 // stb_ptrmap 04188 // 04189 // An stb_ptrmap data structure is an O(1) hash table between pointers. One 04190 // application is to let you store "extra" data associated with pointers, 04191 // which is why it was originally called stb_extra. 04192 04193 stb_declare_hash(STB_EXTERN, stb_ptrmap, stb_ptrmap_, void *, void *) 04194 stb_declare_hash(STB_EXTERN, stb_idict, stb_idict_, stb_int32, stb_int32) 04195 stb_declare_hash(STB_EXTERN, stb_uidict, stbi_uidict_, stb_uint32, stb_uint32) 04196 04197 STB_EXTERN void stb_ptrmap_delete(stb_ptrmap *e, void (*free_func)(void *)); 04198 STB_EXTERN stb_ptrmap *stb_ptrmap_new(void); 04199 04200 STB_EXTERN stb_idict * stb_idict_new_size(int size); 04201 STB_EXTERN void stb_idict_remove_all(stb_idict *e); 04202 STB_EXTERN void stb_uidict_reset(stb_uidict *e); 04203 04204 #ifdef STB_DEFINE 04205 04206 #define STB_EMPTY ((void *) 2) 04207 #define STB_EDEL ((void *) 6) 04208 04209 stb_define_hash_base(STB_noprefix,stb_ptrmap, STB_nofields, stb_ptrmap_,stb_ptrmap_,0.85f, 04210 void *,STB_EMPTY,STB_EDEL,STB_nocopy,STB_nodelete,STB_nosafe, 04211 STB_equal,STB_equal,return stb_hashptr(k);, 04212 void *,STB_nullvalue,NULL) 04213 04214 stb_ptrmap *stb_ptrmap_new(void) 04215 { 04216 return stb_ptrmap_create(); 04217 } 04218 04219 void stb_ptrmap_delete(stb_ptrmap *e, void (*free_func)(void *)) 04220 { 04221 int i; 04222 if (free_func) 04223 for (i=0; i < e->limit; ++i) 04224 if (e->table[i].k != STB_EMPTY && e->table[i].k != STB_EDEL) { 04225 if (free_func == free) 04226 free(e->table[i].v); // allow STB_MALLOC_WRAPPER to operate 04227 else 04228 free_func(e->table[i].v); 04229 } 04230 stb_ptrmap_destroy(e); 04231 } 04232 04233 // extra fields needed for stua_dict 04234 #define STB_IEMPTY ((int) 1) 04235 #define STB_IDEL ((int) 3) 04236 stb_define_hash_base(STB_noprefix, stb_idict, short type; short gc; STB_nofields, stb_idict_,stb_idict_,0.95f, 04237 stb_int32,STB_IEMPTY,STB_IDEL,STB_nocopy,STB_nodelete,STB_nosafe, 04238 STB_equal,STB_equal, 04239 return stb_rehash_improved(k);,stb_int32,STB_nonullvalue,0) 04240 04241 stb_idict * stb_idict_new_size(int size) 04242 { 04243 stb_idict *e = (stb_idict *) malloc(sizeof(*e)); 04244 if (e) { 04245 if (!stb_is_pow2(size)) 04246 size = 1 << stb_log2_ceil(size); 04247 stb_idict_init(e, size); 04248 e->alloced = 1; 04249 } 04250 return e; 04251 } 04252 04253 void stb_idict_remove_all(stb_idict *e) 04254 { 04255 int n; 04256 for (n=0; n < e->limit; ++n) 04257 e->table[n].k = STB_IEMPTY; 04258 e->has_empty = e->has_del = 0; 04259 e->count = 0; 04260 e->deleted = 0; 04261 } 04262 04263 stb_define_hash_base(STB_noprefix, stb_uidict, STB_nofields, stb_uidict_,stb_uidict_,0.85f, 04264 stb_int32,0xffffffff,0xfffffffe,STB_nocopy,STB_nodelete,STB_nosafe, 04265 STB_equal,STB_equal, 04266 return stb_rehash_improved(k);,stb_uint32,STB_nonullvalue,0) 04267 04268 void stb_uidict_reset(stb_uidict *e) 04269 { 04270 int n; 04271 for (n=0; n < e->limit; ++n) 04272 e->table[n].k = 0xffffffff; 04273 e->has_empty = e->has_del = 0; 04274 e->count = 0; 04275 e->deleted = 0; 04276 } 04277 #endif 04278 04280 // 04281 // stb_sparse_ptr_matrix 04282 // 04283 // An stb_ptrmap data structure is an O(1) hash table storing an arbitrary 04284 // block of data for a given pair of pointers. 04285 // 04286 // If create=0, returns 04287 04288 typedef struct stb__st_stb_spmatrix stb_spmatrix; 04289 04290 STB_EXTERN stb_spmatrix * stb_sparse_ptr_matrix_new(int val_size); 04291 STB_EXTERN void stb_sparse_ptr_matrix_free(stb_spmatrix *z); 04292 STB_EXTERN void * stb_sparse_ptr_matrix_get(stb_spmatrix *z, void *a, void *b, int create); 04293 04294 #ifdef STB_DEFINE 04295 typedef struct 04296 { 04297 void *a; 04298 void *b; 04299 } stb__ptrpair; 04300 04301 static stb__ptrpair stb__ptrpair_empty = { (void *) 1, (void *) 1 }; 04302 static stb__ptrpair stb__ptrpair_del = { (void *) 2, (void *) 2 }; 04303 04304 #define STB__equal_ptrpair(x,y) ((x).a == (y).a && (x).b == (y).b) 04305 04306 stb_define_hash_base(STB_noprefix, stb_spmatrix, int val_size; void *arena;, stb__spmatrix_,stb__spmatrix_, 0.85, 04307 stb__ptrpair, stb__ptrpair_empty, stb__ptrpair_del, 04308 STB_nocopy, STB_nodelete, STB_nosafe, 04309 STB__equal_ptrpair, STB__equal_ptrpair, return stb_rehash(stb_hashptr(k.a))+stb_hashptr(k.b);, 04310 void *, STB_nullvalue, 0) 04311 04312 stb_spmatrix *stb_sparse_ptr_matrix_new(int val_size) 04313 { 04314 stb_spmatrix *m = stb__spmatrix_create(); 04315 if (m) m->val_size = val_size; 04316 if (m) m->arena = stb_malloc_global(1); 04317 return m; 04318 } 04319 04320 void stb_sparse_ptr_matrix_free(stb_spmatrix *z) 04321 { 04322 if (z->arena) stb_free(z->arena); 04323 stb__spmatrix_destroy(z); 04324 } 04325 04326 void *stb_sparse_ptr_matrix_get(stb_spmatrix *z, void *a, void *b, int create) 04327 { 04328 stb__ptrpair t = { a,b }; 04329 void *data = stb__spmatrix_get(z, t); 04330 if (!data && create) { 04331 data = stb_malloc_raw(z->arena, z->val_size); 04332 if (!data) return NULL; 04333 memset(data, 0, z->val_size); 04334 stb__spmatrix_add(z, t, data); 04335 } 04336 return data; 04337 } 04338 #endif 04339 04340 04341 04343 // 04344 // SDICT: Hash Table for Strings (symbol table) 04345 // 04346 // if "use_arena=1", then strings will be copied 04347 // into blocks and never freed until the sdict is freed; 04348 // otherwise they're malloc()ed and free()d on the fly. 04349 // (specify use_arena=1 if you never stb_sdict_remove) 04350 04351 stb_declare_hash(STB_EXTERN, stb_sdict, stb_sdict_, char *, void *) 04352 04353 STB_EXTERN stb_sdict * stb_sdict_new(int use_arena); 04354 STB_EXTERN stb_sdict * stb_sdict_copy(stb_sdict*); 04355 STB_EXTERN void stb_sdict_delete(stb_sdict *); 04356 STB_EXTERN void * stb_sdict_change(stb_sdict *, char *str, void *p); 04357 STB_EXTERN int stb_sdict_count(stb_sdict *d); 04358 04359 STB_EXTERN int stb_sdict_internal_limit(stb_sdict *d); 04360 STB_EXTERN char * stb_sdict_internal_key(stb_sdict *d, int n); 04361 STB_EXTERN void * stb_sdict_internal_value(stb_sdict *d, int n); 04362 04363 #define stb_sdict_for(d,i,q,z) \ 04364 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) \ 04365 if (q==NULL||q==(void *) 1);else // reversed makes macro friendly 04366 04367 #ifdef STB_DEFINE 04368 04369 // if in same translation unit, for speed, don't call accessors 04370 #undef stb_sdict_for 04371 #define stb_sdict_for(d,i,q,z) \ 04372 for(i=0; i < (d)->limit ? (q=(d)->table[i].k,z=(d)->table[i].v,1) : 0; ++i) \ 04373 if (q==NULL||q==(void *) 1);else // reversed makes macro friendly 04374 04375 #define STB_DEL ((void *) 1) 04376 #define STB_SDEL ((char *) 1) 04377 04378 #define stb_sdict__copy(x) \ 04379 stb_p_strcpy_s(a->arena ? stb_malloc_string(a->arena, strlen(x)+1) \ 04380 : (char *) malloc(strlen(x)+1), strlen(x)+1, x) 04381 04382 #define stb_sdict__dispose(x) if (!a->arena) free(x) 04383 04384 stb_define_hash_base(STB_noprefix, stb_sdict, void*arena;, stb_sdict_,stb_sdictinternal_, 0.85f, 04385 char *, NULL, STB_SDEL, stb_sdict__copy, stb_sdict__dispose, 04386 STB_safecompare, !strcmp, STB_equal, return stb_hash(k);, 04387 void *, STB_nullvalue, NULL) 04388 04389 int stb_sdict_count(stb_sdict *a) 04390 { 04391 return a->count; 04392 } 04393 04394 int stb_sdict_internal_limit(stb_sdict *a) 04395 { 04396 return a->limit; 04397 } 04398 char* stb_sdict_internal_key(stb_sdict *a, int n) 04399 { 04400 return a->table[n].k; 04401 } 04402 void* stb_sdict_internal_value(stb_sdict *a, int n) 04403 { 04404 return a->table[n].v; 04405 } 04406 04407 stb_sdict * stb_sdict_new(int use_arena) 04408 { 04409 stb_sdict *d = stb_sdict_create(); 04410 if (d == NULL) return NULL; 04411 d->arena = use_arena ? stb_malloc_global(1) : NULL; 04412 return d; 04413 } 04414 04415 stb_sdict* stb_sdict_copy(stb_sdict *old) 04416 { 04417 stb_sdict *n; 04418 void *old_arena = old->arena; 04419 void *new_arena = old_arena ? stb_malloc_global(1) : NULL; 04420 old->arena = new_arena; 04421 n = stb_sdictinternal_copy(old); 04422 old->arena = old_arena; 04423 if (n) 04424 n->arena = new_arena; 04425 else if (new_arena) 04426 stb_free(new_arena); 04427 return n; 04428 } 04429 04430 04431 void stb_sdict_delete(stb_sdict *d) 04432 { 04433 if (d->arena) 04434 stb_free(d->arena); 04435 stb_sdict_destroy(d); 04436 } 04437 04438 void * stb_sdict_change(stb_sdict *d, char *str, void *p) 04439 { 04440 void *q = stb_sdict_get(d, str); 04441 stb_sdict_set(d, str, p); 04442 return q; 04443 } 04444 #endif 04445 04447 // 04448 // Instantiated data structures 04449 // 04450 // This is an attempt to implement a templated data structure. 04451 // What you do is define a struct foo, and then include several 04452 // pointer fields to struct foo in your struct. Then you call 04453 // the instantiator, which creates the functions that implement 04454 // the data structure. This requires massive undebuggable #defines, 04455 // so we limit the cases where we do this. 04456 // 04457 // AA tree is an encoding of a 2-3 tree whereas RB trees encode a 2-3-4 tree; 04458 // much simpler code due to fewer cases. 04459 04460 #define stb__bst_parent(x) x 04461 #define stb__bst_noparent(x) 04462 04463 #define stb_bst_fields(N) \ 04464 *STB_(N,left), *STB_(N,right); \ 04465 unsigned char STB_(N,level) 04466 04467 #define stb_bst_fields_parent(N) \ 04468 *STB_(N,left), *STB_(N,right), *STB_(N,parent); \ 04469 unsigned char STB_(N,level) 04470 04471 #define STB__level(N,x) ((x) ? (x)->STB_(N,level) : 0) 04472 04473 #define stb_bst_base(TYPE, N, TREE, M, compare, PAR) \ 04474 \ 04475 static int STB_(N,_compare)(TYPE *p, TYPE *q) \ 04476 { \ 04477 compare \ 04478 } \ 04479 \ 04480 static void STB_(N,setleft)(TYPE *q, TYPE *v) \ 04481 { \ 04482 q->STB_(N,left) = v; \ 04483 PAR(if (v) v->STB_(N,parent) = q;) \ 04484 } \ 04485 \ 04486 static void STB_(N,setright)(TYPE *q, TYPE *v) \ 04487 { \ 04488 q->STB_(N,right) = v; \ 04489 PAR(if (v) v->STB_(N,parent) = q;) \ 04490 } \ 04491 \ 04492 static TYPE *STB_(N,skew)(TYPE *q) \ 04493 { \ 04494 if (q == NULL) return q; \ 04495 if (q->STB_(N,left) \ 04496 && q->STB_(N,left)->STB_(N,level) == q->STB_(N,level)) { \ 04497 TYPE *p = q->STB_(N,left); \ 04498 STB_(N,setleft)(q, p->STB_(N,right)); \ 04499 STB_(N,setright)(p, q); \ 04500 return p; \ 04501 } \ 04502 return q; \ 04503 } \ 04504 \ 04505 static TYPE *STB_(N,split)(TYPE *p) \ 04506 { \ 04507 TYPE *q = p->STB_(N,right); \ 04508 if (q && q->STB_(N,right) \ 04509 && q->STB_(N,right)->STB_(N,level) == p->STB_(N,level)) { \ 04510 STB_(N,setright)(p, q->STB_(N,left)); \ 04511 STB_(N,setleft)(q,p); \ 04512 ++q->STB_(N,level); \ 04513 return q; \ 04514 } \ 04515 return p; \ 04516 } \ 04517 \ 04518 TYPE *STB__(N,insert)(TYPE *tree, TYPE *item) \ 04519 { \ 04520 int c; \ 04521 if (tree == NULL) { \ 04522 item->STB_(N,left) = NULL; \ 04523 item->STB_(N,right) = NULL; \ 04524 item->STB_(N,level) = 1; \ 04525 PAR(item->STB_(N,parent) = NULL;) \ 04526 return item; \ 04527 } \ 04528 c = STB_(N,_compare)(item,tree); \ 04529 if (c == 0) { \ 04530 if (item != tree) { \ 04531 STB_(N,setleft)(item, tree->STB_(N,left)); \ 04532 STB_(N,setright)(item, tree->STB_(N,right)); \ 04533 item->STB_(N,level) = tree->STB_(N,level); \ 04534 PAR(item->STB_(N,parent) = NULL;) \ 04535 } \ 04536 return item; \ 04537 } \ 04538 if (c < 0) \ 04539 STB_(N,setleft )(tree, STB__(N,insert)(tree->STB_(N,left), item)); \ 04540 else \ 04541 STB_(N,setright)(tree, STB__(N,insert)(tree->STB_(N,right), item)); \ 04542 tree = STB_(N,skew)(tree); \ 04543 tree = STB_(N,split)(tree); \ 04544 PAR(tree->STB_(N,parent) = NULL;) \ 04545 return tree; \ 04546 } \ 04547 \ 04548 TYPE *STB__(N,remove)(TYPE *tree, TYPE *item) \ 04549 { \ 04550 static TYPE *delnode, *leaf, *restore; \ 04551 if (tree == NULL) return NULL; \ 04552 leaf = tree; \ 04553 if (STB_(N,_compare)(item, tree) < 0) { \ 04554 STB_(N,setleft)(tree, STB__(N,remove)(tree->STB_(N,left), item)); \ 04555 } else { \ 04556 TYPE *r; \ 04557 delnode = tree; \ 04558 r = STB__(N,remove)(tree->STB_(N,right), item); \ 04559 /* maybe move 'leaf' up to this location */ \ 04560 if (restore == tree) { tree = leaf; leaf = restore = NULL; } \ 04561 STB_(N,setright)(tree,r); \ 04562 assert(tree->STB_(N,right) != tree); \ 04563 } \ 04564 if (tree == leaf) { \ 04565 if (delnode == item) { \ 04566 tree = tree->STB_(N,right); \ 04567 assert(leaf->STB_(N,left) == NULL); \ 04568 /* move leaf (the right sibling) up to delnode */ \ 04569 STB_(N,setleft )(leaf, item->STB_(N,left )); \ 04570 STB_(N,setright)(leaf, item->STB_(N,right)); \ 04571 leaf->STB_(N,level) = item->STB_(N,level); \ 04572 if (leaf != item) \ 04573 restore = delnode; \ 04574 } \ 04575 delnode = NULL; \ 04576 } else { \ 04577 if (STB__level(N,tree->STB_(N,left) ) < tree->STB_(N,level)-1 || \ 04578 STB__level(N,tree->STB_(N,right)) < tree->STB_(N,level)-1) { \ 04579 --tree->STB_(N,level); \ 04580 if (STB__level(N,tree->STB_(N,right)) > tree->STB_(N,level)) \ 04581 tree->STB_(N,right)->STB_(N,level) = tree->STB_(N,level); \ 04582 tree = STB_(N,skew)(tree); \ 04583 STB_(N,setright)(tree, STB_(N,skew)(tree->STB_(N,right))); \ 04584 if (tree->STB_(N,right)) \ 04585 STB_(N,setright)(tree->STB_(N,right), \ 04586 STB_(N,skew)(tree->STB_(N,right)->STB_(N,right))); \ 04587 tree = STB_(N,split)(tree); \ 04588 if (tree->STB_(N,right)) \ 04589 STB_(N,setright)(tree, STB_(N,split)(tree->STB_(N,right))); \ 04590 } \ 04591 } \ 04592 PAR(if (tree) tree->STB_(N,parent) = NULL;) \ 04593 return tree; \ 04594 } \ 04595 \ 04596 TYPE *STB__(N,last)(TYPE *tree) \ 04597 { \ 04598 if (tree) \ 04599 while (tree->STB_(N,right)) tree = tree->STB_(N,right); \ 04600 return tree; \ 04601 } \ 04602 \ 04603 TYPE *STB__(N,first)(TYPE *tree) \ 04604 { \ 04605 if (tree) \ 04606 while (tree->STB_(N,left)) tree = tree->STB_(N,left); \ 04607 return tree; \ 04608 } \ 04609 \ 04610 TYPE *STB__(N,next)(TYPE *tree, TYPE *item) \ 04611 { \ 04612 TYPE *next = NULL; \ 04613 if (item->STB_(N,right)) \ 04614 return STB__(N,first)(item->STB_(N,right)); \ 04615 PAR( \ 04616 while(item->STB_(N,parent)) { \ 04617 TYPE *up = item->STB_(N,parent); \ 04618 if (up->STB_(N,left) == item) return up; \ 04619 item = up; \ 04620 } \ 04621 return NULL; \ 04622 ) \ 04623 while (tree != item) { \ 04624 if (STB_(N,_compare)(item, tree) < 0) { \ 04625 next = tree; \ 04626 tree = tree->STB_(N,left); \ 04627 } else { \ 04628 tree = tree->STB_(N,right); \ 04629 } \ 04630 } \ 04631 return next; \ 04632 } \ 04633 \ 04634 TYPE *STB__(N,prev)(TYPE *tree, TYPE *item) \ 04635 { \ 04636 TYPE *next = NULL; \ 04637 if (item->STB_(N,left)) \ 04638 return STB__(N,last)(item->STB_(N,left)); \ 04639 PAR( \ 04640 while(item->STB_(N,parent)) { \ 04641 TYPE *up = item->STB_(N,parent); \ 04642 if (up->STB_(N,right) == item) return up; \ 04643 item = up; \ 04644 } \ 04645 return NULL; \ 04646 ) \ 04647 while (tree != item) { \ 04648 if (STB_(N,_compare)(item, tree) < 0) { \ 04649 tree = tree->STB_(N,left); \ 04650 } else { \ 04651 next = tree; \ 04652 tree = tree->STB_(N,right); \ 04653 } \ 04654 } \ 04655 return next; \ 04656 } \ 04657 \ 04658 STB__DEBUG( \ 04659 void STB__(N,_validate)(TYPE *tree, int root) \ 04660 { \ 04661 if (tree == NULL) return; \ 04662 PAR(if(root) assert(tree->STB_(N,parent) == NULL);) \ 04663 assert(STB__level(N,tree->STB_(N,left) ) == tree->STB_(N,level)-1); \ 04664 assert(STB__level(N,tree->STB_(N,right)) <= tree->STB_(N,level)); \ 04665 assert(STB__level(N,tree->STB_(N,right)) >= tree->STB_(N,level)-1); \ 04666 if (tree->STB_(N,right)) { \ 04667 assert(STB__level(N,tree->STB_(N,right)->STB_(N,right)) \ 04668 != tree->STB_(N,level)); \ 04669 PAR(assert(tree->STB_(N,right)->STB_(N,parent) == tree);) \ 04670 } \ 04671 PAR(if(tree->STB_(N,left)) assert(tree->STB_(N,left)->STB_(N,parent) == tree);) \ 04672 STB__(N,_validate)(tree->STB_(N,left) ,0); \ 04673 STB__(N,_validate)(tree->STB_(N,right),0); \ 04674 } \ 04675 ) \ 04676 \ 04677 typedef struct \ 04678 { \ 04679 TYPE *root; \ 04680 } TREE; \ 04681 \ 04682 void STB__(M,Insert)(TREE *tree, TYPE *item) \ 04683 { tree->root = STB__(N,insert)(tree->root, item); } \ 04684 void STB__(M,Remove)(TREE *tree, TYPE *item) \ 04685 { tree->root = STB__(N,remove)(tree->root, item); } \ 04686 TYPE *STB__(M,Next)(TREE *tree, TYPE *item) \ 04687 { return STB__(N,next)(tree->root, item); } \ 04688 TYPE *STB__(M,Prev)(TREE *tree, TYPE *item) \ 04689 { return STB__(N,prev)(tree->root, item); } \ 04690 TYPE *STB__(M,First)(TREE *tree) { return STB__(N,first)(tree->root); } \ 04691 TYPE *STB__(M,Last) (TREE *tree) { return STB__(N,last) (tree->root); } \ 04692 void STB__(M,Init)(TREE *tree) { tree->root = NULL; } 04693 04694 04695 #define stb_bst_find(N,tree,fcompare) \ 04696 { \ 04697 int c; \ 04698 while (tree != NULL) { \ 04699 fcompare \ 04700 if (c == 0) return tree; \ 04701 if (c < 0) tree = tree->STB_(N,left); \ 04702 else tree = tree->STB_(N,right); \ 04703 } \ 04704 return NULL; \ 04705 } 04706 04707 #define stb_bst_raw(TYPE,N,TREE,M,vfield,VTYPE,compare,PAR) \ 04708 stb_bst_base(TYPE,N,TREE,M, \ 04709 VTYPE a = p->vfield; VTYPE b = q->vfield; return (compare);, PAR ) \ 04710 \ 04711 TYPE *STB__(N,find)(TYPE *tree, VTYPE a) \ 04712 stb_bst_find(N,tree,VTYPE b = tree->vfield; c = (compare);) \ 04713 TYPE *STB__(M,Find)(TREE *tree, VTYPE a) \ 04714 { return STB__(N,find)(tree->root, a); } 04715 04716 #define stb_bst(TYPE,N,TREE,M,vfield,VTYPE,compare) \ 04717 stb_bst_raw(TYPE,N,TREE,M,vfield,VTYPE,compare,stb__bst_noparent) 04718 #define stb_bst_parent(TYPE,N,TREE,M,vfield,VTYPE,compare) \ 04719 stb_bst_raw(TYPE,N,TREE,M,vfield,VTYPE,compare,stb__bst_parent) 04720 04721 04722 04724 // 04725 // Pointer Nulling 04726 // 04727 // This lets you automatically NULL dangling pointers to "registered" 04728 // objects. Note that you have to make sure you call the appropriate 04729 // functions when you free or realloc blocks of memory that contain 04730 // pointers or pointer targets. stb.h can automatically do this for 04731 // stb_arr, or for all frees/reallocs if it's wrapping them. 04732 // 04733 04734 #ifdef STB_NPTR 04735 04736 STB_EXTERN void stb_nptr_set(void *address_of_pointer, void *value_to_write); 04737 STB_EXTERN void stb_nptr_didset(void *address_of_pointer); 04738 04739 STB_EXTERN void stb_nptr_didfree(void *address_being_freed, int len); 04740 STB_EXTERN void stb_nptr_free(void *address_being_freed, int len); 04741 04742 STB_EXTERN void stb_nptr_didrealloc(void *new_address, void *old_address, int len); 04743 STB_EXTERN void stb_nptr_recache(void); // recache all known pointers 04744 // do this after pointer sets outside your control, slow 04745 04746 #ifdef STB_DEFINE 04747 // for fast updating on free/realloc, we need to be able to find 04748 // all the objects (pointers and targets) within a given block; 04749 // this precludes hashing 04750 04751 // we use a three-level hierarchy of memory to minimize storage: 04752 // level 1: 65536 pointers to stb__memory_node (always uses 256 KB) 04753 // level 2: each stb__memory_node represents a 64K block of memory 04754 // with 256 stb__memory_leafs (worst case 64MB) 04755 // level 3: each stb__memory_leaf represents 256 bytes of memory 04756 // using a list of target locations and a list of pointers 04757 // (which are hopefully fairly short normally!) 04758 04759 // this approach won't work in 64-bit, which has a much larger address 04760 // space. need to redesign 04761 04762 #define STB__NPTR_ROOT_LOG2 16 04763 #define STB__NPTR_ROOT_NUM (1 << STB__NPTR_ROOT_LOG2) 04764 #define STB__NPTR_ROOT_SHIFT (32 - STB__NPTR_ROOT_LOG2) 04765 04766 #define STB__NPTR_NODE_LOG2 5 04767 #define STB__NPTR_NODE_NUM (1 << STB__NPTR_NODE_LOG2) 04768 #define STB__NPTR_NODE_MASK (STB__NPTR_NODE_NUM-1) 04769 #define STB__NPTR_NODE_SHIFT (STB__NPTR_ROOT_SHIFT - STB__NPTR_NODE_LOG2) 04770 #define STB__NPTR_NODE_OFFSET(x) (((x) >> STB__NPTR_NODE_SHIFT) & STB__NPTR_NODE_MASK) 04771 04772 typedef struct stb__st_nptr 04773 { 04774 void *ptr; // address of actual pointer 04775 struct stb__st_nptr *next; // next pointer with same target 04776 struct stb__st_nptr **prev; // prev pointer with same target, address of 'next' field (or first) 04777 struct stb__st_nptr *next_in_block; 04778 } stb__nptr; 04779 04780 typedef struct stb__st_nptr_target 04781 { 04782 void *ptr; // address of target 04783 stb__nptr *first; // address of first nptr pointing to this 04784 struct stb__st_nptr_target *next_in_block; 04785 } stb__nptr_target; 04786 04787 typedef struct 04788 { 04789 stb__nptr *pointers; 04790 stb__nptr_target *targets; 04791 } stb__memory_leaf; 04792 04793 typedef struct 04794 { 04795 stb__memory_leaf *children[STB__NPTR_NODE_NUM]; 04796 } stb__memory_node; 04797 04798 stb__memory_node *stb__memtab_root[STB__NPTR_ROOT_NUM]; 04799 04800 static stb__memory_leaf *stb__nptr_find_leaf(void *mem) 04801 { 04802 stb_uint32 address = (stb_uint32) mem; 04803 stb__memory_node *z = stb__memtab_root[address >> STB__NPTR_ROOT_SHIFT]; 04804 if (z) 04805 return z->children[STB__NPTR_NODE_OFFSET(address)]; 04806 else 04807 return NULL; 04808 } 04809 04810 static void * stb__nptr_alloc(int size) 04811 { 04812 return stb__realloc_raw(0,size); 04813 } 04814 04815 static void stb__nptr_free(void *p) 04816 { 04817 stb__realloc_raw(p,0); 04818 } 04819 04820 static stb__memory_leaf *stb__nptr_make_leaf(void *mem) 04821 { 04822 stb_uint32 address = (stb_uint32) mem; 04823 stb__memory_node *z = stb__memtab_root[address >> STB__NPTR_ROOT_SHIFT]; 04824 stb__memory_leaf *f; 04825 if (!z) { 04826 int i; 04827 z = (stb__memory_node *) stb__nptr_alloc(sizeof(*stb__memtab_root[0])); 04828 stb__memtab_root[address >> STB__NPTR_ROOT_SHIFT] = z; 04829 for (i=0; i < 256; ++i) 04830 z->children[i] = 0; 04831 } 04832 f = (stb__memory_leaf *) stb__nptr_alloc(sizeof(*f)); 04833 z->children[STB__NPTR_NODE_OFFSET(address)] = f; 04834 f->pointers = NULL; 04835 f->targets = NULL; 04836 return f; 04837 } 04838 04839 static stb__nptr_target *stb__nptr_find_target(void *target, int force) 04840 { 04841 stb__memory_leaf *p = stb__nptr_find_leaf(target); 04842 if (p) { 04843 stb__nptr_target *t = p->targets; 04844 while (t) { 04845 if (t->ptr == target) 04846 return t; 04847 t = t->next_in_block; 04848 } 04849 } 04850 if (force) { 04851 stb__nptr_target *t = (stb__nptr_target*) stb__nptr_alloc(sizeof(*t)); 04852 if (!p) p = stb__nptr_make_leaf(target); 04853 t->ptr = target; 04854 t->first = NULL; 04855 t->next_in_block = p->targets; 04856 p->targets = t; 04857 return t; 04858 } else 04859 return NULL; 04860 } 04861 04862 static stb__nptr *stb__nptr_find_pointer(void *ptr, int force) 04863 { 04864 stb__memory_leaf *p = stb__nptr_find_leaf(ptr); 04865 if (p) { 04866 stb__nptr *t = p->pointers; 04867 while (t) { 04868 if (t->ptr == ptr) 04869 return t; 04870 t = t->next_in_block; 04871 } 04872 } 04873 if (force) { 04874 stb__nptr *t = (stb__nptr *) stb__nptr_alloc(sizeof(*t)); 04875 if (!p) p = stb__nptr_make_leaf(ptr); 04876 t->ptr = ptr; 04877 t->next = NULL; 04878 t->prev = NULL; 04879 t->next_in_block = p->pointers; 04880 p->pointers = t; 04881 return t; 04882 } else 04883 return NULL; 04884 } 04885 04886 void stb_nptr_set(void *address_of_pointer, void *value_to_write) 04887 { 04888 if (*(void **)address_of_pointer != value_to_write) { 04889 *(void **) address_of_pointer = value_to_write; 04890 stb_nptr_didset(address_of_pointer); 04891 } 04892 } 04893 04894 void stb_nptr_didset(void *address_of_pointer) 04895 { 04896 // first unlink from old chain 04897 void *new_address; 04898 stb__nptr *p = stb__nptr_find_pointer(address_of_pointer, 1); // force building if doesn't exist 04899 if (p->prev) { // if p->prev is NULL, we just built it, or it was NULL 04900 *(p->prev) = p->next; 04901 if (p->next) p->next->prev = p->prev; 04902 } 04903 // now add to new chain 04904 new_address = *(void **)address_of_pointer; 04905 if (new_address != NULL) { 04906 stb__nptr_target *t = stb__nptr_find_target(new_address, 1); 04907 p->next = t->first; 04908 if (p->next) p->next->prev = &p->next; 04909 p->prev = &t->first; 04910 t->first = p; 04911 } else { 04912 p->prev = NULL; 04913 p->next = NULL; 04914 } 04915 } 04916 04917 void stb__nptr_block(void *address, int len, void (*function)(stb__memory_leaf *f, int datum, void *start, void *end), int datum) 04918 { 04919 void *end_address = (void *) ((char *) address + len - 1); 04920 stb__memory_node *n; 04921 stb_uint32 start = (stb_uint32) address; 04922 stb_uint32 end = start + len - 1; 04923 04924 int b0 = start >> STB__NPTR_ROOT_SHIFT; 04925 int b1 = end >> STB__NPTR_ROOT_SHIFT; 04926 int b=b0,i,e0,e1; 04927 04928 e0 = STB__NPTR_NODE_OFFSET(start); 04929 04930 if (datum <= 0) { 04931 // first block 04932 n = stb__memtab_root[b0]; 04933 if (n) { 04934 if (b0 != b1) 04935 e1 = STB__NPTR_NODE_NUM-1; 04936 else 04937 e1 = STB__NPTR_NODE_OFFSET(end); 04938 for (i=e0; i <= e1; ++i) 04939 if (n->children[i]) 04940 function(n->children[i], datum, address, end_address); 04941 } 04942 if (b1 > b0) { 04943 // blocks other than the first and last block 04944 for (b=b0+1; b < b1; ++b) { 04945 n = stb__memtab_root[b]; 04946 if (n) 04947 for (i=0; i <= STB__NPTR_NODE_NUM-1; ++i) 04948 if (n->children[i]) 04949 function(n->children[i], datum, address, end_address); 04950 } 04951 // last block 04952 n = stb__memtab_root[b1]; 04953 if (n) { 04954 e1 = STB__NPTR_NODE_OFFSET(end); 04955 for (i=0; i <= e1; ++i) 04956 if (n->children[i]) 04957 function(n->children[i], datum, address, end_address); 04958 } 04959 } 04960 } else { 04961 if (b1 > b0) { 04962 // last block 04963 n = stb__memtab_root[b1]; 04964 if (n) { 04965 e1 = STB__NPTR_NODE_OFFSET(end); 04966 for (i=e1; i >= 0; --i) 04967 if (n->children[i]) 04968 function(n->children[i], datum, address, end_address); 04969 } 04970 // blocks other than the first and last block 04971 for (b=b1-1; b > b0; --b) { 04972 n = stb__memtab_root[b]; 04973 if (n) 04974 for (i=STB__NPTR_NODE_NUM-1; i >= 0; --i) 04975 if (n->children[i]) 04976 function(n->children[i], datum, address, end_address); 04977 } 04978 } 04979 // first block 04980 n = stb__memtab_root[b0]; 04981 if (n) { 04982 if (b0 != b1) 04983 e1 = STB__NPTR_NODE_NUM-1; 04984 else 04985 e1 = STB__NPTR_NODE_OFFSET(end); 04986 for (i=e1; i >= e0; --i) 04987 if (n->children[i]) 04988 function(n->children[i], datum, address, end_address); 04989 } 04990 } 04991 } 04992 04993 static void stb__nptr_delete_pointers(stb__memory_leaf *f, int offset, void *start, void *end) 04994 { 04995 stb__nptr **p = &f->pointers; 04996 while (*p) { 04997 stb__nptr *n = *p; 04998 if (n->ptr >= start && n->ptr <= end) { 04999 // unlink 05000 if (n->prev) { 05001 *(n->prev) = n->next; 05002 if (n->next) n->next->prev = n->prev; 05003 } 05004 *p = n->next_in_block; 05005 stb__nptr_free(n); 05006 } else 05007 p = &(n->next_in_block); 05008 } 05009 } 05010 05011 static void stb__nptr_delete_targets(stb__memory_leaf *f, int offset, void *start, void *end) 05012 { 05013 stb__nptr_target **p = &f->targets; 05014 while (*p) { 05015 stb__nptr_target *n = *p; 05016 if (n->ptr >= start && n->ptr <= end) { 05017 // null pointers 05018 stb__nptr *z = n->first; 05019 while (z) { 05020 stb__nptr *y = z->next; 05021 z->prev = NULL; 05022 z->next = NULL; 05023 *(void **) z->ptr = NULL; 05024 z = y; 05025 } 05026 // unlink this target 05027 *p = n->next_in_block; 05028 stb__nptr_free(n); 05029 } else 05030 p = &(n->next_in_block); 05031 } 05032 } 05033 05034 void stb_nptr_didfree(void *address_being_freed, int len) 05035 { 05036 // step one: delete all pointers in this block 05037 stb__nptr_block(address_being_freed, len, stb__nptr_delete_pointers, 0); 05038 // step two: NULL all pointers to this block; do this second to avoid NULLing deleted pointers 05039 stb__nptr_block(address_being_freed, len, stb__nptr_delete_targets, 0); 05040 } 05041 05042 void stb_nptr_free(void *address_being_freed, int len) 05043 { 05044 free(address_being_freed); 05045 stb_nptr_didfree(address_being_freed, len); 05046 } 05047 05048 static void stb__nptr_move_targets(stb__memory_leaf *f, int offset, void *start, void *end) 05049 { 05050 stb__nptr_target **t = &f->targets; 05051 while (*t) { 05052 stb__nptr_target *n = *t; 05053 if (n->ptr >= start && n->ptr <= end) { 05054 stb__nptr *z; 05055 stb__memory_leaf *f; 05056 // unlink n 05057 *t = n->next_in_block; 05058 // update n to new address 05059 n->ptr = (void *) ((char *) n->ptr + offset); 05060 f = stb__nptr_find_leaf(n->ptr); 05061 if (!f) f = stb__nptr_make_leaf(n->ptr); 05062 n->next_in_block = f->targets; 05063 f->targets = n; 05064 // now go through all pointers and make them point here 05065 z = n->first; 05066 while (z) { 05067 *(void**) z->ptr = n->ptr; 05068 z = z->next; 05069 } 05070 } else 05071 t = &(n->next_in_block); 05072 } 05073 } 05074 05075 static void stb__nptr_move_pointers(stb__memory_leaf *f, int offset, void *start, void *end) 05076 { 05077 stb__nptr **p = &f->pointers; 05078 while (*p) { 05079 stb__nptr *n = *p; 05080 if (n->ptr >= start && n->ptr <= end) { 05081 // unlink 05082 *p = n->next_in_block; 05083 n->ptr = (void *) ((int) n->ptr + offset); 05084 // move to new block 05085 f = stb__nptr_find_leaf(n->ptr); 05086 if (!f) f = stb__nptr_make_leaf(n->ptr); 05087 n->next_in_block = f->pointers; 05088 f->pointers = n; 05089 } else 05090 p = &(n->next_in_block); 05091 } 05092 } 05093 05094 void stb_nptr_realloc(void *new_address, void *old_address, int len) 05095 { 05096 if (new_address == old_address) return; 05097 05098 // have to move the pointers first, because moving the targets 05099 // requires writing to the pointers-to-the-targets, and if some of those moved too, 05100 // we need to make sure we don't write to the old memory 05101 05102 // step one: move all pointers within the block 05103 stb__nptr_block(old_address, len, stb__nptr_move_pointers, (char *) new_address - (char *) old_address); 05104 // step two: move all targets within the block 05105 stb__nptr_block(old_address, len, stb__nptr_move_targets, (char *) new_address - (char *) old_address); 05106 } 05107 05108 void stb_nptr_move(void *new_address, void *old_address) 05109 { 05110 stb_nptr_realloc(new_address, old_address, 1); 05111 } 05112 05113 void stb_nptr_recache(void) 05114 { 05115 int i,j; 05116 for (i=0; i < STB__NPTR_ROOT_NUM; ++i) 05117 if (stb__memtab_root[i]) 05118 for (j=0; j < STB__NPTR_NODE_NUM; ++j) 05119 if (stb__memtab_root[i]->children[j]) { 05120 stb__nptr *p = stb__memtab_root[i]->children[j]->pointers; 05121 while (p) { 05122 stb_nptr_didset(p->ptr); 05123 p = p->next_in_block; 05124 } 05125 } 05126 } 05127 05128 #endif // STB_DEFINE 05129 #endif // STB_NPTR 05130 05131 05133 // 05134 // File Processing 05135 // 05136 05137 05138 #ifdef _WIN32 05139 #define stb_rename(x,y) _wrename((const wchar_t *)stb__from_utf8(x), (const wchar_t *)stb__from_utf8_alt(y)) 05140 #else 05141 #define stb_rename rename 05142 #endif 05143 05144 STB_EXTERN void stb_fput_varlen64(FILE *f, stb_uint64 v); 05145 STB_EXTERN stb_uint64 stb_fget_varlen64(FILE *f); 05146 STB_EXTERN int stb_size_varlen64(stb_uint64 v); 05147 05148 05149 #define stb_filec (char *) stb_file 05150 #define stb_fileu (unsigned char *) stb_file 05151 STB_EXTERN void * stb_file(char *filename, size_t *length); 05152 STB_EXTERN void * stb_file_max(char *filename, size_t *length); 05153 STB_EXTERN size_t stb_filelen(FILE *f); 05154 STB_EXTERN int stb_filewrite(char *filename, void *data, size_t length); 05155 STB_EXTERN int stb_filewritestr(char *filename, char *data); 05156 STB_EXTERN char ** stb_stringfile(char *filename, int *len); 05157 STB_EXTERN char ** stb_stringfile_trimmed(char *name, int *len, char comm); 05158 STB_EXTERN char * stb_fgets(char *buffer, int buflen, FILE *f); 05159 STB_EXTERN char * stb_fgets_malloc(FILE *f); 05160 STB_EXTERN int stb_fexists(char *filename); 05161 STB_EXTERN int stb_fcmp(char *s1, char *s2); 05162 STB_EXTERN int stb_feq(char *s1, char *s2); 05163 STB_EXTERN time_t stb_ftimestamp(char *filename); 05164 05165 STB_EXTERN int stb_fullpath(char *abs, int abs_size, char *rel); 05166 STB_EXTERN FILE * stb_fopen(char *filename, const char *mode); 05167 STB_EXTERN int stb_fclose(FILE *f, int keep); 05168 05169 enum 05170 { 05171 stb_keep_no = 0, 05172 stb_keep_yes = 1, 05173 stb_keep_if_different = 2, 05174 }; 05175 05176 STB_EXTERN int stb_copyfile(char *src, char *dest); 05177 05178 STB_EXTERN void stb_fput_varlen64(FILE *f, stb_uint64 v); 05179 STB_EXTERN stb_uint64 stb_fget_varlen64(FILE *f); 05180 STB_EXTERN int stb_size_varlen64(stb_uint64 v); 05181 05182 STB_EXTERN void stb_fwrite32(FILE *f, stb_uint32 datum); 05183 STB_EXTERN void stb_fput_varlen (FILE *f, int v); 05184 STB_EXTERN void stb_fput_varlenu(FILE *f, unsigned int v); 05185 STB_EXTERN int stb_fget_varlen (FILE *f); 05186 STB_EXTERN stb_uint stb_fget_varlenu(FILE *f); 05187 STB_EXTERN void stb_fput_ranged (FILE *f, int v, int b, stb_uint n); 05188 STB_EXTERN int stb_fget_ranged (FILE *f, int b, stb_uint n); 05189 STB_EXTERN int stb_size_varlen (int v); 05190 STB_EXTERN int stb_size_varlenu(unsigned int v); 05191 STB_EXTERN int stb_size_ranged (int b, stb_uint n); 05192 05193 STB_EXTERN int stb_fread(void *data, size_t len, size_t count, void *f); 05194 STB_EXTERN int stb_fwrite(void *data, size_t len, size_t count, void *f); 05195 05196 #if 0 05197 typedef struct 05198 { 05199 FILE *base_file; 05200 char *buffer; 05201 int buffer_size; 05202 int buffer_off; 05203 int buffer_left; 05204 } STBF; 05205 05206 STB_EXTERN STBF *stb_tfopen(char *filename, char *mode); 05207 STB_EXTERN int stb_tfread(void *data, size_t len, size_t count, STBF *f); 05208 STB_EXTERN int stb_tfwrite(void *data, size_t len, size_t count, STBF *f); 05209 #endif 05210 05211 #ifdef STB_DEFINE 05212 05213 #if 0 05214 STBF *stb_tfopen(char *filename, char *mode) 05215 { 05216 STBF *z; 05217 FILE *f = stb_p_fopen(filename, mode); 05218 if (!f) return NULL; 05219 z = (STBF *) malloc(sizeof(*z)); 05220 if (!z) { fclose(f); return NULL; } 05221 z->base_file = f; 05222 if (!strcmp(mode, "rb") || !strcmp(mode, "wb")) { 05223 z->buffer_size = 4096; 05224 z->buffer_off = z->buffer_size; 05225 z->buffer_left = 0; 05226 z->buffer = malloc(z->buffer_size); 05227 if (!z->buffer) { free(z); fclose(f); return NULL; } 05228 } else { 05229 z->buffer = 0; 05230 z->buffer_size = 0; 05231 z->buffer_left = 0; 05232 } 05233 return z; 05234 } 05235 05236 int stb_tfread(void *data, size_t len, size_t count, STBF *f) 05237 { 05238 int total = len*count, done=0; 05239 if (!total) return 0; 05240 if (total <= z->buffer_left) { 05241 memcpy(data, z->buffer + z->buffer_off, total); 05242 z->buffer_off += total; 05243 z->buffer_left -= total; 05244 return count; 05245 } else { 05246 char *out = (char *) data; 05247 05248 // consume all buffered data 05249 memcpy(data, z->buffer + z->buffer_off, z->buffer_left); 05250 done = z->buffer_left; 05251 out += z->buffer_left; 05252 z->buffer_left=0; 05253 05254 if (total-done > (z->buffer_size >> 1)) { 05255 done += fread(out 05256 } 05257 } 05258 } 05259 #endif 05260 05261 void stb_fwrite32(FILE *f, stb_uint32 x) 05262 { 05263 fwrite(&x, 4, 1, f); 05264 } 05265 05266 #if defined(_WIN32) 05267 #define stb__stat _stat 05268 #else 05269 #define stb__stat stat 05270 #endif 05271 05272 int stb_fexists(char *filename) 05273 { 05274 struct stb__stat buf; 05275 return stb__windows( 05276 _wstat((const wchar_t *)stb__from_utf8(filename), &buf), 05277 stat(filename,&buf) 05278 ) == 0; 05279 } 05280 05281 time_t stb_ftimestamp(char *filename) 05282 { 05283 struct stb__stat buf; 05284 if (stb__windows( 05285 _wstat((const wchar_t *)stb__from_utf8(filename), &buf), 05286 stat(filename,&buf) 05287 ) == 0) 05288 { 05289 return buf.st_mtime; 05290 } else { 05291 return 0; 05292 } 05293 } 05294 05295 size_t stb_filelen(FILE *f) 05296 { 05297 long len, pos; 05298 pos = ftell(f); 05299 fseek(f, 0, SEEK_END); 05300 len = ftell(f); 05301 fseek(f, pos, SEEK_SET); 05302 return (size_t) len; 05303 } 05304 05305 void *stb_file(char *filename, size_t *length) 05306 { 05307 FILE *f = stb__fopen(filename, "rb"); 05308 char *buffer; 05309 size_t len, len2; 05310 if (!f) return NULL; 05311 len = stb_filelen(f); 05312 buffer = (char *) malloc(len+2); // nul + extra 05313 len2 = fread(buffer, 1, len, f); 05314 if (len2 == len) { 05315 if (length) *length = len; 05316 buffer[len] = 0; 05317 } else { 05318 free(buffer); 05319 buffer = NULL; 05320 } 05321 fclose(f); 05322 return buffer; 05323 } 05324 05325 int stb_filewrite(char *filename, void *data, size_t length) 05326 { 05327 FILE *f = stb_fopen(filename, "wb"); 05328 if (f) { 05329 unsigned char *data_ptr = (unsigned char *) data; 05330 size_t remaining = length; 05331 while (remaining > 0) { 05332 size_t len2 = remaining > 65536 ? 65536 : remaining; 05333 size_t len3 = fwrite(data_ptr, 1, len2, f); 05334 if (len2 != len3) { 05335 fprintf(stderr, "Failed while writing %s\n", filename); 05336 break; 05337 } 05338 remaining -= len2; 05339 data_ptr += len2; 05340 } 05341 stb_fclose(f, stb_keep_if_different); 05342 } 05343 return f != NULL; 05344 } 05345 05346 int stb_filewritestr(char *filename, char *data) 05347 { 05348 return stb_filewrite(filename, data, strlen(data)); 05349 } 05350 05351 void * stb_file_max(char *filename, size_t *length) 05352 { 05353 FILE *f = stb__fopen(filename, "rb"); 05354 char *buffer; 05355 size_t len, maxlen; 05356 if (!f) return NULL; 05357 maxlen = *length; 05358 buffer = (char *) malloc(maxlen+1); 05359 len = fread(buffer, 1, maxlen, f); 05360 buffer[len] = 0; 05361 fclose(f); 05362 *length = len; 05363 return buffer; 05364 } 05365 05366 char ** stb_stringfile(char *filename, int *plen) 05367 { 05368 FILE *f = stb__fopen(filename, "rb"); 05369 char *buffer, **list=NULL, *s; 05370 size_t len, count, i; 05371 05372 if (!f) return NULL; 05373 len = stb_filelen(f); 05374 buffer = (char *) malloc(len+1); 05375 len = fread(buffer, 1, len, f); 05376 buffer[len] = 0; 05377 fclose(f); 05378 05379 // two passes through: first time count lines, second time set them 05380 for (i=0; i < 2; ++i) { 05381 s = buffer; 05382 if (i == 1) 05383 list[0] = s; 05384 count = 1; 05385 while (*s) { 05386 if (*s == '\n' || *s == '\r') { 05387 // detect if both cr & lf are together 05388 int crlf = (s[0] + s[1]) == ('\n' + '\r'); 05389 if (i == 1) *s = 0; 05390 if (crlf) ++s; 05391 if (s[1]) { // it's not over yet 05392 if (i == 1) list[count] = s+1; 05393 ++count; 05394 } 05395 } 05396 ++s; 05397 } 05398 if (i == 0) { 05399 list = (char **) malloc(sizeof(*list) * (count+1) + len+1); 05400 if (!list) return NULL; 05401 list[count] = 0; 05402 // recopy the file so there's just a single allocation to free 05403 memcpy(&list[count+1], buffer, len+1); 05404 free(buffer); 05405 buffer = (char *) &list[count+1]; 05406 if (plen) *plen = (int) count; 05407 } 05408 } 05409 return list; 05410 } 05411 05412 char ** stb_stringfile_trimmed(char *name, int *len, char comment) 05413 { 05414 int i,n,o=0; 05415 char **s = stb_stringfile(name, &n); 05416 if (s == NULL) return NULL; 05417 for (i=0; i < n; ++i) { 05418 char *p = stb_skipwhite(s[i]); 05419 if (*p && *p != comment) 05420 s[o++] = p; 05421 } 05422 s[o] = NULL; 05423 if (len) *len = o; 05424 return s; 05425 } 05426 05427 char * stb_fgets(char *buffer, int buflen, FILE *f) 05428 { 05429 char *p; 05430 buffer[0] = 0; 05431 p = fgets(buffer, buflen, f); 05432 if (p) { 05433 int n = (int) (strlen(p)-1); 05434 if (n >= 0) 05435 if (p[n] == '\n') 05436 p[n] = 0; 05437 } 05438 return p; 05439 } 05440 05441 char * stb_fgets_malloc(FILE *f) 05442 { 05443 // avoid reallocing for small strings 05444 char quick_buffer[800]; 05445 quick_buffer[sizeof(quick_buffer)-2] = 0; 05446 if (!fgets(quick_buffer, sizeof(quick_buffer), f)) 05447 return NULL; 05448 05449 if (quick_buffer[sizeof(quick_buffer)-2] == 0) { 05450 size_t n = strlen(quick_buffer); 05451 if (n > 0 && quick_buffer[n-1] == '\n') 05452 quick_buffer[n-1] = 0; 05453 return stb_p_strdup(quick_buffer); 05454 } else { 05455 char *p; 05456 char *a = stb_p_strdup(quick_buffer); 05457 size_t len = sizeof(quick_buffer)-1; 05458 05459 while (!feof(f)) { 05460 if (a[len-1] == '\n') break; 05461 a = (char *) realloc(a, len*2); 05462 p = &a[len]; 05463 p[len-2] = 0; 05464 if (!fgets(p, (int) len, f)) 05465 break; 05466 if (p[len-2] == 0) { 05467 len += strlen(p); 05468 break; 05469 } 05470 len = len + (len-1); 05471 } 05472 if (a[len-1] == '\n') 05473 a[len-1] = 0; 05474 return a; 05475 } 05476 } 05477 05478 int stb_fullpath(char *abs, int abs_size, char *rel) 05479 { 05480 #ifdef _WIN32 05481 return _fullpath(abs, rel, abs_size) != NULL; 05482 #else 05483 if (rel[0] == '/' || rel[0] == '~') { 05484 if ((int) strlen(rel) >= abs_size) 05485 return 0; 05486 stb_p_strcpy_s(abs,65536,rel); 05487 return STB_TRUE; 05488 } else { 05489 int n; 05490 getcwd(abs, abs_size); 05491 n = strlen(abs); 05492 if (n+(int) strlen(rel)+2 <= abs_size) { 05493 abs[n] = '/'; 05494 stb_p_strcpy_s(abs+n+1, 65536,rel); 05495 return STB_TRUE; 05496 } else { 05497 return STB_FALSE; 05498 } 05499 } 05500 #endif 05501 } 05502 05503 static int stb_fcmp_core(FILE *f, FILE *g) 05504 { 05505 char buf1[1024],buf2[1024]; 05506 int n1,n2, res=0; 05507 05508 while (1) { 05509 n1 = (int) fread(buf1, 1, sizeof(buf1), f); 05510 n2 = (int) fread(buf2, 1, sizeof(buf2), g); 05511 res = memcmp(buf1,buf2,stb_min(n1,n2)); 05512 if (res) 05513 break; 05514 if (n1 != n2) { 05515 res = n1 < n2 ? -1 : 1; 05516 break; 05517 } 05518 if (n1 == 0) 05519 break; 05520 } 05521 05522 fclose(f); 05523 fclose(g); 05524 return res; 05525 } 05526 05527 int stb_fcmp(char *s1, char *s2) 05528 { 05529 FILE *f = stb__fopen(s1, "rb"); 05530 FILE *g = stb__fopen(s2, "rb"); 05531 05532 if (f == NULL || g == NULL) { 05533 if (f) fclose(f); 05534 if (g) { 05535 fclose(g); 05536 return STB_TRUE; 05537 } 05538 return f != NULL; 05539 } 05540 05541 return stb_fcmp_core(f,g); 05542 } 05543 05544 int stb_feq(char *s1, char *s2) 05545 { 05546 FILE *f = stb__fopen(s1, "rb"); 05547 FILE *g = stb__fopen(s2, "rb"); 05548 05549 if (f == NULL || g == NULL) { 05550 if (f) fclose(f); 05551 if (g) fclose(g); 05552 return f == g; 05553 } 05554 05555 // feq is faster because it shortcuts if they're different length 05556 if (stb_filelen(f) != stb_filelen(g)) { 05557 fclose(f); 05558 fclose(g); 05559 return 0; 05560 } 05561 05562 return !stb_fcmp_core(f,g); 05563 } 05564 05565 static stb_ptrmap *stb__files; 05566 05567 typedef struct 05568 { 05569 char *temp_name; 05570 char *name; 05571 int errors; 05572 } stb__file_data; 05573 05574 static FILE *stb__open_temp_file(char *temp_name, char *src_name, const char *mode) 05575 { 05576 size_t p; 05577 #ifdef _MSC_VER 05578 int j; 05579 #endif 05580 FILE *f; 05581 // try to generate a temporary file in the same directory 05582 p = strlen(src_name)-1; 05583 while (p > 0 && src_name[p] != '/' && src_name[p] != '\\' 05584 && src_name[p] != ':' && src_name[p] != '~') 05585 --p; 05586 ++p; 05587 05588 memcpy(temp_name, src_name, p); 05589 05590 #ifdef _MSC_VER 05591 // try multiple times to make a temp file... just in 05592 // case some other process makes the name first 05593 for (j=0; j < 32; ++j) { 05594 stb_p_strcpy_s(temp_name+p, 65536, "stmpXXXXXX"); 05595 if (!stb_p_mktemp(temp_name)) 05596 return 0; 05597 05598 f = stb_p_fopen(temp_name, mode); 05599 if (f != NULL) 05600 break; 05601 } 05602 #else 05603 { 05604 stb_p_strcpy_s(temp_name+p, 65536, "stmpXXXXXX"); 05605 #ifdef __MINGW32__ 05606 int fd = open(stb_p_mktemp(temp_name), O_RDWR); 05607 #else 05608 int fd = mkstemp(temp_name); 05609 #endif 05610 if (fd == -1) return NULL; 05611 f = fdopen(fd, mode); 05612 if (f == NULL) { 05613 unlink(temp_name); 05614 close(fd); 05615 return NULL; 05616 } 05617 } 05618 #endif 05619 return f; 05620 } 05621 05622 05623 FILE * stb_fopen(char *filename, const char *mode) 05624 { 05625 FILE *f; 05626 char name_full[4096]; 05627 char temp_full[sizeof(name_full) + 12]; 05628 05629 // @TODO: if the file doesn't exist, we can also use the fastpath here 05630 if (mode[0] != 'w' && !strchr(mode, '+')) 05631 return stb__fopen(filename, mode); 05632 05633 // save away the full path to the file so if the program 05634 // changes the cwd everything still works right! unix has 05635 // better ways to do this, but we have to work in windows 05636 name_full[0] = '\0'; // stb_fullpath reads name_full[0] 05637 if (stb_fullpath(name_full, sizeof(name_full), filename)==0) 05638 return 0; 05639 05640 f = stb__open_temp_file(temp_full, name_full, mode); 05641 if (f != NULL) { 05642 stb__file_data *d = (stb__file_data *) malloc(sizeof(*d)); 05643 if (!d) { assert(0); /* NOTREACHED */fclose(f); return NULL; } 05644 if (stb__files == NULL) stb__files = stb_ptrmap_create(); 05645 d->temp_name = stb_p_strdup(temp_full); 05646 d->name = stb_p_strdup(name_full); 05647 d->errors = 0; 05648 stb_ptrmap_add(stb__files, f, d); 05649 return f; 05650 } 05651 05652 return NULL; 05653 } 05654 05655 int stb_fclose(FILE *f, int keep) 05656 { 05657 stb__file_data *d; 05658 05659 int ok = STB_FALSE; 05660 if (f == NULL) return 0; 05661 05662 if (ferror(f)) 05663 keep = stb_keep_no; 05664 05665 fclose(f); 05666 05667 if (stb__files && stb_ptrmap_remove(stb__files, f, (void **) &d)) { 05668 if (stb__files->count == 0) { 05669 stb_ptrmap_destroy(stb__files); 05670 stb__files = NULL; 05671 } 05672 } else 05673 return STB_TRUE; // not special 05674 05675 if (keep == stb_keep_if_different) { 05676 // check if the files are identical 05677 if (stb_feq(d->name, d->temp_name)) { 05678 keep = stb_keep_no; 05679 ok = STB_TRUE; // report success if no change 05680 } 05681 } 05682 05683 if (keep == stb_keep_no) { 05684 remove(d->temp_name); 05685 } else { 05686 if (!stb_fexists(d->name)) { 05687 // old file doesn't exist, so just move the new file over it 05688 stb_rename(d->temp_name, d->name); 05689 } else { 05690 // don't delete the old file yet in case there are troubles! First rename it! 05691 char preserved_old_file[4096]; 05692 05693 // generate a temp filename in the same directory (also creates it, which we don't need) 05694 FILE *dummy = stb__open_temp_file(preserved_old_file, d->name, "wb"); 05695 if (dummy != NULL) { 05696 // we don't actually want the open file 05697 fclose(dummy); 05698 05699 // discard what we just created 05700 remove(preserved_old_file); // if this fails, there's nothing we can do, and following logic handles it as best as possible anyway 05701 05702 // move the existing file to the preserved name 05703 if (0 != stb_rename(d->name, preserved_old_file)) { // 0 on success 05704 // failed, state is: 05705 // filename -> old file 05706 // tempname -> new file 05707 // keep tempname around so we don't lose data 05708 } else { 05709 // state is: 05710 // preserved -> old file 05711 // tempname -> new file 05712 // move the new file to the old name 05713 if (0 == stb_rename(d->temp_name, d->name)) { 05714 // state is: 05715 // preserved -> old file 05716 // filename -> new file 05717 ok = STB_TRUE; 05718 05719 // 'filename -> new file' has always been the goal, so clean up 05720 remove(preserved_old_file); // nothing to be done if it fails 05721 } else { 05722 // couldn't rename, so try renaming preserved file back 05723 05724 // state is: 05725 // preserved -> old file 05726 // tempname -> new file 05727 stb_rename(preserved_old_file, d->name); 05728 // if the rename failed, there's nothing more we can do 05729 } 05730 } 05731 } else { 05732 // we couldn't get a temp filename. do this the naive way; the worst case failure here 05733 // leaves the filename pointing to nothing and the new file as a tempfile 05734 remove(d->name); 05735 stb_rename(d->temp_name, d->name); 05736 } 05737 } 05738 } 05739 05740 free(d->temp_name); 05741 free(d->name); 05742 free(d); 05743 05744 return ok; 05745 } 05746 05747 int stb_copyfile(char *src, char *dest) 05748 { 05749 char raw_buffer[1024]; 05750 char *buffer; 05751 int buf_size = 65536; 05752 05753 FILE *f, *g; 05754 05755 // if file already exists at destination, do nothing 05756 if (stb_feq(src, dest)) return STB_TRUE; 05757 05758 // open file 05759 f = stb__fopen(src, "rb"); 05760 if (f == NULL) return STB_FALSE; 05761 05762 // open file for writing 05763 g = stb__fopen(dest, "wb"); 05764 if (g == NULL) { 05765 fclose(f); 05766 return STB_FALSE; 05767 } 05768 05769 buffer = (char *) malloc(buf_size); 05770 if (buffer == NULL) { 05771 buffer = raw_buffer; 05772 buf_size = sizeof(raw_buffer); 05773 } 05774 05775 while (!feof(f)) { 05776 size_t n = fread(buffer, 1, buf_size, f); 05777 if (n != 0) 05778 fwrite(buffer, 1, n, g); 05779 } 05780 05781 fclose(f); 05782 if (buffer != raw_buffer) 05783 free(buffer); 05784 05785 fclose(g); 05786 return STB_TRUE; 05787 } 05788 05789 // varlen: 05790 // v' = (v >> 31) + (v < 0 ? ~v : v)<<1; // small abs(v) => small v' 05791 // output v as big endian v'+k for v' <= k: 05792 // 1 byte : v' <= 0x00000080 ( -64 <= v < 64) 7 bits 05793 // 2 bytes: v' <= 0x00004000 (-8192 <= v < 8192) 14 bits 05794 // 3 bytes: v' <= 0x00200000 21 bits 05795 // 4 bytes: v' <= 0x10000000 28 bits 05796 // the number of most significant 1-bits in the first byte 05797 // equals the number of bytes after the first 05798 05799 #define stb__varlen_xform(v) (v<0 ? (~v << 1)+1 : (v << 1)) 05800 05801 int stb_size_varlen(int v) { return stb_size_varlenu(stb__varlen_xform(v)); } 05802 int stb_size_varlenu(unsigned int v) 05803 { 05804 if (v < 0x00000080) return 1; 05805 if (v < 0x00004000) return 2; 05806 if (v < 0x00200000) return 3; 05807 if (v < 0x10000000) return 4; 05808 return 5; 05809 } 05810 05811 void stb_fput_varlen(FILE *f, int v) { stb_fput_varlenu(f, stb__varlen_xform(v)); } 05812 05813 void stb_fput_varlenu(FILE *f, unsigned int z) 05814 { 05815 if (z >= 0x10000000) fputc(0xF0,f); 05816 if (z >= 0x00200000) fputc((z < 0x10000000 ? 0xE0 : 0)+(z>>24),f); 05817 if (z >= 0x00004000) fputc((z < 0x00200000 ? 0xC0 : 0)+(z>>16),f); 05818 if (z >= 0x00000080) fputc((z < 0x00004000 ? 0x80 : 0)+(z>> 8),f); 05819 fputc(z,f); 05820 } 05821 05822 #define stb_fgetc(f) ((unsigned char) fgetc(f)) 05823 05824 int stb_fget_varlen(FILE *f) 05825 { 05826 unsigned int z = stb_fget_varlenu(f); 05827 return (z & 1) ? ~(z>>1) : (z>>1); 05828 } 05829 05830 unsigned int stb_fget_varlenu(FILE *f) 05831 { 05832 unsigned int z; 05833 unsigned char d; 05834 d = stb_fgetc(f); 05835 05836 if (d >= 0x80) { 05837 if (d >= 0xc0) { 05838 if (d >= 0xe0) { 05839 if (d == 0xf0) z = stb_fgetc(f) << 24; 05840 else z = (d - 0xe0) << 24; 05841 z += stb_fgetc(f) << 16; 05842 } 05843 else 05844 z = (d - 0xc0) << 16; 05845 z += stb_fgetc(f) << 8; 05846 } else 05847 z = (d - 0x80) << 8; 05848 z += stb_fgetc(f); 05849 } else 05850 z = d; 05851 return z; 05852 } 05853 05854 stb_uint64 stb_fget_varlen64(FILE *f) 05855 { 05856 stb_uint64 z; 05857 unsigned char d; 05858 d = stb_fgetc(f); 05859 05860 if (d >= 0x80) { 05861 if (d >= 0xc0) { 05862 if (d >= 0xe0) { 05863 if (d >= 0xf0) { 05864 if (d >= 0xf8) { 05865 if (d >= 0xfc) { 05866 if (d >= 0xfe) { 05867 if (d >= 0xff) 05868 z = (stb_uint64) stb_fgetc(f) << 56; 05869 else 05870 z = (stb_uint64) (d - 0xfe) << 56; 05871 z |= (stb_uint64) stb_fgetc(f) << 48; 05872 } else z = (stb_uint64) (d - 0xfc) << 48; 05873 z |= (stb_uint64) stb_fgetc(f) << 40; 05874 } else z = (stb_uint64) (d - 0xf8) << 40; 05875 z |= (stb_uint64) stb_fgetc(f) << 32; 05876 } else z = (stb_uint64) (d - 0xf0) << 32; 05877 z |= (stb_uint) stb_fgetc(f) << 24; 05878 } else z = (stb_uint) (d - 0xe0) << 24; 05879 z |= (stb_uint) stb_fgetc(f) << 16; 05880 } else z = (stb_uint) (d - 0xc0) << 16; 05881 z |= (stb_uint) stb_fgetc(f) << 8; 05882 } else z = (stb_uint) (d - 0x80) << 8; 05883 z |= stb_fgetc(f); 05884 } else 05885 z = d; 05886 05887 return (z & 1) ? ~(z >> 1) : (z >> 1); 05888 } 05889 05890 int stb_size_varlen64(stb_uint64 v) 05891 { 05892 if (v < 0x00000080) return 1; 05893 if (v < 0x00004000) return 2; 05894 if (v < 0x00200000) return 3; 05895 if (v < 0x10000000) return 4; 05896 if (v < STB_IMM_UINT64(0x0000000800000000)) return 5; 05897 if (v < STB_IMM_UINT64(0x0000040000000000)) return 6; 05898 if (v < STB_IMM_UINT64(0x0002000000000000)) return 7; 05899 if (v < STB_IMM_UINT64(0x0100000000000000)) return 8; 05900 return 9; 05901 } 05902 05903 void stb_fput_varlen64(FILE *f, stb_uint64 v) 05904 { 05905 stb_uint64 z = stb__varlen_xform(v); 05906 int first=1; 05907 if (z >= STB_IMM_UINT64(0x100000000000000)) { 05908 fputc(0xff,f); 05909 first=0; 05910 } 05911 if (z >= STB_IMM_UINT64(0x02000000000000)) fputc((first ? 0xFE : 0)+(char)(z>>56),f), first=0; 05912 if (z >= STB_IMM_UINT64(0x00040000000000)) fputc((first ? 0xFC : 0)+(char)(z>>48),f), first=0; 05913 if (z >= STB_IMM_UINT64(0x00000800000000)) fputc((first ? 0xF8 : 0)+(char)(z>>40),f), first=0; 05914 if (z >= STB_IMM_UINT64(0x00000010000000)) fputc((first ? 0xF0 : 0)+(char)(z>>32),f), first=0; 05915 if (z >= STB_IMM_UINT64(0x00000000200000)) fputc((first ? 0xE0 : 0)+(char)(z>>24),f), first=0; 05916 if (z >= STB_IMM_UINT64(0x00000000004000)) fputc((first ? 0xC0 : 0)+(char)(z>>16),f), first=0; 05917 if (z >= STB_IMM_UINT64(0x00000000000080)) fputc((first ? 0x80 : 0)+(char)(z>> 8),f), first=0; 05918 fputc((char)z,f); 05919 } 05920 05921 void stb_fput_ranged(FILE *f, int v, int b, stb_uint n) 05922 { 05923 v -= b; 05924 if (n <= (1 << 31)) 05925 assert((stb_uint) v < n); 05926 if (n > (1 << 24)) fputc(v >> 24, f); 05927 if (n > (1 << 16)) fputc(v >> 16, f); 05928 if (n > (1 << 8)) fputc(v >> 8, f); 05929 fputc(v,f); 05930 } 05931 05932 int stb_fget_ranged(FILE *f, int b, stb_uint n) 05933 { 05934 unsigned int v=0; 05935 if (n > (1 << 24)) v += stb_fgetc(f) << 24; 05936 if (n > (1 << 16)) v += stb_fgetc(f) << 16; 05937 if (n > (1 << 8)) v += stb_fgetc(f) << 8; 05938 v += stb_fgetc(f); 05939 return b+v; 05940 } 05941 05942 int stb_size_ranged(int b, stb_uint n) 05943 { 05944 if (n > (1 << 24)) return 4; 05945 if (n > (1 << 16)) return 3; 05946 if (n > (1 << 8)) return 2; 05947 return 1; 05948 } 05949 05950 void stb_fput_string(FILE *f, char *s) 05951 { 05952 size_t len = strlen(s); 05953 stb_fput_varlenu(f, (unsigned int) len); 05954 fwrite(s, 1, len, f); 05955 } 05956 05957 // inverse of the above algorithm 05958 char *stb_fget_string(FILE *f, void *p) 05959 { 05960 char *s; 05961 int len = stb_fget_varlenu(f); 05962 if (len > 4096) return NULL; 05963 s = p ? stb_malloc_string(p, len+1) : (char *) malloc(len+1); 05964 fread(s, 1, len, f); 05965 s[len] = 0; 05966 return s; 05967 } 05968 05969 char *stb_strdup(char *str, void *pool) 05970 { 05971 size_t len = strlen(str); 05972 char *p = stb_malloc_string(pool, len+1); 05973 stb_p_strcpy_s(p, len+1, str); 05974 return p; 05975 } 05976 05977 // strip the trailing '/' or '\\' from a directory so we can refer to it 05978 // as a file for _stat() 05979 char *stb_strip_final_slash(char *t) 05980 { 05981 if (t[0]) { 05982 char *z = t + strlen(t) - 1; 05983 // *z is the last character 05984 if (*z == '\\' || *z == '/') 05985 if (z != t+2 || t[1] != ':') // but don't strip it if it's e.g. "c:/" 05986 *z = 0; 05987 if (*z == '\\') 05988 *z = '/'; // canonicalize to make sure it matches db 05989 } 05990 return t; 05991 } 05992 05993 char *stb_strip_final_slash_regardless(char *t) 05994 { 05995 if (t[0]) { 05996 char *z = t + strlen(t) - 1; 05997 // *z is the last character 05998 if (*z == '\\' || *z == '/') 05999 *z = 0; 06000 if (*z == '\\') 06001 *z = '/'; // canonicalize to make sure it matches db 06002 } 06003 return t; 06004 } 06005 #endif 06006 06008 // 06009 // Options parsing 06010 // 06011 06012 STB_EXTERN char **stb_getopt_param(int *argc, char **argv, char *param); 06013 STB_EXTERN char **stb_getopt(int *argc, char **argv); 06014 STB_EXTERN void stb_getopt_free(char **opts); 06015 06016 #ifdef STB_DEFINE 06017 06018 void stb_getopt_free(char **opts) 06019 { 06020 int i; 06021 char ** o2 = opts; 06022 for (i=0; i < stb_arr_len(o2); ++i) 06023 free(o2[i]); 06024 stb_arr_free(o2); 06025 } 06026 06027 char **stb_getopt(int *argc, char **argv) 06028 { 06029 return stb_getopt_param(argc, argv, (char*) ""); 06030 } 06031 06032 char **stb_getopt_param(int *argc, char **argv, char *param) 06033 { 06034 char ** opts=NULL; 06035 int i,j=1; 06036 for (i=1; i < *argc; ++i) { 06037 if (argv[i][0] != '-') { 06038 argv[j++] = argv[i]; 06039 } else { 06040 if (argv[i][1] == 0) { // plain - == don't parse further options 06041 ++i; 06042 while (i < *argc) 06043 argv[j++] = argv[i++]; 06044 break; 06045 } else if (argv[i][1] == '-') { 06046 // copy argument through including initial '-' for clarity 06047 stb_arr_push(opts, stb_p_strdup(argv[i])); 06048 } else { 06049 int k; 06050 char *q = argv[i]; // traverse options list 06051 for (k=1; q[k]; ++k) { 06052 char *s; 06053 if (strchr(param, q[k])) { // does it take a parameter? 06054 char *t = &q[k+1], z = q[k]; 06055 size_t len=0; 06056 if (*t == 0) { 06057 if (i == *argc-1) { // takes a parameter, but none found 06058 *argc = 0; 06059 stb_getopt_free(opts); 06060 return NULL; 06061 } 06062 t = argv[++i]; 06063 } else 06064 k += (int) strlen(t); 06065 len = strlen(t); 06066 s = (char *) malloc(len+2); 06067 if (!s) return NULL; 06068 s[0] = z; 06069 stb_p_strcpy_s(s+1, len+2, t); 06070 } else { 06071 // no parameter 06072 s = (char *) malloc(2); 06073 if (!s) return NULL; 06074 s[0] = q[k]; 06075 s[1] = 0; 06076 } 06077 stb_arr_push(opts, s); 06078 } 06079 } 06080 } 06081 } 06082 stb_arr_push(opts, NULL); 06083 *argc = j; 06084 return opts; 06085 } 06086 #endif 06087 06088 06090 // 06091 // Portable directory reading 06092 // 06093 06094 STB_EXTERN char **stb_readdir_files (char *dir); 06095 STB_EXTERN char **stb_readdir_files_mask(char *dir, char *wild); 06096 STB_EXTERN char **stb_readdir_subdirs(char *dir); 06097 STB_EXTERN char **stb_readdir_subdirs_mask(char *dir, char *wild); 06098 STB_EXTERN void stb_readdir_free (char **files); 06099 STB_EXTERN char **stb_readdir_recursive(char *dir, char *filespec); 06100 STB_EXTERN void stb_delete_directory_recursive(char *dir); 06101 06102 #ifdef STB_DEFINE 06103 06104 #ifdef _MSC_VER 06105 #include <io.h> 06106 #else 06107 #include <unistd.h> 06108 #include <dirent.h> 06109 #endif 06110 06111 void stb_readdir_free(char **files) 06112 { 06113 char **f2 = files; 06114 int i; 06115 for (i=0; i < stb_arr_len(f2); ++i) 06116 free(f2[i]); 06117 stb_arr_free(f2); 06118 } 06119 06120 static int isdotdirname(char *name) 06121 { 06122 if (name[0] == '.') 06123 return (name[1] == '.') ? !name[2] : !name[1]; 06124 return 0; 06125 } 06126 06127 STB_EXTERN int stb_wildmatchi(char *expr, char *candidate); 06128 static char **readdir_raw(char *dir, int return_subdirs, char *mask) 06129 { 06130 char **results = NULL; 06131 char buffer[4096], with_slash[4096]; 06132 size_t n; 06133 06134 #ifdef _MSC_VER 06135 stb__wchar *ws; 06136 struct _wfinddata_t data; 06137 #ifdef _WIN64 06138 const intptr_t none = -1; 06139 intptr_t z; 06140 #else 06141 const long none = -1; 06142 long z; 06143 #endif 06144 #else // !_MSC_VER 06145 const DIR *none = NULL; 06146 DIR *z; 06147 #endif 06148 06149 n = stb_strscpy(buffer,dir,sizeof(buffer)); 06150 if (!n || n >= sizeof(buffer)) 06151 return NULL; 06152 stb_fixpath(buffer); 06153 n--; 06154 06155 if (n > 0 && (buffer[n-1] != '/')) { 06156 buffer[n++] = '/'; 06157 } 06158 buffer[n] = 0; 06159 if (!stb_strscpy(with_slash,buffer,sizeof(with_slash))) 06160 return NULL; 06161 06162 #ifdef _MSC_VER 06163 if (!stb_strscpy(buffer+n,"*.*",sizeof(buffer)-n)) 06164 return NULL; 06165 ws = stb__from_utf8(buffer); 06166 z = _wfindfirst((const wchar_t *)ws, &data); 06167 #else 06168 z = opendir(dir); 06169 #endif 06170 06171 if (z != none) { 06172 int nonempty = STB_TRUE; 06173 #ifndef _MSC_VER 06174 struct dirent *data = readdir(z); 06175 nonempty = (data != NULL); 06176 #endif 06177 06178 if (nonempty) { 06179 06180 do { 06181 int is_subdir; 06182 #ifdef _MSC_VER 06183 char *name = stb__to_utf8((stb__wchar *)data.name); 06184 if (name == NULL) { 06185 fprintf(stderr, "%s to convert '%S' to %s!\n", "Unable", data.name, "utf8"); 06186 continue; 06187 } 06188 is_subdir = !!(data.attrib & _A_SUBDIR); 06189 #else 06190 char *name = data->d_name; 06191 if (!stb_strscpy(buffer+n,name,sizeof(buffer)-n)) 06192 break; 06193 // Could follow DT_LNK, but would need to check for recursive links. 06194 is_subdir = !!(data->d_type & DT_DIR); 06195 #endif 06196 06197 if (is_subdir == return_subdirs) { 06198 if (!is_subdir || !isdotdirname(name)) { 06199 if (!mask || stb_wildmatchi(mask, name)) { 06200 char buffer[4096],*p=buffer; 06201 if ( stb_snprintf(buffer, sizeof(buffer), "%s%s", with_slash, name) < 0 ) 06202 break; 06203 if (buffer[0] == '.' && buffer[1] == '/') 06204 p = buffer+2; 06205 stb_arr_push(results, stb_p_strdup(p)); 06206 } 06207 } 06208 } 06209 } 06210 #ifdef _MSC_VER 06211 while (0 == _wfindnext(z, &data)); 06212 #else 06213 while ((data = readdir(z)) != NULL); 06214 #endif 06215 } 06216 #ifdef _MSC_VER 06217 _findclose(z); 06218 #else 06219 closedir(z); 06220 #endif 06221 } 06222 return results; 06223 } 06224 06225 char **stb_readdir_files (char *dir) { return readdir_raw(dir, 0, NULL); } 06226 char **stb_readdir_subdirs(char *dir) { return readdir_raw(dir, 1, NULL); } 06227 char **stb_readdir_files_mask(char *dir, char *wild) { return readdir_raw(dir, 0, wild); } 06228 char **stb_readdir_subdirs_mask(char *dir, char *wild) { return readdir_raw(dir, 1, wild); } 06229 06230 int stb__rec_max=0x7fffffff; 06231 static char **stb_readdir_rec(char **sofar, char *dir, char *filespec) 06232 { 06233 char **files; 06234 char ** dirs; 06235 char **p; 06236 06237 if (stb_arr_len(sofar) >= stb__rec_max) return sofar; 06238 06239 files = stb_readdir_files_mask(dir, filespec); 06240 stb_arr_for(p, files) { 06241 stb_arr_push(sofar, stb_p_strdup(*p)); 06242 if (stb_arr_len(sofar) >= stb__rec_max) break; 06243 } 06244 stb_readdir_free(files); 06245 if (stb_arr_len(sofar) >= stb__rec_max) return sofar; 06246 06247 dirs = stb_readdir_subdirs(dir); 06248 stb_arr_for(p, dirs) 06249 sofar = stb_readdir_rec(sofar, *p, filespec); 06250 stb_readdir_free(dirs); 06251 return sofar; 06252 } 06253 06254 char **stb_readdir_recursive(char *dir, char *filespec) 06255 { 06256 return stb_readdir_rec(NULL, dir, filespec); 06257 } 06258 06259 void stb_delete_directory_recursive(char *dir) 06260 { 06261 char **list = stb_readdir_subdirs(dir); 06262 int i; 06263 for (i=0; i < stb_arr_len(list); ++i) 06264 stb_delete_directory_recursive(list[i]); 06265 stb_arr_free(list); 06266 list = stb_readdir_files(dir); 06267 for (i=0; i < stb_arr_len(list); ++i) 06268 if (!remove(list[i])) { 06269 // on windows, try again after making it writeable; don't ALWAYS 06270 // do this first since that would be slow in the normal case 06271 #ifdef _MSC_VER 06272 _chmod(list[i], _S_IWRITE); 06273 remove(list[i]); 06274 #endif 06275 } 06276 stb_arr_free(list); 06277 stb__windows(_rmdir,rmdir)(dir); 06278 } 06279 06280 #endif 06281 06283 // 06284 // construct trees from filenames; useful for cmirror summaries 06285 06286 typedef struct stb_dirtree2 stb_dirtree2; 06287 06288 struct stb_dirtree2 06289 { 06290 stb_dirtree2 **subdirs; 06291 06292 // make convenient for stb_summarize_tree 06293 int num_subdir; 06294 float weight; 06295 06296 // actual data 06297 char *fullpath; 06298 char *relpath; 06299 char **files; 06300 }; 06301 06302 STB_EXTERN stb_dirtree2 *stb_dirtree2_from_files_relative(char *src, char **filelist, int count); 06303 STB_EXTERN stb_dirtree2 *stb_dirtree2_from_files(char **filelist, int count); 06304 STB_EXTERN int stb_dir_is_prefix(char *dir, int dirlen, char *file); 06305 06306 #ifdef STB_DEFINE 06307 06308 int stb_dir_is_prefix(char *dir, int dirlen, char *file) 06309 { 06310 if (dirlen == 0) return STB_TRUE; 06311 if (stb_strnicmp(dir, file, dirlen)) return STB_FALSE; 06312 if (file[dirlen] == '/' || file[dirlen] == '\\') return STB_TRUE; 06313 return STB_FALSE; 06314 } 06315 06316 stb_dirtree2 *stb_dirtree2_from_files_relative(char *src, char **filelist, int count) 06317 { 06318 char buffer1[1024]; 06319 int i; 06320 int dlen = (int) strlen(src), elen; 06321 stb_dirtree2 *d; 06322 char ** descendents = NULL; 06323 char ** files = NULL; 06324 char *s; 06325 if (!count) return NULL; 06326 // first find all the ones that belong here... note this is will take O(NM) with N files and M subdirs 06327 for (i=0; i < count; ++i) { 06328 if (stb_dir_is_prefix(src, dlen, filelist[i])) { 06329 stb_arr_push(descendents, filelist[i]); 06330 } 06331 } 06332 if (descendents == NULL) 06333 return NULL; 06334 elen = dlen; 06335 // skip a leading slash 06336 if (elen == 0 && (descendents[0][0] == '/' || descendents[0][0] == '\\')) 06337 ++elen; 06338 else if (elen) 06339 ++elen; 06340 // now extract all the ones that have their root here 06341 for (i=0; i < stb_arr_len(descendents);) { 06342 if (!stb_strchr2(descendents[i]+elen, '/', '\\')) { 06343 stb_arr_push(files, descendents[i]); 06344 descendents[i] = descendents[stb_arr_len(descendents)-1]; 06345 stb_arr_pop(descendents); 06346 } else 06347 ++i; 06348 } 06349 // now create a record 06350 d = (stb_dirtree2 *) malloc(sizeof(*d)); 06351 d->files = files; 06352 d->subdirs = NULL; 06353 d->fullpath = stb_p_strdup(src); 06354 s = stb_strrchr2(d->fullpath, '/', '\\'); 06355 if (s) 06356 ++s; 06357 else 06358 s = d->fullpath; 06359 d->relpath = s; 06360 // now create the children 06361 qsort(descendents, stb_arr_len(descendents), sizeof(char *), stb_qsort_stricmp(0)); 06362 buffer1[0] = 0; 06363 for (i=0; i < stb_arr_len(descendents); ++i) { 06364 char buffer2[1024]; 06365 char *s = descendents[i] + elen, *t; 06366 t = stb_strchr2(s, '/', '\\'); 06367 assert(t); 06368 stb_strncpy(buffer2, descendents[i], (int) (t-descendents[i]+1)); 06369 if (stb_stricmp(buffer1, buffer2)) { 06370 stb_dirtree2 *t = stb_dirtree2_from_files_relative(buffer2, descendents, stb_arr_len(descendents)); 06371 assert(t != NULL); 06372 stb_p_strcpy_s(buffer1, sizeof(buffer1), buffer2); 06373 stb_arr_push(d->subdirs, t); 06374 } 06375 } 06376 d->num_subdir = stb_arr_len(d->subdirs); 06377 d->weight = 0; 06378 return d; 06379 } 06380 06381 stb_dirtree2 *stb_dirtree2_from_files(char **filelist, int count) 06382 { 06383 return stb_dirtree2_from_files_relative((char*) "", filelist, count); 06384 } 06385 #endif 06386 06388 // 06389 // Checksums: CRC-32, ADLER32, SHA-1 06390 // 06391 // CRC-32 and ADLER32 allow streaming blocks 06392 // SHA-1 requires either a complete buffer, max size 2^32 - 73 06393 // or it can checksum directly from a file, max 2^61 06394 06395 #define STB_ADLER32_SEED 1 06396 #define STB_CRC32_SEED 0 // note that we logical NOT this in the code 06397 06398 STB_EXTERN stb_uint 06399 stb_adler32(stb_uint adler32, stb_uchar *buffer, stb_uint buflen); 06400 STB_EXTERN stb_uint 06401 stb_crc32_block(stb_uint crc32, stb_uchar *buffer, stb_uint len); 06402 STB_EXTERN stb_uint stb_crc32(unsigned char *buffer, stb_uint len); 06403 06404 STB_EXTERN void stb_sha1( 06405 unsigned char output[20], unsigned char *buffer, unsigned int len); 06406 STB_EXTERN int stb_sha1_file(unsigned char output[20], char *file); 06407 06408 STB_EXTERN void stb_sha1_readable(char display[27], unsigned char sha[20]); 06409 06410 #ifdef STB_DEFINE 06411 stb_uint stb_crc32_block(stb_uint crc, unsigned char *buffer, stb_uint len) 06412 { 06413 static stb_uint crc_table[256]; 06414 stb_uint i,j,s; 06415 crc = ~crc; 06416 06417 if (crc_table[1] == 0) 06418 for(i=0; i < 256; i++) { 06419 for (s=i, j=0; j < 8; ++j) 06420 s = (s >> 1) ^ (s & 1 ? 0xedb88320 : 0); 06421 crc_table[i] = s; 06422 } 06423 for (i=0; i < len; ++i) 06424 crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; 06425 return ~crc; 06426 } 06427 06428 stb_uint stb_crc32(unsigned char *buffer, stb_uint len) 06429 { 06430 return stb_crc32_block(0, buffer, len); 06431 } 06432 06433 stb_uint stb_adler32(stb_uint adler32, stb_uchar *buffer, stb_uint buflen) 06434 { 06435 const unsigned long ADLER_MOD = 65521; 06436 unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16; 06437 unsigned long blocklen, i; 06438 06439 blocklen = buflen % 5552; 06440 while (buflen) { 06441 for (i=0; i + 7 < blocklen; i += 8) { 06442 s1 += buffer[0], s2 += s1; 06443 s1 += buffer[1], s2 += s1; 06444 s1 += buffer[2], s2 += s1; 06445 s1 += buffer[3], s2 += s1; 06446 s1 += buffer[4], s2 += s1; 06447 s1 += buffer[5], s2 += s1; 06448 s1 += buffer[6], s2 += s1; 06449 s1 += buffer[7], s2 += s1; 06450 06451 buffer += 8; 06452 } 06453 06454 for (; i < blocklen; ++i) 06455 s1 += *buffer++, s2 += s1; 06456 06457 s1 %= ADLER_MOD, s2 %= ADLER_MOD; 06458 buflen -= blocklen; 06459 blocklen = 5552; 06460 } 06461 return (s2 << 16) + s1; 06462 } 06463 06464 static void stb__sha1(stb_uchar *chunk, stb_uint h[5]) 06465 { 06466 int i; 06467 stb_uint a,b,c,d,e; 06468 stb_uint w[80]; 06469 06470 for (i=0; i < 16; ++i) 06471 w[i] = stb_big32(&chunk[i*4]); 06472 for (i=16; i < 80; ++i) { 06473 stb_uint t; 06474 t = w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]; 06475 w[i] = (t + t) | (t >> 31); 06476 } 06477 06478 a = h[0]; 06479 b = h[1]; 06480 c = h[2]; 06481 d = h[3]; 06482 e = h[4]; 06483 06484 #define STB__SHA1(k,f) \ 06485 { \ 06486 stb_uint temp = (a << 5) + (a >> 27) + (f) + e + (k) + w[i]; \ 06487 e = d; \ 06488 d = c; \ 06489 c = (b << 30) + (b >> 2); \ 06490 b = a; \ 06491 a = temp; \ 06492 } 06493 06494 i=0; 06495 for (; i < 20; ++i) STB__SHA1(0x5a827999, d ^ (b & (c ^ d)) ); 06496 for (; i < 40; ++i) STB__SHA1(0x6ed9eba1, b ^ c ^ d ); 06497 for (; i < 60; ++i) STB__SHA1(0x8f1bbcdc, (b & c) + (d & (b ^ c)) ); 06498 for (; i < 80; ++i) STB__SHA1(0xca62c1d6, b ^ c ^ d ); 06499 06500 #undef STB__SHA1 06501 06502 h[0] += a; 06503 h[1] += b; 06504 h[2] += c; 06505 h[3] += d; 06506 h[4] += e; 06507 } 06508 06509 void stb_sha1(stb_uchar output[20], stb_uchar *buffer, stb_uint len) 06510 { 06511 unsigned char final_block[128]; 06512 stb_uint end_start, final_len, j; 06513 int i; 06514 06515 stb_uint h[5]; 06516 06517 h[0] = 0x67452301; 06518 h[1] = 0xefcdab89; 06519 h[2] = 0x98badcfe; 06520 h[3] = 0x10325476; 06521 h[4] = 0xc3d2e1f0; 06522 06523 // we need to write padding to the last one or two 06524 // blocks, so build those first into 'final_block' 06525 06526 // we have to write one special byte, plus the 8-byte length 06527 06528 // compute the block where the data runs out 06529 end_start = len & ~63; 06530 06531 // compute the earliest we can encode the length 06532 if (((len+9) & ~63) == end_start) { 06533 // it all fits in one block, so fill a second-to-last block 06534 end_start -= 64; 06535 } 06536 06537 final_len = end_start + 128; 06538 06539 // now we need to copy the data in 06540 assert(end_start + 128 >= len+9); 06541 assert(end_start < len || len < 64-9); 06542 06543 j = 0; 06544 if (end_start > len) 06545 j = (stb_uint) - (int) end_start; 06546 06547 for (; end_start + j < len; ++j) 06548 final_block[j] = buffer[end_start + j]; 06549 final_block[j++] = 0x80; 06550 while (j < 128-5) // 5 byte length, so write 4 extra padding bytes 06551 final_block[j++] = 0; 06552 // big-endian size 06553 final_block[j++] = len >> 29; 06554 final_block[j++] = len >> 21; 06555 final_block[j++] = len >> 13; 06556 final_block[j++] = len >> 5; 06557 final_block[j++] = len << 3; 06558 assert(j == 128 && end_start + j == final_len); 06559 06560 for (j=0; j < final_len; j += 64) { // 512-bit chunks 06561 if (j+64 >= end_start+64) 06562 stb__sha1(&final_block[j - end_start], h); 06563 else 06564 stb__sha1(&buffer[j], h); 06565 } 06566 06567 for (i=0; i < 5; ++i) { 06568 output[i*4 + 0] = h[i] >> 24; 06569 output[i*4 + 1] = h[i] >> 16; 06570 output[i*4 + 2] = h[i] >> 8; 06571 output[i*4 + 3] = h[i] >> 0; 06572 } 06573 } 06574 06575 #ifdef _MSC_VER 06576 int stb_sha1_file(stb_uchar output[20], char *file) 06577 { 06578 int i; 06579 stb_uint64 length=0; 06580 unsigned char buffer[128]; 06581 06582 FILE *f = stb__fopen(file, "rb"); 06583 stb_uint h[5]; 06584 06585 if (f == NULL) return 0; // file not found 06586 06587 h[0] = 0x67452301; 06588 h[1] = 0xefcdab89; 06589 h[2] = 0x98badcfe; 06590 h[3] = 0x10325476; 06591 h[4] = 0xc3d2e1f0; 06592 06593 for(;;) { 06594 size_t n = fread(buffer, 1, 64, f); 06595 if (n == 64) { 06596 stb__sha1(buffer, h); 06597 length += n; 06598 } else { 06599 int block = 64; 06600 06601 length += n; 06602 06603 buffer[n++] = 0x80; 06604 06605 // if there isn't enough room for the length, double the block 06606 if (n + 8 > 64) 06607 block = 128; 06608 06609 // pad to end 06610 memset(buffer+n, 0, block-8-n); 06611 06612 i = block - 8; 06613 buffer[i++] = (stb_uchar) (length >> 53); 06614 buffer[i++] = (stb_uchar) (length >> 45); 06615 buffer[i++] = (stb_uchar) (length >> 37); 06616 buffer[i++] = (stb_uchar) (length >> 29); 06617 buffer[i++] = (stb_uchar) (length >> 21); 06618 buffer[i++] = (stb_uchar) (length >> 13); 06619 buffer[i++] = (stb_uchar) (length >> 5); 06620 buffer[i++] = (stb_uchar) (length << 3); 06621 assert(i == block); 06622 stb__sha1(buffer, h); 06623 if (block == 128) 06624 stb__sha1(buffer+64, h); 06625 else 06626 assert(block == 64); 06627 break; 06628 } 06629 } 06630 fclose(f); 06631 06632 for (i=0; i < 5; ++i) { 06633 output[i*4 + 0] = h[i] >> 24; 06634 output[i*4 + 1] = h[i] >> 16; 06635 output[i*4 + 2] = h[i] >> 8; 06636 output[i*4 + 3] = h[i] >> 0; 06637 } 06638 06639 return 1; 06640 } 06641 #endif // _MSC_VER 06642 06643 // client can truncate this wherever they like 06644 void stb_sha1_readable(char display[27], unsigned char sha[20]) 06645 { 06646 char encoding[65] = "0123456789abcdefghijklmnopqrstuv" 06647 "wxyzABCDEFGHIJKLMNOPQRSTUVWXYZ%$"; 06648 int num_bits = 0, acc=0; 06649 int i=0,o=0; 06650 while (o < 26) { 06651 int v; 06652 // expand the accumulator 06653 if (num_bits < 6) { 06654 assert(i != 20); 06655 acc += sha[i++] << num_bits; 06656 num_bits += 8; 06657 } 06658 v = acc & ((1 << 6) - 1); 06659 display[o++] = encoding[v]; 06660 acc >>= 6; 06661 num_bits -= 6; 06662 } 06663 assert(num_bits == 20*8 - 26*6); 06664 display[o++] = encoding[acc]; 06665 } 06666 06667 #endif // STB_DEFINE 06668 06670 // 06671 // simplified WINDOWS registry interface... hopefully 06672 // we'll never actually use this? 06673 06674 #if defined(_WIN32) 06675 06676 STB_EXTERN void * stb_reg_open(const char *mode, const char *where); // mode: "rHKLM" or "rHKCU" or "w.." 06677 STB_EXTERN void stb_reg_close(void *reg); 06678 STB_EXTERN int stb_reg_read(void *zreg, const char *str, void *data, unsigned long len); 06679 STB_EXTERN int stb_reg_read_string(void *zreg, const char *str, char *data, int len); 06680 STB_EXTERN void stb_reg_write(void *zreg, const char *str, const void *data, unsigned long len); 06681 STB_EXTERN void stb_reg_write_string(void *zreg, const char *str, const char *data); 06682 06683 #if defined(STB_DEFINE) && !defined(STB_NO_REGISTRY) 06684 06685 #define STB_HAS_REGISTRY 06686 06687 #ifndef _WINDOWS_ 06688 06689 #define HKEY void * 06690 06691 STB_EXTERN __declspec(dllimport) long __stdcall RegCloseKey ( HKEY hKey ); 06692 STB_EXTERN __declspec(dllimport) long __stdcall RegCreateKeyExA ( HKEY hKey, const char * lpSubKey, 06693 int Reserved, char * lpClass, int dwOptions, 06694 int samDesired, void *lpSecurityAttributes, HKEY * phkResult, int * lpdwDisposition ); 06695 STB_EXTERN __declspec(dllimport) long __stdcall RegDeleteKeyA ( HKEY hKey, const char * lpSubKey ); 06696 STB_EXTERN __declspec(dllimport) long __stdcall RegQueryValueExA ( HKEY hKey, const char * lpValueName, 06697 int * lpReserved, unsigned long * lpType, unsigned char * lpData, unsigned long * lpcbData ); 06698 STB_EXTERN __declspec(dllimport) long __stdcall RegSetValueExA ( HKEY hKey, const char * lpValueName, 06699 int Reserved, int dwType, const unsigned char* lpData, int cbData ); 06700 STB_EXTERN __declspec(dllimport) long __stdcall RegOpenKeyExA ( HKEY hKey, const char * lpSubKey, 06701 int ulOptions, int samDesired, HKEY * phkResult ); 06702 06703 #endif // _WINDOWS_ 06704 06705 #define STB__REG_OPTION_NON_VOLATILE 0 06706 #define STB__REG_KEY_ALL_ACCESS 0x000f003f 06707 #define STB__REG_KEY_READ 0x00020019 06708 06709 #ifdef _M_AMD64 06710 #define STB__HKEY_CURRENT_USER 0x80000001ull 06711 #define STB__HKEY_LOCAL_MACHINE 0x80000002ull 06712 #else 06713 #define STB__HKEY_CURRENT_USER 0x80000001 06714 #define STB__HKEY_LOCAL_MACHINE 0x80000002 06715 #endif 06716 06717 void *stb_reg_open(const char *mode, const char *where) 06718 { 06719 long res; 06720 HKEY base; 06721 HKEY zreg; 06722 if (!stb_stricmp(mode+1, "cu") || !stb_stricmp(mode+1, "hkcu")) 06723 base = (HKEY) STB__HKEY_CURRENT_USER; 06724 else if (!stb_stricmp(mode+1, "lm") || !stb_stricmp(mode+1, "hklm")) 06725 base = (HKEY) STB__HKEY_LOCAL_MACHINE; 06726 else 06727 return NULL; 06728 06729 if (mode[0] == 'r') 06730 res = RegOpenKeyExA(base, where, 0, STB__REG_KEY_READ, &zreg); 06731 else if (mode[0] == 'w') 06732 res = RegCreateKeyExA(base, where, 0, NULL, STB__REG_OPTION_NON_VOLATILE, STB__REG_KEY_ALL_ACCESS, NULL, &zreg, NULL); 06733 else 06734 return NULL; 06735 06736 return res ? NULL : zreg; 06737 } 06738 06739 void stb_reg_close(void *reg) 06740 { 06741 RegCloseKey((HKEY) reg); 06742 } 06743 06744 #define STB__REG_SZ 1 06745 #define STB__REG_BINARY 3 06746 #define STB__REG_DWORD 4 06747 06748 int stb_reg_read(void *zreg, const char *str, void *data, unsigned long len) 06749 { 06750 unsigned long type; 06751 unsigned long alen = len; 06752 if (0 == RegQueryValueExA((HKEY) zreg, str, 0, &type, (unsigned char *) data, &len)) 06753 if (type == STB__REG_BINARY || type == STB__REG_SZ || type == STB__REG_DWORD) { 06754 if (len < alen) 06755 *((char *) data + len) = 0; 06756 return 1; 06757 } 06758 return 0; 06759 } 06760 06761 void stb_reg_write(void *zreg, const char *str, const void *data, unsigned long len) 06762 { 06763 if (zreg) 06764 RegSetValueExA((HKEY) zreg, str, 0, STB__REG_BINARY, (const unsigned char *) data, len); 06765 } 06766 06767 int stb_reg_read_string(void *zreg, const char *str, char *data, int len) 06768 { 06769 if (!stb_reg_read(zreg, str, data, len)) return 0; 06770 data[len-1] = 0; // force a 0 at the end of the string no matter what 06771 return 1; 06772 } 06773 06774 void stb_reg_write_string(void *zreg, const char *str, const char *data) 06775 { 06776 if (zreg) 06777 RegSetValueExA((HKEY) zreg, str, 0, STB__REG_SZ, (const unsigned char *) data, (int) strlen(data)+1); 06778 } 06779 #endif // STB_DEFINE 06780 #endif // _WIN32 06781 06782 06784 // 06785 // stb_cfg - This is like the registry, but the config info 06786 // is all stored in plain old files where we can 06787 // backup and restore them easily. The LOCATION of 06788 // the config files is gotten from... the registry! 06789 06790 #ifndef STB_NO_STB_STRINGS 06791 typedef struct stb_cfg_st stb_cfg; 06792 06793 STB_EXTERN stb_cfg * stb_cfg_open(char *config, const char *mode); // mode = "r", "w" 06794 STB_EXTERN void stb_cfg_close(stb_cfg *cfg); 06795 STB_EXTERN int stb_cfg_read(stb_cfg *cfg, char *key, void *value, int len); 06796 STB_EXTERN void stb_cfg_write(stb_cfg *cfg, char *key, void *value, int len); 06797 STB_EXTERN int stb_cfg_read_string(stb_cfg *cfg, char *key, char *value, int len); 06798 STB_EXTERN void stb_cfg_write_string(stb_cfg *cfg, char *key, char *value); 06799 STB_EXTERN int stb_cfg_delete(stb_cfg *cfg, char *key); 06800 STB_EXTERN void stb_cfg_set_directory(char *dir); 06801 06802 #ifdef STB_DEFINE 06803 06804 typedef struct 06805 { 06806 char *key; 06807 void *value; 06808 int value_len; 06809 } stb__cfg_item; 06810 06811 struct stb_cfg_st 06812 { 06813 stb__cfg_item *data; 06814 char *loaded_file; // this needs to be freed 06815 FILE *f; // write the data to this file on close 06816 }; 06817 06818 static const char *stb__cfg_sig = "sTbCoNfIg!\0\0"; 06819 static char stb__cfg_dir[512]; 06820 STB_EXTERN void stb_cfg_set_directory(char *dir) 06821 { 06822 stb_p_strcpy_s(stb__cfg_dir, sizeof(stb__cfg_dir), dir); 06823 } 06824 06825 STB_EXTERN stb_cfg * stb_cfg_open(char *config, const char *mode) 06826 { 06827 size_t len; 06828 stb_cfg *z; 06829 char file[512]; 06830 if (mode[0] != 'r' && mode[0] != 'w') return NULL; 06831 06832 if (!stb__cfg_dir[0]) { 06833 #ifdef _WIN32 06834 stb_p_strcpy_s(stb__cfg_dir, sizeof(stb__cfg_dir), "c:/stb"); 06835 #else 06836 strcpy(stb__cfg_dir, "~/.stbconfig"); 06837 #endif 06838 06839 #ifdef STB_HAS_REGISTRY 06840 { 06841 void *reg = stb_reg_open("rHKLM", "Software\\SilverSpaceship\\stb"); 06842 if (reg) { 06843 stb_reg_read_string(reg, "config_dir", stb__cfg_dir, sizeof(stb__cfg_dir)); 06844 stb_reg_close(reg); 06845 } 06846 } 06847 #endif 06848 } 06849 06850 stb_p_sprintf(file stb_p_size(sizeof(file)), "%s/%s.cfg", stb__cfg_dir, config); 06851 06852 z = (stb_cfg *) stb_malloc(0, sizeof(*z)); 06853 z->data = NULL; 06854 06855 z->loaded_file = stb_filec(file, &len); 06856 if (z->loaded_file) { 06857 char *s = z->loaded_file; 06858 if (!memcmp(s, stb__cfg_sig, 12)) { 06859 char *s = z->loaded_file + 12; 06860 while (s < z->loaded_file + len) { 06861 stb__cfg_item a; 06862 int n = *(stb_int16 *) s; 06863 a.key = s+2; 06864 s = s+2 + n; 06865 a.value_len = *(int *) s; 06866 s += 4; 06867 a.value = s; 06868 s += a.value_len; 06869 stb_arr_push(z->data, a); 06870 } 06871 assert(s == z->loaded_file + len); 06872 } 06873 } 06874 06875 if (mode[0] == 'w') 06876 z->f = stb_p_fopen(file, "wb"); 06877 else 06878 z->f = NULL; 06879 06880 return z; 06881 } 06882 06883 void stb_cfg_close(stb_cfg *z) 06884 { 06885 if (z->f) { 06886 int i; 06887 // write the file out 06888 fwrite(stb__cfg_sig, 12, 1, z->f); 06889 for (i=0; i < stb_arr_len(z->data); ++i) { 06890 stb_int16 n = (stb_int16) strlen(z->data[i].key)+1; 06891 fwrite(&n, 2, 1, z->f); 06892 fwrite(z->data[i].key, n, 1, z->f); 06893 fwrite(&z->data[i].value_len, 4, 1, z->f); 06894 fwrite(z->data[i].value, z->data[i].value_len, 1, z->f); 06895 } 06896 fclose(z->f); 06897 } 06898 stb_arr_free(z->data); 06899 stb_free(z); 06900 } 06901 06902 int stb_cfg_read(stb_cfg *z, char *key, void *value, int len) 06903 { 06904 int i; 06905 for (i=0; i < stb_arr_len(z->data); ++i) { 06906 if (!stb_stricmp(z->data[i].key, key)) { 06907 int n = stb_min(len, z->data[i].value_len); 06908 memcpy(value, z->data[i].value, n); 06909 if (n < len) 06910 *((char *) value + n) = 0; 06911 return 1; 06912 } 06913 } 06914 return 0; 06915 } 06916 06917 void stb_cfg_write(stb_cfg *z, char *key, void *value, int len) 06918 { 06919 int i; 06920 for (i=0; i < stb_arr_len(z->data); ++i) 06921 if (!stb_stricmp(z->data[i].key, key)) 06922 break; 06923 if (i == stb_arr_len(z->data)) { 06924 stb__cfg_item p; 06925 p.key = stb_strdup(key, z); 06926 p.value = NULL; 06927 p.value_len = 0; 06928 stb_arr_push(z->data, p); 06929 } 06930 z->data[i].value = stb_malloc(z, len); 06931 z->data[i].value_len = len; 06932 memcpy(z->data[i].value, value, len); 06933 } 06934 06935 int stb_cfg_delete(stb_cfg *z, char *key) 06936 { 06937 int i; 06938 for (i=0; i < stb_arr_len(z->data); ++i) 06939 if (!stb_stricmp(z->data[i].key, key)) { 06940 stb_arr_fastdelete(z->data, i); 06941 return 1; 06942 } 06943 return 0; 06944 } 06945 06946 int stb_cfg_read_string(stb_cfg *z, char *key, char *value, int len) 06947 { 06948 if (!stb_cfg_read(z, key, value, len)) return 0; 06949 value[len-1] = 0; 06950 return 1; 06951 } 06952 06953 void stb_cfg_write_string(stb_cfg *z, char *key, char *value) 06954 { 06955 stb_cfg_write(z, key, value, (int) strlen(value)+1); 06956 } 06957 #endif 06958 06960 // 06961 // stb_dirtree - load a description of a directory tree 06962 // uses a cache and stat()s the directories for changes 06963 // MUCH faster on NTFS, _wrong_ on FAT32, so should 06964 // ignore the db on FAT32 06965 06966 #ifdef _WIN32 06967 06968 typedef struct 06969 { 06970 char * path; // full path from passed-in root 06971 time_t last_modified; 06972 int num_files; 06973 int flag; 06974 } stb_dirtree_dir; 06975 06976 typedef struct 06977 { 06978 char *name; // name relative to path 06979 int dir; // index into dirs[] array 06980 stb_int64 size; // size, max 4GB 06981 time_t last_modified; 06982 int flag; 06983 } stb_dirtree_file; 06984 06985 typedef struct 06986 { 06987 stb_dirtree_dir *dirs; 06988 stb_dirtree_file *files; 06989 06990 // internal use 06991 void * string_pool; // used to free data en masse 06992 } stb_dirtree; 06993 06994 extern void stb_dirtree_free ( stb_dirtree *d ); 06995 extern stb_dirtree *stb_dirtree_get ( char *dir); 06996 extern stb_dirtree *stb_dirtree_get_dir ( char *dir, char *cache_dir); 06997 extern stb_dirtree *stb_dirtree_get_with_file ( char *dir, char *cache_file); 06998 06999 // get a list of all the files recursively underneath 'dir' 07000 // 07001 // cache_file is used to store a copy of the directory tree to speed up 07002 // later calls. It must be unique to 'dir' and the current working 07003 // directory! Otherwise who knows what will happen (a good solution 07004 // is to put it _in_ dir, but this API doesn't force that). 07005 // 07006 // Also, it might be possible to break this if you have two different processes 07007 // do a call to stb_dirtree_get() with the same cache file at about the same 07008 // time, but I _think_ it might just work. 07009 07010 // i needed to build an identical data structure representing the state of 07011 // a mirrored copy WITHOUT bothering to rescan it (i.e. we're mirroring to 07012 // it WITHOUT scanning it, e.g. it's over the net), so this requires access 07013 // to all of the innards. 07014 extern void stb_dirtree_db_add_dir(stb_dirtree *active, char *path, time_t last); 07015 extern void stb_dirtree_db_add_file(stb_dirtree *active, char *name, int dir, stb_int64 size, time_t last); 07016 extern void stb_dirtree_db_read(stb_dirtree *target, char *filename, char *dir); 07017 extern void stb_dirtree_db_write(stb_dirtree *target, char *filename, char *dir); 07018 07019 #ifdef STB_DEFINE 07020 static void stb__dirtree_add_dir(char *path, time_t last, stb_dirtree *active) 07021 { 07022 stb_dirtree_dir d; 07023 d.last_modified = last; 07024 d.num_files = 0; 07025 d.path = stb_strdup(path, active->string_pool); 07026 stb_arr_push(active->dirs, d); 07027 } 07028 07029 static void stb__dirtree_add_file(char *name, int dir, stb_int64 size, time_t last, stb_dirtree *active) 07030 { 07031 stb_dirtree_file f; 07032 f.dir = dir; 07033 f.size = size; 07034 f.last_modified = last; 07035 f.name = stb_strdup(name, active->string_pool); 07036 ++active->dirs[dir].num_files; 07037 stb_arr_push(active->files, f); 07038 } 07039 07040 // version 02 supports > 4GB files 07041 static char stb__signature[12] = { 's', 'T', 'b', 'D', 'i', 'R', 't', 'R', 'e', 'E', '0', '2' }; 07042 07043 static void stb__dirtree_save_db(char *filename, stb_dirtree *data, char *root) 07044 { 07045 int i, num_dirs_final=0, num_files_final; 07046 char *info = root ? root : (char*)""; 07047 int *remap; 07048 FILE *f = stb_p_fopen(filename, "wb"); 07049 if (!f) return; 07050 07051 fwrite(stb__signature, sizeof(stb__signature), 1, f); 07052 fwrite(info, strlen(info)+1, 1, f); 07053 // need to be slightly tricky and not write out NULLed directories, nor the root 07054 07055 // build remapping table of all dirs we'll be writing out 07056 remap = (int *) malloc(sizeof(remap[0]) * stb_arr_len(data->dirs)); 07057 for (i=0; i < stb_arr_len(data->dirs); ++i) { 07058 if (data->dirs[i].path == NULL || (root && 0==stb_stricmp(data->dirs[i].path, root))) { 07059 remap[i] = -1; 07060 } else { 07061 remap[i] = num_dirs_final++; 07062 } 07063 } 07064 07065 fwrite(&num_dirs_final, 4, 1, f); 07066 for (i=0; i < stb_arr_len(data->dirs); ++i) { 07067 if (remap[i] >= 0) { 07068 fwrite(&data->dirs[i].last_modified, 4, 1, f); 07069 stb_fput_string(f, data->dirs[i].path); 07070 } 07071 } 07072 07073 num_files_final = 0; 07074 for (i=0; i < stb_arr_len(data->files); ++i) 07075 if (remap[data->files[i].dir] >= 0 && data->files[i].name) 07076 ++num_files_final; 07077 07078 fwrite(&num_files_final, 4, 1, f); 07079 for (i=0; i < stb_arr_len(data->files); ++i) { 07080 if (remap[data->files[i].dir] >= 0 && data->files[i].name) { 07081 stb_fput_ranged(f, remap[data->files[i].dir], 0, num_dirs_final); 07082 stb_fput_varlen64(f, data->files[i].size); 07083 fwrite(&data->files[i].last_modified, 4, 1, f); 07084 stb_fput_string(f, data->files[i].name); 07085 } 07086 } 07087 07088 fclose(f); 07089 } 07090 07091 // note: stomps any existing data, rather than appending 07092 static void stb__dirtree_load_db(char *filename, stb_dirtree *data, char *dir) 07093 { 07094 char sig[2048]; 07095 int i,n; 07096 FILE *f = stb_p_fopen(filename, "rb"); 07097 07098 if (!f) return; 07099 07100 data->string_pool = stb_malloc(0,1); 07101 07102 fread(sig, sizeof(stb__signature), 1, f); 07103 if (memcmp(stb__signature, sig, sizeof(stb__signature))) { fclose(f); return; } 07104 if (!fread(sig, strlen(dir)+1, 1, f)) { fclose(f); return; } 07105 if (stb_stricmp(sig,dir)) { fclose(f); return; } 07106 07107 // we can just read them straight in, because they're guaranteed to be valid 07108 fread(&n, 4, 1, f); 07109 stb_arr_setlen(data->dirs, n); 07110 for(i=0; i < stb_arr_len(data->dirs); ++i) { 07111 fread(&data->dirs[i].last_modified, 4, 1, f); 07112 data->dirs[i].path = stb_fget_string(f, data->string_pool); 07113 if (data->dirs[i].path == NULL) goto bail; 07114 } 07115 fread(&n, 4, 1, f); 07116 stb_arr_setlen(data->files, n); 07117 for (i=0; i < stb_arr_len(data->files); ++i) { 07118 data->files[i].dir = stb_fget_ranged(f, 0, stb_arr_len(data->dirs)); 07119 data->files[i].size = stb_fget_varlen64(f); 07120 fread(&data->files[i].last_modified, 4, 1, f); 07121 data->files[i].name = stb_fget_string(f, data->string_pool); 07122 if (data->files[i].name == NULL) goto bail; 07123 } 07124 07125 if (0) { 07126 bail: 07127 stb_arr_free(data->dirs); 07128 stb_arr_free(data->files); 07129 } 07130 fclose(f); 07131 } 07132 07133 FILE *hlog; 07134 07135 static int stb__dircount, stb__dircount_mask, stb__showfile; 07136 static void stb__dirtree_scandir(char *path, time_t last_time, stb_dirtree *active) 07137 { 07138 // this is dumb depth first; theoretically it might be faster 07139 // to fully traverse each directory before visiting its children, 07140 // but it's complicated and didn't seem like a gain in the test app 07141 07142 int n; 07143 07144 struct _wfinddatai64_t c_file; 07145 long hFile; 07146 stb__wchar full_path[1024]; 07147 int has_slash; 07148 if (stb__showfile) printf("<"); 07149 07150 has_slash = (path[0] && path[strlen(path)-1] == '/'); 07151 07152 // @TODO: do this concatenation without using swprintf to avoid this mess: 07153 #if (defined(_MSC_VER) && _MSC_VER < 1400) // || (defined(__clang__)) 07154 // confusingly, Windows Kits\10 needs to go down this path?!? 07155 // except now it doesn't, I don't know what changed 07156 if (has_slash) 07157 swprintf(full_path, L"%s*", stb__from_utf8(path)); 07158 else 07159 swprintf(full_path, L"%s/*", stb__from_utf8(path)); 07160 #else 07161 if (has_slash) 07162 swprintf((wchar_t *) full_path, (size_t) 1024, L"%s*", (wchar_t *) stb__from_utf8(path)); 07163 else 07164 swprintf((wchar_t *) full_path, (size_t) 1024, L"%s/*", (wchar_t *) stb__from_utf8(path)); 07165 #endif 07166 07167 // it's possible this directory is already present: that means it was in the 07168 // cache, but its parent wasn't... in that case, we're done with it 07169 if (stb__showfile) printf("C[%d]", stb_arr_len(active->dirs)); 07170 for (n=0; n < stb_arr_len(active->dirs); ++n) 07171 if (0 == stb_stricmp(active->dirs[n].path, path)) { 07172 if (stb__showfile) printf("D"); 07173 return; 07174 } 07175 if (stb__showfile) printf("E"); 07176 07177 // otherwise, we need to add it 07178 stb__dirtree_add_dir(path, last_time, active); 07179 n = stb_arr_lastn(active->dirs); 07180 07181 if (stb__showfile) printf("["); 07182 if( (hFile = (long) _wfindfirsti64( (wchar_t *) full_path, &c_file )) != -1L ) { 07183 do { 07184 if (stb__showfile) printf(")"); 07185 if (c_file.attrib & _A_SUBDIR) { 07186 // ignore subdirectories starting with '.', e.g. "." and ".." 07187 if (c_file.name[0] != '.') { 07188 char *new_path = (char *) full_path; 07189 char *temp = stb__to_utf8((stb__wchar *) c_file.name); 07190 07191 if (has_slash) 07192 stb_p_sprintf(new_path stb_p_size(sizeof(full_path)), "%s%s", path, temp); 07193 else 07194 stb_p_sprintf(new_path stb_p_size(sizeof(full_path)), "%s/%s", path, temp); 07195 07196 if (stb__dircount_mask) { 07197 ++stb__dircount; 07198 if (!(stb__dircount & stb__dircount_mask)) { 07199 char dummy_path[128], *pad; 07200 stb_strncpy(dummy_path, new_path, sizeof(dummy_path)-1); 07201 if (strlen(dummy_path) > 96) { 07202 stb_p_strcpy_s(dummy_path+96/2-1,128, "..."); 07203 stb_p_strcpy_s(dummy_path+96/2+2,128, new_path + strlen(new_path)-96/2+2); 07204 } 07205 pad = dummy_path + strlen(dummy_path); 07206 while (pad < dummy_path+98) 07207 *pad++ = ' '; 07208 *pad = 0; 07209 printf("%s\r", dummy_path); 07210 #if 0 07211 if (hlog == 0) { 07212 hlog = stb_p_fopen("c:/x/temp.log", "w"); 07213 fprintf(hlog, "%s\n", dummy_path); 07214 } 07215 #endif 07216 } 07217 } 07218 07219 stb__dirtree_scandir(new_path, c_file.time_write, active); 07220 } 07221 } else { 07222 char *temp = stb__to_utf8((stb__wchar *) c_file.name); 07223 stb__dirtree_add_file(temp, n, c_file.size, c_file.time_write, active); 07224 } 07225 if (stb__showfile) printf("("); 07226 } while( _wfindnexti64( hFile, &c_file ) == 0 ); 07227 if (stb__showfile) printf("]"); 07228 _findclose( hFile ); 07229 } 07230 if (stb__showfile) printf(">\n"); 07231 } 07232 07233 // scan the database and see if it's all valid 07234 static int stb__dirtree_update_db(stb_dirtree *db, stb_dirtree *active) 07235 { 07236 int changes_detected = STB_FALSE; 07237 int i; 07238 int *remap; 07239 int *rescan=NULL; 07240 remap = (int *) malloc(sizeof(remap[0]) * stb_arr_len(db->dirs)); 07241 memset(remap, 0, sizeof(remap[0]) * stb_arr_len(db->dirs)); 07242 rescan = NULL; 07243 07244 for (i=0; i < stb_arr_len(db->dirs); ++i) { 07245 struct _stat info; 07246 if (stb__dircount_mask) { 07247 ++stb__dircount; 07248 if (!(stb__dircount & stb__dircount_mask)) { 07249 printf("."); 07250 } 07251 } 07252 if (0 == _stat(db->dirs[i].path, &info)) { 07253 if (info.st_mode & _S_IFDIR) { 07254 // it's still a directory, as expected 07255 int n = abs((int) (info.st_mtime - db->dirs[i].last_modified)); 07256 if (n > 1 && n != 3600) { // the 3600 is a hack because sometimes this jumps for no apparent reason, even when no time zone or DST issues are at play 07257 // it's changed! force a rescan 07258 // we don't want to scan it until we've stat()d its 07259 // subdirs, though, so we queue it 07260 if (stb__showfile) printf("Changed: %s - %08x:%08x\n", db->dirs[i].path, (unsigned int) db->dirs[i].last_modified, (unsigned int) info.st_mtime); 07261 stb_arr_push(rescan, i); 07262 // update the last_mod time 07263 db->dirs[i].last_modified = info.st_mtime; 07264 // ignore existing files in this dir 07265 remap[i] = -1; 07266 changes_detected = STB_TRUE; 07267 } else { 07268 // it hasn't changed, just copy it through unchanged 07269 stb__dirtree_add_dir(db->dirs[i].path, db->dirs[i].last_modified, active); 07270 remap[i] = stb_arr_lastn(active->dirs); 07271 } 07272 } else { 07273 // this path used to refer to a directory, but now it's a file! 07274 // assume that the parent directory is going to be forced to rescan anyway 07275 goto delete_entry; 07276 } 07277 } else { 07278 delete_entry: 07279 // directory no longer exists, so don't copy it 07280 // we don't free it because it's in the string pool now 07281 db->dirs[i].path = NULL; 07282 remap[i] = -1; 07283 changes_detected = STB_TRUE; 07284 } 07285 } 07286 07287 // at this point, we have: 07288 // 07289 // <rescan> holds a list of directory indices that need to be scanned due to being out of date 07290 // <remap> holds the directory index in <active> for each dir in <db>, if it exists; -1 if not 07291 // directories in <rescan> are not in <active> yet 07292 07293 // so we can go ahead and remap all the known files right now 07294 for (i=0; i < stb_arr_len(db->files); ++i) { 07295 int dir = db->files[i].dir; 07296 if (remap[dir] >= 0) { 07297 stb__dirtree_add_file(db->files[i].name, remap[dir], db->files[i].size, db->files[i].last_modified, active); 07298 } 07299 } 07300 07301 // at this point we're done with db->files, and done with remap 07302 free(remap); 07303 07304 // now scan those directories using the standard scan 07305 for (i=0; i < stb_arr_len(rescan); ++i) { 07306 int z = rescan[i]; 07307 stb__dirtree_scandir(db->dirs[z].path, db->dirs[z].last_modified, active); 07308 } 07309 stb_arr_free(rescan); 07310 07311 return changes_detected; 07312 } 07313 07314 static void stb__dirtree_free_raw(stb_dirtree *d) 07315 { 07316 stb_free(d->string_pool); 07317 stb_arr_free(d->dirs); 07318 stb_arr_free(d->files); 07319 } 07320 07321 stb_dirtree *stb_dirtree_get_with_file(char *dir, char *cache_file) 07322 { 07323 stb_dirtree *output = (stb_dirtree *) malloc(sizeof(*output)); 07324 stb_dirtree db,active; 07325 int prev_dir_count, cache_mismatch; 07326 07327 char *stripped_dir; // store the directory name without a trailing '/' or '\\' 07328 07329 // load the database of last-known state on disk 07330 db.string_pool = NULL; 07331 db.files = NULL; 07332 db.dirs = NULL; 07333 07334 stripped_dir = stb_strip_final_slash(stb_p_strdup(dir)); 07335 07336 if (cache_file != NULL) 07337 stb__dirtree_load_db(cache_file, &db, stripped_dir); 07338 else if (stb__showfile) 07339 printf("No cache file\n"); 07340 07341 active.files = NULL; 07342 active.dirs = NULL; 07343 active.string_pool = stb_malloc(0,1); // @TODO: share string pools between both? 07344 07345 // check all the directories in the database; make note if 07346 // anything we scanned had changed, and rescan those things 07347 cache_mismatch = stb__dirtree_update_db(&db, &active); 07348 07349 // check the root tree 07350 prev_dir_count = stb_arr_len(active.dirs); // record how many directories we've seen 07351 07352 stb__dirtree_scandir(stripped_dir, 0, &active); // no last_modified time available for root 07353 07354 if (stb__dircount_mask) 07355 printf(" \r"); 07356 07357 // done with the DB; write it back out if any changes, i.e. either 07358 // 1. any inconsistency found between cached information and actual disk 07359 // or 2. if scanning the root found any new directories--which we detect because 07360 // more than one directory got added to the active db during that scan 07361 if (cache_mismatch || stb_arr_len(active.dirs) > prev_dir_count+1) 07362 stb__dirtree_save_db(cache_file, &active, stripped_dir); 07363 07364 free(stripped_dir); 07365 07366 stb__dirtree_free_raw(&db); 07367 07368 *output = active; 07369 return output; 07370 } 07371 07372 stb_dirtree *stb_dirtree_get_dir(char *dir, char *cache_dir) 07373 { 07374 int i; 07375 stb_uint8 sha[20]; 07376 char dir_lower[1024]; 07377 char cache_file[1024],*s; 07378 if (cache_dir == NULL) 07379 return stb_dirtree_get_with_file(dir, NULL); 07380 stb_p_strcpy_s(dir_lower, sizeof(dir_lower), dir); 07381 stb_tolower(dir_lower); 07382 stb_sha1(sha, (unsigned char *) dir_lower, (unsigned int) strlen(dir_lower)); 07383 stb_p_strcpy_s(cache_file, sizeof(cache_file), cache_dir); 07384 s = cache_file + strlen(cache_file); 07385 if (s[-1] != '/' && s[-1] != '\\') *s++ = '/'; 07386 stb_p_strcpy_s(s, sizeof(cache_file), "dirtree_"); 07387 s += strlen(s); 07388 for (i=0; i < 8; ++i) { 07389 char *hex = (char*)"0123456789abcdef"; 07390 stb_uint z = sha[i]; 07391 *s++ = hex[z >> 4]; 07392 *s++ = hex[z & 15]; 07393 } 07394 stb_p_strcpy_s(s, sizeof(cache_file), ".bin"); 07395 return stb_dirtree_get_with_file(dir, cache_file); 07396 } 07397 07398 stb_dirtree *stb_dirtree_get(char *dir) 07399 { 07400 char cache_dir[256]; 07401 stb_p_strcpy_s(cache_dir, sizeof(cache_dir), "c:/bindata"); 07402 #ifdef STB_HAS_REGISTRY 07403 { 07404 void *reg = stb_reg_open("rHKLM", "Software\\SilverSpaceship\\stb"); 07405 if (reg) { 07406 stb_reg_read(reg, "dirtree", cache_dir, sizeof(cache_dir)); 07407 stb_reg_close(reg); 07408 } 07409 } 07410 #endif 07411 return stb_dirtree_get_dir(dir, cache_dir); 07412 } 07413 07414 void stb_dirtree_free(stb_dirtree *d) 07415 { 07416 stb__dirtree_free_raw(d); 07417 free(d); 07418 } 07419 07420 void stb_dirtree_db_add_dir(stb_dirtree *active, char *path, time_t last) 07421 { 07422 stb__dirtree_add_dir(path, last, active); 07423 } 07424 07425 void stb_dirtree_db_add_file(stb_dirtree *active, char *name, int dir, stb_int64 size, time_t last) 07426 { 07427 stb__dirtree_add_file(name, dir, size, last, active); 07428 } 07429 07430 void stb_dirtree_db_read(stb_dirtree *target, char *filename, char *dir) 07431 { 07432 char *s = stb_strip_final_slash(stb_p_strdup(dir)); 07433 target->dirs = 0; 07434 target->files = 0; 07435 target->string_pool = 0; 07436 stb__dirtree_load_db(filename, target, s); 07437 free(s); 07438 } 07439 07440 void stb_dirtree_db_write(stb_dirtree *target, char *filename, char *dir) 07441 { 07442 stb__dirtree_save_db(filename, target, 0); // don't strip out any directories 07443 } 07444 07445 #endif // STB_DEFINE 07446 07447 #endif // _WIN32 07448 #endif // STB_NO_STB_STRINGS 07449 07451 // 07452 // STB_MALLOC_WRAPPER 07453 // 07454 // you can use the wrapper functions with your own malloc wrapper, 07455 // or define STB_MALLOC_WRAPPER project-wide to have 07456 // malloc/free/realloc/strdup all get vectored to it 07457 07458 // this has too many very specific error messages you could google for and find in stb.h, 07459 // so don't use it if they don't want any stb.h-identifiable strings 07460 #if defined(STB_DEFINE) && !defined(STB_NO_STB_STRINGS) 07461 07462 typedef struct 07463 { 07464 void *p; 07465 char *file; 07466 int line; 07467 size_t size; 07468 } stb_malloc_record; 07469 07470 #ifndef STB_MALLOC_HISTORY_COUNT 07471 #define STB_MALLOC_HISTORY_COUNT 50 // 800 bytes 07472 #endif 07473 07474 stb_malloc_record *stb__allocations; 07475 static int stb__alloc_size, stb__alloc_limit, stb__alloc_mask; 07476 int stb__alloc_count; 07477 07478 stb_malloc_record stb__alloc_history[STB_MALLOC_HISTORY_COUNT]; 07479 int stb__history_pos; 07480 07481 static int stb__hashfind(void *p) 07482 { 07483 stb_uint32 h = stb_hashptr(p); 07484 int s,n = h & stb__alloc_mask; 07485 if (stb__allocations[n].p == p) 07486 return n; 07487 s = stb_rehash(h)|1; 07488 for(;;) { 07489 if (stb__allocations[n].p == NULL) 07490 return -1; 07491 n = (n+s) & stb__alloc_mask; 07492 if (stb__allocations[n].p == p) 07493 return n; 07494 } 07495 } 07496 07497 size_t stb_wrapper_allocsize(void *p) 07498 { 07499 int n = stb__hashfind(p); 07500 if (n < 0) return 0; 07501 return stb__allocations[n].size; 07502 } 07503 07504 static int stb__historyfind(void *p) 07505 { 07506 int n = stb__history_pos; 07507 int i; 07508 for (i=0; i < STB_MALLOC_HISTORY_COUNT; ++i) { 07509 if (--n < 0) n = STB_MALLOC_HISTORY_COUNT-1; 07510 if (stb__alloc_history[n].p == p) 07511 return n; 07512 } 07513 return -1; 07514 } 07515 07516 static void stb__add_alloc(void *p, size_t sz, char *file, int line); 07517 static void stb__grow_alloc(void) 07518 { 07519 int i,old_num = stb__alloc_size; 07520 stb_malloc_record *old = stb__allocations; 07521 if (stb__alloc_size == 0) 07522 stb__alloc_size = 64; 07523 else 07524 stb__alloc_size *= 2; 07525 07526 stb__allocations = (stb_malloc_record *) stb__realloc_raw(NULL, stb__alloc_size * sizeof(stb__allocations[0])); 07527 if (stb__allocations == NULL) 07528 stb_fatal("Internal error: couldn't grow malloc wrapper table"); 07529 memset(stb__allocations, 0, stb__alloc_size * sizeof(stb__allocations[0])); 07530 stb__alloc_limit = (stb__alloc_size*3)>>2; 07531 stb__alloc_mask = stb__alloc_size-1; 07532 07533 stb__alloc_count = 0; 07534 07535 for (i=0; i < old_num; ++i) 07536 if (old[i].p > STB_DEL) { 07537 stb__add_alloc(old[i].p, old[i].size, old[i].file, old[i].line); 07538 assert(stb__hashfind(old[i].p) >= 0); 07539 } 07540 for (i=0; i < old_num; ++i) 07541 if (old[i].p > STB_DEL) 07542 assert(stb__hashfind(old[i].p) >= 0); 07543 stb__realloc_raw(old, 0); 07544 } 07545 07546 static void stb__add_alloc(void *p, size_t sz, char *file, int line) 07547 { 07548 stb_uint32 h; 07549 int n; 07550 if (stb__alloc_count >= stb__alloc_limit) 07551 stb__grow_alloc(); 07552 h = stb_hashptr(p); 07553 n = h & stb__alloc_mask; 07554 if (stb__allocations[n].p > STB_DEL) { 07555 int s = stb_rehash(h)|1; 07556 do { 07557 n = (n+s) & stb__alloc_mask; 07558 } while (stb__allocations[n].p > STB_DEL); 07559 } 07560 assert(stb__allocations[n].p == NULL || stb__allocations[n].p == STB_DEL); 07561 stb__allocations[n].p = p; 07562 stb__allocations[n].size = sz; 07563 stb__allocations[n].line = line; 07564 stb__allocations[n].file = file; 07565 ++stb__alloc_count; 07566 } 07567 07568 static void stb__remove_alloc(int n, char *file, int line) 07569 { 07570 stb__alloc_history[stb__history_pos] = stb__allocations[n]; 07571 stb__alloc_history[stb__history_pos].file = file; 07572 stb__alloc_history[stb__history_pos].line = line; 07573 if (++stb__history_pos == STB_MALLOC_HISTORY_COUNT) 07574 stb__history_pos = 0; 07575 stb__allocations[n].p = STB_DEL; 07576 --stb__alloc_count; 07577 } 07578 07579 void stb_wrapper_malloc(void *p, size_t sz, char *file, int line) 07580 { 07581 if (!p) return; 07582 stb__add_alloc(p,sz,file,line); 07583 } 07584 07585 void stb_wrapper_free(void *p, char *file, int line) 07586 { 07587 int n; 07588 07589 if (p == NULL) return; 07590 07591 n = stb__hashfind(p); 07592 07593 if (n >= 0) 07594 stb__remove_alloc(n, file, line); 07595 else { 07596 // tried to free something we hadn't allocated! 07597 n = stb__historyfind(p); 07598 assert(0); /* NOTREACHED */ 07599 if (n >= 0) 07600 stb_fatal("Attempted to free %d-byte block %p at %s:%d previously freed/realloced at %s:%d", 07601 stb__alloc_history[n].size, p, 07602 file, line, 07603 stb__alloc_history[n].file, stb__alloc_history[n].line); 07604 else 07605 stb_fatal("Attempted to free unknown block %p at %s:%d", p, file,line); 07606 } 07607 } 07608 07609 void stb_wrapper_check(void *p) 07610 { 07611 int n; 07612 07613 if (p == NULL) return; 07614 07615 n = stb__hashfind(p); 07616 07617 if (n >= 0) return; 07618 07619 for (n=0; n < stb__alloc_size; ++n) 07620 if (stb__allocations[n].p == p) 07621 stb_fatal("Internal error: pointer %p was allocated, but hash search failed", p); 07622 07623 // tried to free something that wasn't allocated! 07624 n = stb__historyfind(p); 07625 if (n >= 0) 07626 stb_fatal("Checked %d-byte block %p previously freed/realloced at %s:%d", 07627 stb__alloc_history[n].size, p, 07628 stb__alloc_history[n].file, stb__alloc_history[n].line); 07629 stb_fatal("Checked unknown block %p"); 07630 } 07631 07632 void stb_wrapper_realloc(void *p, void *q, size_t sz, char *file, int line) 07633 { 07634 int n; 07635 if (p == NULL) { stb_wrapper_malloc(q, sz, file, line); return; } 07636 if (q == NULL) return; // nothing happened 07637 07638 n = stb__hashfind(p); 07639 if (n == -1) { 07640 // tried to free something we hadn't allocated! 07641 // this is weird, though, because we got past the realloc! 07642 n = stb__historyfind(p); 07643 assert(0); /* NOTREACHED */ 07644 if (n >= 0) 07645 stb_fatal("Attempted to realloc %d-byte block %p at %s:%d previously freed/realloced at %s:%d", 07646 stb__alloc_history[n].size, p, 07647 file, line, 07648 stb__alloc_history[n].file, stb__alloc_history[n].line); 07649 else 07650 stb_fatal("Attempted to realloc unknown block %p at %s:%d", p, file,line); 07651 } else { 07652 if (q == p) { 07653 stb__allocations[n].size = sz; 07654 stb__allocations[n].file = file; 07655 stb__allocations[n].line = line; 07656 } else { 07657 stb__remove_alloc(n, file, line); 07658 stb__add_alloc(q,sz,file,line); 07659 } 07660 } 07661 } 07662 07663 void stb_wrapper_listall(void (*func)(void *ptr, size_t sz, char *file, int line)) 07664 { 07665 int i; 07666 for (i=0; i < stb__alloc_size; ++i) 07667 if (stb__allocations[i].p > STB_DEL) 07668 func(stb__allocations[i].p , stb__allocations[i].size, 07669 stb__allocations[i].file, stb__allocations[i].line); 07670 } 07671 07672 void stb_wrapper_dump(char *filename) 07673 { 07674 int i; 07675 FILE *f = stb_p_fopen(filename, "w"); 07676 if (!f) return; 07677 for (i=0; i < stb__alloc_size; ++i) 07678 if (stb__allocations[i].p > STB_DEL) 07679 fprintf(f, "%p %7d - %4d %s\n", 07680 stb__allocations[i].p , (int) stb__allocations[i].size, 07681 stb__allocations[i].line, stb__allocations[i].file); 07682 } 07683 #endif // STB_DEFINE 07684 07685 07687 // 07688 // stb_pointer_set 07689 // 07690 // 07691 // For data structures that support querying by key, data structure 07692 // classes always hand-wave away the issue of what to do if two entries 07693 // have the same key: basically, store a linked list of all the nodes 07694 // which have the same key (a LISP-style list). 07695 // 07696 // The thing is, it's not that trivial. If you have an O(log n) 07697 // lookup data structure, but then n/4 items have the same value, 07698 // you don't want to spend O(n) time scanning that list when 07699 // deleting an item if you already have a pointer to the item. 07700 // (You have to spend O(n) time enumerating all the items with 07701 // a given key, sure, and you can't accelerate deleting a particular 07702 // item if you only have the key, not a pointer to the item.) 07703 // 07704 // I'm going to call this data structure, whatever it turns out to 07705 // be, a "pointer set", because we don't store any associated data for 07706 // items in this data structure, we just answer the question of 07707 // whether an item is in it or not (it's effectively one bit per pointer). 07708 // Technically they don't have to be pointers; you could cast ints 07709 // to (void *) if you want, but you can't store 0 or 1 because of the 07710 // hash table. 07711 // 07712 // Since the fastest data structure we might want to add support for 07713 // identical-keys to is a hash table with O(1)-ish lookup time, 07714 // that means that the conceptual "linked list of all items with 07715 // the same indexed value" that we build needs to have the same 07716 // performance; that way when we index a table we think is arbitrary 07717 // ints, but in fact half of them are 0, we don't get screwed. 07718 // 07719 // Therefore, it needs to be a hash table, at least when it gets 07720 // large. On the other hand, when the data has totally arbitrary ints 07721 // or floats, there won't be many collisions, and we'll have tons of 07722 // 1-item bitmaps. That will be grossly inefficient as hash tables; 07723 // trade-off; the hash table is reasonably efficient per-item when 07724 // it's large, but not when it's small. So we need to do something 07725 // Judy-like and use different strategies depending on the size. 07726 // 07727 // Like Judy, we'll use the bottom bit to encode the strategy: 07728 // 07729 // bottom bits: 07730 // 00 - direct pointer 07731 // 01 - 4-item bucket (16 bytes, no length, NULLs) 07732 // 10 - N-item array 07733 // 11 - hash table 07734 07735 typedef struct stb_ps stb_ps; 07736 07737 STB_EXTERN int stb_ps_find (stb_ps *ps, void *value); 07738 STB_EXTERN stb_ps * stb_ps_add (stb_ps *ps, void *value); 07739 STB_EXTERN stb_ps * stb_ps_remove(stb_ps *ps, void *value); 07740 STB_EXTERN stb_ps * stb_ps_remove_any(stb_ps *ps, void **value); 07741 STB_EXTERN void stb_ps_delete(stb_ps *ps); 07742 STB_EXTERN int stb_ps_count (stb_ps *ps); 07743 07744 STB_EXTERN stb_ps * stb_ps_copy (stb_ps *ps); 07745 STB_EXTERN int stb_ps_subset(stb_ps *bigger, stb_ps *smaller); 07746 STB_EXTERN int stb_ps_eq (stb_ps *p0, stb_ps *p1); 07747 07748 STB_EXTERN void ** stb_ps_getlist (stb_ps *ps, int *count); 07749 STB_EXTERN int stb_ps_writelist(stb_ps *ps, void **list, int size ); 07750 07751 // enum and fastlist don't allocate storage, but you must consume the 07752 // list before there's any chance the data structure gets screwed up; 07753 STB_EXTERN int stb_ps_enum (stb_ps *ps, void *data, 07754 int (*func)(void *value, void*data) ); 07755 STB_EXTERN void ** stb_ps_fastlist(stb_ps *ps, int *count); 07756 // result: 07757 // returns a list, *count is the length of that list, 07758 // but some entries of the list may be invalid; 07759 // test with 'stb_ps_fastlist_valid(x)' 07760 07761 #define stb_ps_fastlist_valid(x) ((stb_uinta) (x) > 1) 07762 07763 #ifdef STB_DEFINE 07764 07765 enum 07766 { 07767 STB_ps_direct = 0, 07768 STB_ps_bucket = 1, 07769 STB_ps_array = 2, 07770 STB_ps_hash = 3, 07771 }; 07772 07773 #define STB_BUCKET_SIZE 4 07774 07775 typedef struct 07776 { 07777 void *p[STB_BUCKET_SIZE]; 07778 } stb_ps_bucket; 07779 #define GetBucket(p) ((stb_ps_bucket *) ((char *) (p) - STB_ps_bucket)) 07780 #define EncodeBucket(p) ((stb_ps *) ((char *) (p) + STB_ps_bucket)) 07781 07782 static void stb_bucket_free(stb_ps_bucket *b) 07783 { 07784 free(b); 07785 } 07786 07787 static stb_ps_bucket *stb_bucket_create2(void *v0, void *v1) 07788 { 07789 stb_ps_bucket *b = (stb_ps_bucket*) malloc(sizeof(*b)); 07790 b->p[0] = v0; 07791 b->p[1] = v1; 07792 b->p[2] = NULL; 07793 b->p[3] = NULL; 07794 return b; 07795 } 07796 07797 static stb_ps_bucket * stb_bucket_create3(void **v) 07798 { 07799 stb_ps_bucket *b = (stb_ps_bucket*) malloc(sizeof(*b)); 07800 b->p[0] = v[0]; 07801 b->p[1] = v[1]; 07802 b->p[2] = v[2]; 07803 b->p[3] = NULL; 07804 return b; 07805 } 07806 07807 07808 // could use stb_arr, but this will save us memory 07809 typedef struct 07810 { 07811 int count; 07812 void *p[1]; 07813 } stb_ps_array; 07814 #define GetArray(p) ((stb_ps_array *) ((char *) (p) - STB_ps_array)) 07815 #define EncodeArray(p) ((stb_ps *) ((char *) (p) + STB_ps_array)) 07816 07817 static int stb_ps_array_max = 13; 07818 07819 typedef struct 07820 { 07821 int size, mask; 07822 int count, count_deletes; 07823 int grow_threshhold; 07824 int shrink_threshhold; 07825 int rehash_threshhold; 07826 int any_offset; 07827 void *table[1]; 07828 } stb_ps_hash; 07829 #define GetHash(p) ((stb_ps_hash *) ((char *) (p) - STB_ps_hash)) 07830 #define EncodeHash(p) ((stb_ps *) ((char *) (p) + STB_ps_hash)) 07831 07832 #define stb_ps_empty(v) (((stb_uint32) v) <= 1) 07833 07834 static stb_ps_hash *stb_ps_makehash(int size, int old_size, void **old_data) 07835 { 07836 int i; 07837 stb_ps_hash *h = (stb_ps_hash *) malloc(sizeof(*h) + (size-1) * sizeof(h->table[0])); 07838 assert(stb_is_pow2(size)); 07839 h->size = size; 07840 h->mask = size-1; 07841 h->shrink_threshhold = (int) (0.3f * size); 07842 h-> grow_threshhold = (int) (0.8f * size); 07843 h->rehash_threshhold = (int) (0.9f * size); 07844 h->count = 0; 07845 h->count_deletes = 0; 07846 h->any_offset = 0; 07847 memset(h->table, 0, size * sizeof(h->table[0])); 07848 for (i=0; i < old_size; ++i) 07849 if (!stb_ps_empty((size_t)old_data[i])) 07850 stb_ps_add(EncodeHash(h), old_data[i]); 07851 return h; 07852 } 07853 07854 void stb_ps_delete(stb_ps *ps) 07855 { 07856 switch (3 & (int)(size_t) ps) { 07857 case STB_ps_direct: break; 07858 case STB_ps_bucket: stb_bucket_free(GetBucket(ps)); break; 07859 case STB_ps_array : free(GetArray(ps)); break; 07860 case STB_ps_hash : free(GetHash(ps)); break; 07861 } 07862 } 07863 07864 stb_ps *stb_ps_copy(stb_ps *ps) 07865 { 07866 int i; 07867 // not a switch: order based on expected performance/power-law distribution 07868 switch (3 & (int)(size_t) ps) { 07869 case STB_ps_direct: return ps; 07870 case STB_ps_bucket: { 07871 stb_ps_bucket *n = (stb_ps_bucket *) malloc(sizeof(*n)); 07872 *n = *GetBucket(ps); 07873 return EncodeBucket(n); 07874 } 07875 case STB_ps_array: { 07876 stb_ps_array *a = GetArray(ps); 07877 stb_ps_array *n = (stb_ps_array *) malloc(sizeof(*n) + stb_ps_array_max * sizeof(n->p[0])); 07878 n->count = a->count; 07879 for (i=0; i < a->count; ++i) 07880 n->p[i] = a->p[i]; 07881 return EncodeArray(n); 07882 } 07883 case STB_ps_hash: { 07884 stb_ps_hash *h = GetHash(ps); 07885 stb_ps_hash *n = stb_ps_makehash(h->size, h->size, h->table); 07886 return EncodeHash(n); 07887 } 07888 } 07889 assert(0); /* NOTREACHED */ 07890 return NULL; 07891 } 07892 07893 int stb_ps_find(stb_ps *ps, void *value) 07894 { 07895 int i, code = 3 & (int)(size_t) ps; 07896 assert((3 & (int)(size_t) value) == STB_ps_direct); 07897 assert(stb_ps_fastlist_valid(value)); 07898 // not a switch: order based on expected performance/power-law distribution 07899 if (code == STB_ps_direct) 07900 return value == ps; 07901 if (code == STB_ps_bucket) { 07902 stb_ps_bucket *b = GetBucket(ps); 07903 assert(STB_BUCKET_SIZE == 4); 07904 if (b->p[0] == value || b->p[1] == value || 07905 b->p[2] == value || b->p[3] == value) 07906 return STB_TRUE; 07907 return STB_FALSE; 07908 } 07909 if (code == STB_ps_array) { 07910 stb_ps_array *a = GetArray(ps); 07911 for (i=0; i < a->count; ++i) 07912 if (a->p[i] == value) 07913 return STB_TRUE; 07914 return STB_FALSE; 07915 } else { 07916 stb_ps_hash *h = GetHash(ps); 07917 stb_uint32 hash = stb_hashptr(value); 07918 stb_uint32 s, n = hash & h->mask; 07919 void **t = h->table; 07920 if (t[n] == value) return STB_TRUE; 07921 if (t[n] == NULL) return STB_FALSE; 07922 s = stb_rehash(hash) | 1; 07923 do { 07924 n = (n + s) & h->mask; 07925 if (t[n] == value) return STB_TRUE; 07926 } while (t[n] != NULL); 07927 return STB_FALSE; 07928 } 07929 } 07930 07931 stb_ps * stb_ps_add (stb_ps *ps, void *value) 07932 { 07933 #ifdef STB_DEBUG 07934 assert(!stb_ps_find(ps,value)); 07935 #endif 07936 if (value == NULL) return ps; // ignore NULL adds to avoid bad breakage 07937 assert((3 & (int)(size_t) value) == STB_ps_direct); 07938 assert(stb_ps_fastlist_valid(value)); 07939 assert(value != STB_DEL); // STB_DEL is less likely 07940 07941 switch (3 & (int)(size_t) ps) { 07942 case STB_ps_direct: 07943 if (ps == NULL) return (stb_ps *) value; 07944 return EncodeBucket(stb_bucket_create2(ps,value)); 07945 07946 case STB_ps_bucket: { 07947 stb_ps_bucket *b = GetBucket(ps); 07948 stb_ps_array *a; 07949 assert(STB_BUCKET_SIZE == 4); 07950 if (b->p[0] == NULL) { b->p[0] = value; return ps; } 07951 if (b->p[1] == NULL) { b->p[1] = value; return ps; } 07952 if (b->p[2] == NULL) { b->p[2] = value; return ps; } 07953 if (b->p[3] == NULL) { b->p[3] = value; return ps; } 07954 a = (stb_ps_array *) malloc(sizeof(*a) + 7 * sizeof(a->p[0])); // 8 slots, must be 2^k 07955 memcpy(a->p, b, sizeof(*b)); 07956 a->p[4] = value; 07957 a->count = 5; 07958 stb_bucket_free(b); 07959 return EncodeArray(a); 07960 } 07961 07962 case STB_ps_array: { 07963 stb_ps_array *a = GetArray(ps); 07964 if (a->count == stb_ps_array_max) { 07965 // promote from array to hash 07966 stb_ps_hash *h = stb_ps_makehash(2 << stb_log2_ceil(a->count), a->count, a->p); 07967 free(a); 07968 return stb_ps_add(EncodeHash(h), value); 07969 } 07970 // do we need to resize the array? the array doubles in size when it 07971 // crosses a power-of-two 07972 if ((a->count & (a->count-1))==0) { 07973 int newsize = a->count*2; 07974 // clamp newsize to max if: 07975 // 1. it's larger than max 07976 // 2. newsize*1.5 is larger than max (to avoid extra resizing) 07977 if (newsize + a->count > stb_ps_array_max) 07978 newsize = stb_ps_array_max; 07979 a = (stb_ps_array *) realloc(a, sizeof(*a) + (newsize-1) * sizeof(a->p[0])); 07980 } 07981 a->p[a->count++] = value; 07982 return EncodeArray(a); 07983 } 07984 case STB_ps_hash: { 07985 stb_ps_hash *h = GetHash(ps); 07986 stb_uint32 hash = stb_hashptr(value); 07987 stb_uint32 n = hash & h->mask; 07988 void **t = h->table; 07989 // find first NULL or STB_DEL entry 07990 if (!stb_ps_empty((size_t)t[n])) { 07991 stb_uint32 s = stb_rehash(hash) | 1; 07992 do { 07993 n = (n + s) & h->mask; 07994 } while (!stb_ps_empty((size_t)t[n])); 07995 } 07996 if (t[n] == STB_DEL) 07997 -- h->count_deletes; 07998 t[n] = value; 07999 ++ h->count; 08000 if (h->count == h->grow_threshhold) { 08001 stb_ps_hash *h2 = stb_ps_makehash(h->size*2, h->size, t); 08002 free(h); 08003 return EncodeHash(h2); 08004 } 08005 if (h->count + h->count_deletes == h->rehash_threshhold) { 08006 stb_ps_hash *h2 = stb_ps_makehash(h->size, h->size, t); 08007 free(h); 08008 return EncodeHash(h2); 08009 } 08010 return ps; 08011 } 08012 } 08013 return NULL; /* NOTREACHED */ 08014 } 08015 08016 stb_ps *stb_ps_remove(stb_ps *ps, void *value) 08017 { 08018 #ifdef STB_DEBUG 08019 assert(stb_ps_find(ps, value)); 08020 #endif 08021 assert((3 & (int)(size_t) value) == STB_ps_direct); 08022 if (value == NULL) return ps; // ignore NULL removes to avoid bad breakage 08023 switch (3 & (int)(size_t) ps) { 08024 case STB_ps_direct: 08025 return ps == value ? NULL : ps; 08026 case STB_ps_bucket: { 08027 stb_ps_bucket *b = GetBucket(ps); 08028 int count=0; 08029 assert(STB_BUCKET_SIZE == 4); 08030 if (b->p[0] == value) b->p[0] = NULL; else count += (b->p[0] != NULL); 08031 if (b->p[1] == value) b->p[1] = NULL; else count += (b->p[1] != NULL); 08032 if (b->p[2] == value) b->p[2] = NULL; else count += (b->p[2] != NULL); 08033 if (b->p[3] == value) b->p[3] = NULL; else count += (b->p[3] != NULL); 08034 if (count == 1) { // shrink bucket at size 1 08035 value = b->p[0]; 08036 if (value == NULL) value = b->p[1]; 08037 if (value == NULL) value = b->p[2]; 08038 if (value == NULL) value = b->p[3]; 08039 assert(value != NULL); 08040 stb_bucket_free(b); 08041 return (stb_ps *) value; // return STB_ps_direct of value 08042 } 08043 return ps; 08044 } 08045 case STB_ps_array: { 08046 stb_ps_array *a = GetArray(ps); 08047 int i; 08048 for (i=0; i < a->count; ++i) { 08049 if (a->p[i] == value) { 08050 a->p[i] = a->p[--a->count]; 08051 if (a->count == 3) { // shrink to bucket! 08052 stb_ps_bucket *b = stb_bucket_create3(a->p); 08053 free(a); 08054 return EncodeBucket(b); 08055 } 08056 return ps; 08057 } 08058 } 08059 return ps; 08060 } 08061 case STB_ps_hash: { 08062 stb_ps_hash *h = GetHash(ps); 08063 stb_uint32 hash = stb_hashptr(value); 08064 stb_uint32 s, n = hash & h->mask; 08065 void **t = h->table; 08066 if (t[n] != value) { 08067 s = stb_rehash(hash) | 1; 08068 do { 08069 n = (n + s) & h->mask; 08070 } while (t[n] != value); 08071 } 08072 t[n] = STB_DEL; 08073 -- h->count; 08074 ++ h->count_deletes; 08075 // should we shrink down to an array? 08076 if (h->count < stb_ps_array_max) { 08077 int n = 1 << stb_log2_floor(stb_ps_array_max); 08078 if (h->count < n) { 08079 stb_ps_array *a = (stb_ps_array *) malloc(sizeof(*a) + (n-1) * sizeof(a->p[0])); 08080 int i,j=0; 08081 for (i=0; i < h->size; ++i) 08082 if (!stb_ps_empty((size_t)t[i])) 08083 a->p[j++] = t[i]; 08084 assert(j == h->count); 08085 a->count = j; 08086 free(h); 08087 return EncodeArray(a); 08088 } 08089 } 08090 if (h->count == h->shrink_threshhold) { 08091 stb_ps_hash *h2 = stb_ps_makehash(h->size >> 1, h->size, t); 08092 free(h); 08093 return EncodeHash(h2); 08094 } 08095 return ps; 08096 } 08097 } 08098 return ps; /* NOTREACHED */ 08099 } 08100 08101 stb_ps *stb_ps_remove_any(stb_ps *ps, void **value) 08102 { 08103 assert(ps != NULL); 08104 switch (3 & (int)(size_t) ps) { 08105 case STB_ps_direct: 08106 *value = ps; 08107 return NULL; 08108 case STB_ps_bucket: { 08109 stb_ps_bucket *b = GetBucket(ps); 08110 int count=0, slast=0, last=0; 08111 assert(STB_BUCKET_SIZE == 4); 08112 if (b->p[0]) { ++count; last = 0; } 08113 if (b->p[1]) { ++count; slast = last; last = 1; } 08114 if (b->p[2]) { ++count; slast = last; last = 2; } 08115 if (b->p[3]) { ++count; slast = last; last = 3; } 08116 *value = b->p[last]; 08117 b->p[last] = 0; 08118 if (count == 2) { 08119 void *leftover = b->p[slast]; // second to last 08120 stb_bucket_free(b); 08121 return (stb_ps *) leftover; 08122 } 08123 return ps; 08124 } 08125 case STB_ps_array: { 08126 stb_ps_array *a = GetArray(ps); 08127 *value = a->p[a->count-1]; 08128 if (a->count == 4) 08129 return stb_ps_remove(ps, *value); 08130 --a->count; 08131 return ps; 08132 } 08133 case STB_ps_hash: { 08134 stb_ps_hash *h = GetHash(ps); 08135 void **t = h->table; 08136 stb_uint32 n = h->any_offset; 08137 while (stb_ps_empty((size_t)t[n])) 08138 n = (n + 1) & h->mask; 08139 *value = t[n]; 08140 h->any_offset = (n+1) & h->mask; 08141 // check if we need to skip down to the previous type 08142 if (h->count-1 < stb_ps_array_max || h->count-1 == h->shrink_threshhold) 08143 return stb_ps_remove(ps, *value); 08144 t[n] = STB_DEL; 08145 -- h->count; 08146 ++ h->count_deletes; 08147 return ps; 08148 } 08149 } 08150 return ps; /* NOTREACHED */ 08151 } 08152 08153 08154 void ** stb_ps_getlist(stb_ps *ps, int *count) 08155 { 08156 int i,n=0; 08157 void **p = NULL; 08158 switch (3 & (int)(size_t) ps) { 08159 case STB_ps_direct: 08160 if (ps == NULL) { *count = 0; return NULL; } 08161 p = (void **) malloc(sizeof(*p) * 1); 08162 p[0] = ps; 08163 *count = 1; 08164 return p; 08165 case STB_ps_bucket: { 08166 stb_ps_bucket *b = GetBucket(ps); 08167 p = (void **) malloc(sizeof(*p) * STB_BUCKET_SIZE); 08168 for (i=0; i < STB_BUCKET_SIZE; ++i) 08169 if (b->p[i] != NULL) 08170 p[n++] = b->p[i]; 08171 break; 08172 } 08173 case STB_ps_array: { 08174 stb_ps_array *a = GetArray(ps); 08175 p = (void **) malloc(sizeof(*p) * a->count); 08176 memcpy(p, a->p, sizeof(*p) * a->count); 08177 *count = a->count; 08178 return p; 08179 } 08180 case STB_ps_hash: { 08181 stb_ps_hash *h = GetHash(ps); 08182 p = (void **) malloc(sizeof(*p) * h->count); 08183 for (i=0; i < h->size; ++i) 08184 if (!stb_ps_empty((size_t)h->table[i])) 08185 p[n++] = h->table[i]; 08186 break; 08187 } 08188 } 08189 *count = n; 08190 return p; 08191 } 08192 08193 int stb_ps_writelist(stb_ps *ps, void **list, int size ) 08194 { 08195 int i,n=0; 08196 switch (3 & (int)(size_t) ps) { 08197 case STB_ps_direct: 08198 if (ps == NULL || size <= 0) return 0; 08199 list[0] = ps; 08200 return 1; 08201 case STB_ps_bucket: { 08202 stb_ps_bucket *b = GetBucket(ps); 08203 for (i=0; i < STB_BUCKET_SIZE; ++i) 08204 if (b->p[i] != NULL && n < size) 08205 list[n++] = b->p[i]; 08206 return n; 08207 } 08208 case STB_ps_array: { 08209 stb_ps_array *a = GetArray(ps); 08210 n = stb_min(size, a->count); 08211 memcpy(list, a->p, sizeof(*list) * n); 08212 return n; 08213 } 08214 case STB_ps_hash: { 08215 stb_ps_hash *h = GetHash(ps); 08216 if (size <= 0) return 0; 08217 for (i=0; i < h->count; ++i) { 08218 if (!stb_ps_empty((size_t)h->table[i])) { 08219 list[n++] = h->table[i]; 08220 if (n == size) break; 08221 } 08222 } 08223 return n; 08224 } 08225 } 08226 return 0; /* NOTREACHED */ 08227 } 08228 08229 int stb_ps_enum(stb_ps *ps, void *data, int (*func)(void *value, void *data)) 08230 { 08231 int i; 08232 switch (3 & (int)(size_t) ps) { 08233 case STB_ps_direct: 08234 if (ps == NULL) return STB_TRUE; 08235 return func(ps, data); 08236 case STB_ps_bucket: { 08237 stb_ps_bucket *b = GetBucket(ps); 08238 for (i=0; i < STB_BUCKET_SIZE; ++i) 08239 if (b->p[i] != NULL) 08240 if (!func(b->p[i], data)) 08241 return STB_FALSE; 08242 return STB_TRUE; 08243 } 08244 case STB_ps_array: { 08245 stb_ps_array *a = GetArray(ps); 08246 for (i=0; i < a->count; ++i) 08247 if (!func(a->p[i], data)) 08248 return STB_FALSE; 08249 return STB_TRUE; 08250 } 08251 case STB_ps_hash: { 08252 stb_ps_hash *h = GetHash(ps); 08253 for (i=0; i < h->count; ++i) 08254 if (!stb_ps_empty((size_t)h->table[i])) 08255 if (!func(h->table[i], data)) 08256 return STB_FALSE; 08257 return STB_TRUE; 08258 } 08259 } 08260 return STB_TRUE; /* NOTREACHED */ 08261 } 08262 08263 int stb_ps_count (stb_ps *ps) 08264 { 08265 switch (3 & (int)(size_t) ps) { 08266 case STB_ps_direct: 08267 return ps != NULL; 08268 case STB_ps_bucket: { 08269 stb_ps_bucket *b = GetBucket(ps); 08270 return (b->p[0] != NULL) + (b->p[1] != NULL) + 08271 (b->p[2] != NULL) + (b->p[3] != NULL); 08272 } 08273 case STB_ps_array: { 08274 stb_ps_array *a = GetArray(ps); 08275 return a->count; 08276 } 08277 case STB_ps_hash: { 08278 stb_ps_hash *h = GetHash(ps); 08279 return h->count; 08280 } 08281 } 08282 return 0; 08283 } 08284 08285 void ** stb_ps_fastlist(stb_ps *ps, int *count) 08286 { 08287 static void *storage; 08288 08289 switch (3 & (int)(size_t) ps) { 08290 case STB_ps_direct: 08291 if (ps == NULL) { *count = 0; return NULL; } 08292 storage = ps; 08293 *count = 1; 08294 return &storage; 08295 case STB_ps_bucket: { 08296 stb_ps_bucket *b = GetBucket(ps); 08297 *count = STB_BUCKET_SIZE; 08298 return b->p; 08299 } 08300 case STB_ps_array: { 08301 stb_ps_array *a = GetArray(ps); 08302 *count = a->count; 08303 return a->p; 08304 } 08305 case STB_ps_hash: { 08306 stb_ps_hash *h = GetHash(ps); 08307 *count = h->size; 08308 return h->table; 08309 } 08310 } 08311 return NULL; /* NOTREACHED */ 08312 } 08313 08314 int stb_ps_subset(stb_ps *bigger, stb_ps *smaller) 08315 { 08316 int i, listlen; 08317 void **list = stb_ps_fastlist(smaller, &listlen); 08318 for(i=0; i < listlen; ++i) 08319 if (stb_ps_fastlist_valid(list[i])) 08320 if (!stb_ps_find(bigger, list[i])) 08321 return 0; 08322 return 1; 08323 } 08324 08325 int stb_ps_eq(stb_ps *p0, stb_ps *p1) 08326 { 08327 if (stb_ps_count(p0) != stb_ps_count(p1)) 08328 return 0; 08329 return stb_ps_subset(p0, p1); 08330 } 08331 08332 #undef GetBucket 08333 #undef GetArray 08334 #undef GetHash 08335 08336 #undef EncodeBucket 08337 #undef EncodeArray 08338 #undef EncodeHash 08339 08340 #endif 08341 08342 08344 // 08345 // Random Numbers via Meresenne Twister or LCG 08346 // 08347 08348 STB_EXTERN unsigned int stb_srandLCG(unsigned int seed); 08349 STB_EXTERN unsigned int stb_randLCG(void); 08350 STB_EXTERN double stb_frandLCG(void); 08351 08352 STB_EXTERN void stb_srand(unsigned int seed); 08353 STB_EXTERN unsigned int stb_rand(void); 08354 STB_EXTERN double stb_frand(void); 08355 STB_EXTERN void stb_shuffle(void *p, size_t n, size_t sz, 08356 unsigned int seed); 08357 STB_EXTERN void stb_reverse(void *p, size_t n, size_t sz); 08358 08359 STB_EXTERN unsigned int stb_randLCG_explicit(unsigned int seed); 08360 08361 #define stb_rand_define(x,y) \ 08362 \ 08363 unsigned int x(void) \ 08364 { \ 08365 static unsigned int stb__rand = y; \ 08366 stb__rand = stb__rand * 2147001325 + 715136305; /* BCPL */ \ 08367 return 0x31415926 ^ ((stb__rand >> 16) + (stb__rand << 16)); \ 08368 } 08369 08370 #ifdef STB_DEFINE 08371 unsigned int stb_randLCG_explicit(unsigned int seed) 08372 { 08373 return seed * 2147001325 + 715136305; 08374 } 08375 08376 static unsigned int stb__rand_seed=0; 08377 08378 unsigned int stb_srandLCG(unsigned int seed) 08379 { 08380 unsigned int previous = stb__rand_seed; 08381 stb__rand_seed = seed; 08382 return previous; 08383 } 08384 08385 unsigned int stb_randLCG(void) 08386 { 08387 stb__rand_seed = stb__rand_seed * 2147001325 + 715136305; // BCPL generator 08388 // shuffle non-random bits to the middle, and xor to decorrelate with seed 08389 return 0x31415926 ^ ((stb__rand_seed >> 16) + (stb__rand_seed << 16)); 08390 } 08391 08392 double stb_frandLCG(void) 08393 { 08394 return stb_randLCG() / ((double) (1 << 16) * (1 << 16)); 08395 } 08396 08397 void stb_shuffle(void *p, size_t n, size_t sz, unsigned int seed) 08398 { 08399 char *a; 08400 unsigned int old_seed; 08401 int i; 08402 if (seed) 08403 old_seed = stb_srandLCG(seed); 08404 a = (char *) p + (n-1) * sz; 08405 08406 for (i=(int) n; i > 1; --i) { 08407 int j = stb_randLCG() % i; 08408 stb_swap(a, (char *) p + j * sz, sz); 08409 a -= sz; 08410 } 08411 if (seed) 08412 stb_srandLCG(old_seed); 08413 } 08414 08415 void stb_reverse(void *p, size_t n, size_t sz) 08416 { 08417 size_t i,j = n-1; 08418 for (i=0; i < j; ++i,--j) { 08419 stb_swap((char *) p + i * sz, (char *) p + j * sz, sz); 08420 } 08421 } 08422 08423 // public domain Mersenne Twister by Michael Brundage 08424 #define STB__MT_LEN 624 08425 08426 int stb__mt_index = STB__MT_LEN*sizeof(int)+1; 08427 unsigned int stb__mt_buffer[STB__MT_LEN]; 08428 08429 void stb_srand(unsigned int seed) 08430 { 08431 int i; 08432 unsigned int old = stb_srandLCG(seed); 08433 for (i = 0; i < STB__MT_LEN; i++) 08434 stb__mt_buffer[i] = stb_randLCG(); 08435 stb_srandLCG(old); 08436 stb__mt_index = STB__MT_LEN*sizeof(unsigned int); 08437 } 08438 08439 #define STB__MT_IA 397 08440 #define STB__MT_IB (STB__MT_LEN - STB__MT_IA) 08441 #define STB__UPPER_MASK 0x80000000 08442 #define STB__LOWER_MASK 0x7FFFFFFF 08443 #define STB__MATRIX_A 0x9908B0DF 08444 #define STB__TWIST(b,i,j) ((b)[i] & STB__UPPER_MASK) | ((b)[j] & STB__LOWER_MASK) 08445 #define STB__MAGIC(s) (((s)&1)*STB__MATRIX_A) 08446 08447 unsigned int stb_rand() 08448 { 08449 unsigned int * b = stb__mt_buffer; 08450 int idx = stb__mt_index; 08451 unsigned int s,r; 08452 int i; 08453 08454 if (idx >= STB__MT_LEN*sizeof(unsigned int)) { 08455 if (idx > STB__MT_LEN*sizeof(unsigned int)) 08456 stb_srand(0); 08457 idx = 0; 08458 i = 0; 08459 for (; i < STB__MT_IB; i++) { 08460 s = STB__TWIST(b, i, i+1); 08461 b[i] = b[i + STB__MT_IA] ^ (s >> 1) ^ STB__MAGIC(s); 08462 } 08463 for (; i < STB__MT_LEN-1; i++) { 08464 s = STB__TWIST(b, i, i+1); 08465 b[i] = b[i - STB__MT_IB] ^ (s >> 1) ^ STB__MAGIC(s); 08466 } 08467 08468 s = STB__TWIST(b, STB__MT_LEN-1, 0); 08469 b[STB__MT_LEN-1] = b[STB__MT_IA-1] ^ (s >> 1) ^ STB__MAGIC(s); 08470 } 08471 stb__mt_index = idx + sizeof(unsigned int); 08472 08473 r = *(unsigned int *)((unsigned char *)b + idx); 08474 08475 r ^= (r >> 11); 08476 r ^= (r << 7) & 0x9D2C5680; 08477 r ^= (r << 15) & 0xEFC60000; 08478 r ^= (r >> 18); 08479 08480 return r; 08481 } 08482 08483 double stb_frand(void) 08484 { 08485 return stb_rand() / ((double) (1 << 16) * (1 << 16)); 08486 } 08487 08488 #endif 08489 08490 08492 // 08493 // stb_dupe 08494 // 08495 // stb_dupe is a duplicate-finding system for very, very large data 08496 // structures--large enough that sorting is too slow, but not so large 08497 // that we can't keep all the data in memory. using it works as follows: 08498 // 08499 // 1. create an stb_dupe: 08500 // provide a hash function 08501 // provide an equality function 08502 // provide an estimate for the size 08503 // optionally provide a comparison function 08504 // 08505 // 2. traverse your data, 'adding' pointers to the stb_dupe 08506 // 08507 // 3. finish and ask for duplicates 08508 // 08509 // the stb_dupe will discard its intermediate data and build 08510 // a collection of sorted lists of duplicates, with non-duplicate 08511 // entries omitted entirely 08512 // 08513 // 08514 // Implementation strategy: 08515 // 08516 // while collecting the N items, we keep a hash table of approximate 08517 // size sqrt(N). (if you tell use the N up front, the hash table is 08518 // just that size exactly) 08519 // 08520 // each entry in the hash table is just an stb__arr of pointers (no need 08521 // to use stb_ps, because we don't need to delete from these) 08522 // 08523 // for step 3, for each entry in the hash table, we apply stb_dupe to it 08524 // recursively. once the size gets small enough (or doesn't decrease 08525 // significantly), we switch to either using qsort() on the comparison 08526 // function, or else we just do the icky N^2 gather 08527 08528 08529 typedef struct stb_dupe stb_dupe; 08530 08531 typedef int (*stb_compare_func)(void *a, void *b); 08532 typedef int (*stb_hash_func)(void *a, unsigned int seed); 08533 08534 STB_EXTERN void stb_dupe_free(stb_dupe *sd); 08535 STB_EXTERN stb_dupe *stb_dupe_create(stb_hash_func hash, 08536 stb_compare_func eq, int size, stb_compare_func ineq); 08537 STB_EXTERN void stb_dupe_add(stb_dupe *sd, void *item); 08538 STB_EXTERN void stb_dupe_finish(stb_dupe *sd); 08539 STB_EXTERN int stb_dupe_numsets(stb_dupe *sd); 08540 STB_EXTERN void **stb_dupe_set(stb_dupe *sd, int num); 08541 STB_EXTERN int stb_dupe_set_count(stb_dupe *sd, int num); 08542 08543 struct stb_dupe 08544 { 08545 void ***hash_table; 08546 int hash_size; 08547 int size_log2; 08548 int population; 08549 08550 int hash_shift; 08551 stb_hash_func hash; 08552 08553 stb_compare_func eq; 08554 stb_compare_func ineq; 08555 08556 void ***dupes; 08557 }; 08558 08559 #ifdef STB_DEFINE 08560 08561 int stb_dupe_numsets(stb_dupe *sd) 08562 { 08563 assert(sd->hash_table == NULL); 08564 return stb_arr_len(sd->dupes); 08565 } 08566 08567 void **stb_dupe_set(stb_dupe *sd, int num) 08568 { 08569 assert(sd->hash_table == NULL); 08570 return sd->dupes[num]; 08571 } 08572 08573 int stb_dupe_set_count(stb_dupe *sd, int num) 08574 { 08575 assert(sd->hash_table == NULL); 08576 return stb_arr_len(sd->dupes[num]); 08577 } 08578 08579 stb_dupe *stb_dupe_create(stb_hash_func hash, stb_compare_func eq, int size, 08580 stb_compare_func ineq) 08581 { 08582 int i, hsize; 08583 stb_dupe *sd = (stb_dupe *) malloc(sizeof(*sd)); 08584 08585 sd->size_log2 = 4; 08586 hsize = 1 << sd->size_log2; 08587 while (hsize * hsize < size) { 08588 ++sd->size_log2; 08589 hsize *= 2; 08590 } 08591 08592 sd->hash = hash; 08593 sd->eq = eq; 08594 sd->ineq = ineq; 08595 sd->hash_shift = 0; 08596 08597 sd->population = 0; 08598 sd->hash_size = hsize; 08599 sd->hash_table = (void ***) malloc(sizeof(*sd->hash_table) * hsize); 08600 for (i=0; i < hsize; ++i) 08601 sd->hash_table[i] = NULL; 08602 08603 sd->dupes = NULL; 08604 08605 return sd; 08606 } 08607 08608 void stb_dupe_add(stb_dupe *sd, void *item) 08609 { 08610 stb_uint32 hash = sd->hash(item, sd->hash_shift); 08611 int z = hash & (sd->hash_size-1); 08612 stb_arr_push(sd->hash_table[z], item); 08613 ++sd->population; 08614 } 08615 08616 void stb_dupe_free(stb_dupe *sd) 08617 { 08618 int i; 08619 for (i=0; i < stb_arr_len(sd->dupes); ++i) 08620 if (sd->dupes[i]) 08621 stb_arr_free(sd->dupes[i]); 08622 stb_arr_free(sd->dupes); 08623 free(sd); 08624 } 08625 08626 static stb_compare_func stb__compare; 08627 08628 static int stb__dupe_compare(const void *a, const void *b) 08629 { 08630 void *p = *(void **) a; 08631 void *q = *(void **) b; 08632 08633 return stb__compare(p,q); 08634 } 08635 08636 void stb_dupe_finish(stb_dupe *sd) 08637 { 08638 int i,j,k; 08639 assert(sd->dupes == NULL); 08640 for (i=0; i < sd->hash_size; ++i) { 08641 void ** list = sd->hash_table[i]; 08642 if (list != NULL) { 08643 int n = stb_arr_len(list); 08644 // @TODO: measure to find good numbers instead of just making them up! 08645 int thresh = (sd->ineq ? 200 : 20); 08646 // if n is large enough to be worth it, and n is smaller than 08647 // before (so we can guarantee we'll use a smaller hash table); 08648 // and there are enough hash bits left, assuming full 32-bit hash 08649 if (n > thresh && n < (sd->population >> 3) && sd->hash_shift + sd->size_log2*2 < 32) { 08650 08651 // recursively process this row using stb_dupe, O(N log log N) 08652 08653 stb_dupe *d = stb_dupe_create(sd->hash, sd->eq, n, sd->ineq); 08654 d->hash_shift = stb_randLCG_explicit(sd->hash_shift); 08655 for (j=0; j < n; ++j) 08656 stb_dupe_add(d, list[j]); 08657 stb_arr_free(sd->hash_table[i]); 08658 stb_dupe_finish(d); 08659 for (j=0; j < stb_arr_len(d->dupes); ++j) { 08660 stb_arr_push(sd->dupes, d->dupes[j]); 08661 d->dupes[j] = NULL; // take over ownership 08662 } 08663 stb_dupe_free(d); 08664 08665 } else if (sd->ineq) { 08666 08667 // process this row using qsort(), O(N log N) 08668 stb__compare = sd->ineq; 08669 qsort(list, n, sizeof(list[0]), stb__dupe_compare); 08670 08671 // find equal subsequences of the list 08672 for (j=0; j < n-1; ) { 08673 // find a subsequence from j..k 08674 for (k=j; k < n; ++k) 08675 // only use ineq so eq can be left undefined 08676 if (sd->ineq(list[j], list[k])) 08677 break; 08678 // k is the first one not in the subsequence 08679 if (k-j > 1) { 08680 void **mylist = NULL; 08681 stb_arr_setlen(mylist, k-j); 08682 memcpy(mylist, list+j, sizeof(list[j]) * (k-j)); 08683 stb_arr_push(sd->dupes, mylist); 08684 } 08685 j = k; 08686 } 08687 stb_arr_free(sd->hash_table[i]); 08688 } else { 08689 08690 // process this row using eq(), O(N^2) 08691 for (j=0; j < n; ++j) { 08692 if (list[j] != NULL) { 08693 void **output = NULL; 08694 for (k=j+1; k < n; ++k) { 08695 if (sd->eq(list[j], list[k])) { 08696 if (output == NULL) 08697 stb_arr_push(output, list[j]); 08698 stb_arr_push(output, list[k]); 08699 list[k] = NULL; 08700 } 08701 } 08702 list[j] = NULL; 08703 if (output) 08704 stb_arr_push(sd->dupes, output); 08705 } 08706 } 08707 stb_arr_free(sd->hash_table[i]); 08708 } 08709 } 08710 } 08711 free(sd->hash_table); 08712 sd->hash_table = NULL; 08713 } 08714 #endif 08715 08717 // 08718 // templatized Sort routine 08719 // 08720 // This is an attempt to implement a templated sorting algorithm. 08721 // To use it, you have to explicitly instantiate it as a _function_, 08722 // then you call that function. This allows the comparison to be inlined, 08723 // giving the sort similar performance to C++ sorts. 08724 // 08725 // It implements quicksort with three-way-median partitioning (generally 08726 // well-behaved), with a final insertion sort pass. 08727 // 08728 // When you define the compare expression, you should assume you have 08729 // elements of your array pointed to by 'a' and 'b', and perform the comparison 08730 // on those. OR you can use one or more statements; first say '0;', then 08731 // write whatever code you want, and compute the result into a variable 'c'. 08732 08733 #define stb_declare_sort(FUNCNAME, TYPE) \ 08734 void FUNCNAME(TYPE *p, int n) 08735 #define stb_define_sort(FUNCNAME,TYPE,COMPARE) \ 08736 stb__define_sort( void, FUNCNAME,TYPE,COMPARE) 08737 #define stb_define_sort_static(FUNCNAME,TYPE,COMPARE) \ 08738 stb__define_sort(static void, FUNCNAME,TYPE,COMPARE) 08739 08740 #define stb__define_sort(MODE, FUNCNAME, TYPE, COMPARE) \ 08741 \ 08742 static void STB_(FUNCNAME,_ins_sort)(TYPE *p, int n) \ 08743 { \ 08744 int i,j; \ 08745 for (i=1; i < n; ++i) { \ 08746 TYPE t = p[i], *a = &t; \ 08747 j = i; \ 08748 while (j > 0) { \ 08749 TYPE *b = &p[j-1]; \ 08750 int c = COMPARE; \ 08751 if (!c) break; \ 08752 p[j] = p[j-1]; \ 08753 --j; \ 08754 } \ 08755 if (i != j) \ 08756 p[j] = t; \ 08757 } \ 08758 } \ 08759 \ 08760 static void STB_(FUNCNAME,_quicksort)(TYPE *p, int n) \ 08761 { \ 08762 /* threshold for transitioning to insertion sort */ \ 08763 while (n > 12) { \ 08764 TYPE *a,*b,t; \ 08765 int c01,c12,c,m,i,j; \ 08766 \ 08767 /* compute median of three */ \ 08768 m = n >> 1; \ 08769 a = &p[0]; \ 08770 b = &p[m]; \ 08771 c = COMPARE; \ 08772 c01 = c; \ 08773 a = &p[m]; \ 08774 b = &p[n-1]; \ 08775 c = COMPARE; \ 08776 c12 = c; \ 08777 /* if 0 >= mid >= end, or 0 < mid < end, then use mid */ \ 08778 if (c01 != c12) { \ 08779 /* otherwise, we'll need to swap something else to middle */ \ 08780 int z; \ 08781 a = &p[0]; \ 08782 b = &p[n-1]; \ 08783 c = COMPARE; \ 08784 /* 0>mid && mid<n: 0>n => n; 0<n => 0 */ \ 08785 /* 0<mid && mid>n: 0>n => 0; 0<n => n */ \ 08786 z = (c == c12) ? 0 : n-1; \ 08787 t = p[z]; \ 08788 p[z] = p[m]; \ 08789 p[m] = t; \ 08790 } \ 08791 /* now p[m] is the median-of-three */ \ 08792 /* swap it to the beginning so it won't move around */ \ 08793 t = p[0]; \ 08794 p[0] = p[m]; \ 08795 p[m] = t; \ 08796 \ 08797 /* partition loop */ \ 08798 i=1; \ 08799 j=n-1; \ 08800 for(;;) { \ 08801 /* handling of equality is crucial here */ \ 08802 /* for sentinels & efficiency with duplicates */ \ 08803 b = &p[0]; \ 08804 for (;;++i) { \ 08805 a=&p[i]; \ 08806 c = COMPARE; \ 08807 if (!c) break; \ 08808 } \ 08809 a = &p[0]; \ 08810 for (;;--j) { \ 08811 b=&p[j]; \ 08812 c = COMPARE; \ 08813 if (!c) break; \ 08814 } \ 08815 /* make sure we haven't crossed */ \ 08816 if (i >= j) break; \ 08817 t = p[i]; \ 08818 p[i] = p[j]; \ 08819 p[j] = t; \ 08820 \ 08821 ++i; \ 08822 --j; \ 08823 } \ 08824 /* recurse on smaller side, iterate on larger */ \ 08825 if (j < (n-i)) { \ 08826 STB_(FUNCNAME,_quicksort)(p,j); \ 08827 p = p+i; \ 08828 n = n-i; \ 08829 } else { \ 08830 STB_(FUNCNAME,_quicksort)(p+i, n-i); \ 08831 n = j; \ 08832 } \ 08833 } \ 08834 } \ 08835 \ 08836 MODE FUNCNAME(TYPE *p, int n) \ 08837 { \ 08838 STB_(FUNCNAME, _quicksort)(p, n); \ 08839 STB_(FUNCNAME, _ins_sort)(p, n); \ 08840 } \ 08841 08842 08844 // 08845 // stb_bitset an array of booleans indexed by integers 08846 // 08847 08848 typedef stb_uint32 stb_bitset; 08849 08850 STB_EXTERN stb_bitset *stb_bitset_new(int value, int len); 08851 08852 #define stb_bitset_clearall(arr,len) (memset(arr, 0, 4 * (len))) 08853 #define stb_bitset_setall(arr,len) (memset(arr, 255, 4 * (len))) 08854 08855 #define stb_bitset_setbit(arr,n) ((arr)[(n) >> 5] |= (1 << (n & 31))) 08856 #define stb_bitset_clearbit(arr,n) ((arr)[(n) >> 5] &= ~(1 << (n & 31))) 08857 #define stb_bitset_testbit(arr,n) ((arr)[(n) >> 5] & (1 << (n & 31))) 08858 08859 STB_EXTERN stb_bitset *stb_bitset_union(stb_bitset *p0, stb_bitset *p1, int len); 08860 08861 STB_EXTERN int *stb_bitset_getlist(stb_bitset *out, int start, int end); 08862 08863 STB_EXTERN int stb_bitset_eq(stb_bitset *p0, stb_bitset *p1, int len); 08864 STB_EXTERN int stb_bitset_disjoint(stb_bitset *p0, stb_bitset *p1, int len); 08865 STB_EXTERN int stb_bitset_disjoint_0(stb_bitset *p0, stb_bitset *p1, int len); 08866 STB_EXTERN int stb_bitset_subset(stb_bitset *bigger, stb_bitset *smaller, int len); 08867 STB_EXTERN int stb_bitset_unioneq_changed(stb_bitset *p0, stb_bitset *p1, int len); 08868 08869 #ifdef STB_DEFINE 08870 int stb_bitset_eq(stb_bitset *p0, stb_bitset *p1, int len) 08871 { 08872 int i; 08873 for (i=0; i < len; ++i) 08874 if (p0[i] != p1[i]) return 0; 08875 return 1; 08876 } 08877 08878 int stb_bitset_disjoint(stb_bitset *p0, stb_bitset *p1, int len) 08879 { 08880 int i; 08881 for (i=0; i < len; ++i) 08882 if (p0[i] & p1[i]) return 0; 08883 return 1; 08884 } 08885 08886 int stb_bitset_disjoint_0(stb_bitset *p0, stb_bitset *p1, int len) 08887 { 08888 int i; 08889 for (i=0; i < len; ++i) 08890 if ((p0[i] | p1[i]) != 0xffffffff) return 0; 08891 return 1; 08892 } 08893 08894 int stb_bitset_subset(stb_bitset *bigger, stb_bitset *smaller, int len) 08895 { 08896 int i; 08897 for (i=0; i < len; ++i) 08898 if ((bigger[i] & smaller[i]) != smaller[i]) return 0; 08899 return 1; 08900 } 08901 08902 stb_bitset *stb_bitset_union(stb_bitset *p0, stb_bitset *p1, int len) 08903 { 08904 int i; 08905 stb_bitset *d = (stb_bitset *) malloc(sizeof(*d) * len); 08906 for (i=0; i < len; ++i) d[i] = p0[i] | p1[i]; 08907 return d; 08908 } 08909 08910 int stb_bitset_unioneq_changed(stb_bitset *p0, stb_bitset *p1, int len) 08911 { 08912 int i, changed=0; 08913 for (i=0; i < len; ++i) { 08914 stb_bitset d = p0[i] | p1[i]; 08915 if (d != p0[i]) { 08916 p0[i] = d; 08917 changed = 1; 08918 } 08919 } 08920 return changed; 08921 } 08922 08923 stb_bitset *stb_bitset_new(int value, int len) 08924 { 08925 int i; 08926 stb_bitset *d = (stb_bitset *) malloc(sizeof(*d) * len); 08927 if (value) value = 0xffffffff; 08928 for (i=0; i < len; ++i) d[i] = value; 08929 return d; 08930 } 08931 08932 int *stb_bitset_getlist(stb_bitset *out, int start, int end) 08933 { 08934 int *list = NULL; 08935 int i; 08936 for (i=start; i < end; ++i) 08937 if (stb_bitset_testbit(out, i)) 08938 stb_arr_push(list, i); 08939 return list; 08940 } 08941 #endif 08942 08944 // 08945 // stb_wordwrap quality word-wrapping for fixed-width fonts 08946 // 08947 08948 STB_EXTERN int stb_wordwrap(int *pairs, int pair_max, int count, char *str); 08949 STB_EXTERN int *stb_wordwrapalloc(int count, char *str); 08950 08951 #ifdef STB_DEFINE 08952 08953 int stb_wordwrap(int *pairs, int pair_max, int count, char *str) 08954 { 08955 int n=0,i=0, start=0,nonwhite=0; 08956 if (pairs == NULL) pair_max = 0x7ffffff0; 08957 else pair_max *= 2; 08958 // parse 08959 for(;;) { 08960 int s=i; // first whitespace char; last nonwhite+1 08961 int w; // word start 08962 // accept whitespace 08963 while (isspace(str[i])) { 08964 if (str[i] == '\n' || str[i] == '\r') { 08965 if (str[i] + str[i+1] == '\n' + '\r') ++i; 08966 if (n >= pair_max) return -1; 08967 if (pairs) pairs[n] = start, pairs[n+1] = s-start; 08968 n += 2; 08969 nonwhite=0; 08970 start = i+1; 08971 s = start; 08972 } 08973 ++i; 08974 } 08975 if (i >= start+count) { 08976 // we've gone off the end using whitespace 08977 if (nonwhite) { 08978 if (n >= pair_max) return -1; 08979 if (pairs) pairs[n] = start, pairs[n+1] = s-start; 08980 n += 2; 08981 start = s = i; 08982 nonwhite=0; 08983 } else { 08984 // output all the whitespace 08985 while (i >= start+count) { 08986 if (n >= pair_max) return -1; 08987 if (pairs) pairs[n] = start, pairs[n+1] = count; 08988 n += 2; 08989 start += count; 08990 } 08991 s = start; 08992 } 08993 } 08994 08995 if (str[i] == 0) break; 08996 // now scan out a word and see if it fits 08997 w = i; 08998 while (str[i] && !isspace(str[i])) { 08999 ++i; 09000 } 09001 // wrapped? 09002 if (i > start + count) { 09003 // huge? 09004 if (i-s <= count) { 09005 if (n >= pair_max) return -1; 09006 if (pairs) pairs[n] = start, pairs[n+1] = s-start; 09007 n += 2; 09008 start = w; 09009 } else { 09010 // This word is longer than one line. If we wrap it onto N lines 09011 // there are leftover chars. do those chars fit on the cur line? 09012 // But if we have leading whitespace, we force it to start here. 09013 if ((w-start) + ((i-w) % count) <= count || !nonwhite) { 09014 // output a full line 09015 if (n >= pair_max) return -1; 09016 if (pairs) pairs[n] = start, pairs[n+1] = count; 09017 n += 2; 09018 start += count; 09019 w = start; 09020 } else { 09021 // output a partial line, trimming trailing whitespace 09022 if (s != start) { 09023 if (n >= pair_max) return -1; 09024 if (pairs) pairs[n] = start, pairs[n+1] = s-start; 09025 n += 2; 09026 start = w; 09027 } 09028 } 09029 // now output full lines as needed 09030 while (start + count <= i) { 09031 if (n >= pair_max) return -1; 09032 if (pairs) pairs[n] = start, pairs[n+1] = count; 09033 n += 2; 09034 start += count; 09035 } 09036 } 09037 } 09038 nonwhite=1; 09039 } 09040 if (start < i) { 09041 if (n >= pair_max) return -1; 09042 if (pairs) pairs[n] = start, pairs[n+1] = i-start; 09043 n += 2; 09044 } 09045 return n>>1; 09046 } 09047 09048 int *stb_wordwrapalloc(int count, char *str) 09049 { 09050 int n = stb_wordwrap(NULL,0,count,str); 09051 int *z = NULL; 09052 stb_arr_setlen(z, n*2); 09053 stb_wordwrap(z, n, count, str); 09054 return z; 09055 } 09056 #endif 09057 09058 09060 // 09061 // stb_match: wildcards and regexping 09062 // 09063 09064 STB_EXTERN int stb_wildmatch (char *expr, char *candidate); 09065 STB_EXTERN int stb_wildmatchi(char *expr, char *candidate); 09066 STB_EXTERN int stb_wildfind (char *expr, char *candidate); 09067 STB_EXTERN int stb_wildfindi (char *expr, char *candidate); 09068 09069 STB_EXTERN int stb_regex(char *regex, char *candidate); 09070 09071 typedef struct stb_matcher stb_matcher; 09072 09073 STB_EXTERN stb_matcher *stb_regex_matcher(char *regex); 09074 STB_EXTERN int stb_matcher_match(stb_matcher *m, char *str); 09075 STB_EXTERN int stb_matcher_find(stb_matcher *m, char *str); 09076 STB_EXTERN void stb_matcher_free(stb_matcher *f); 09077 09078 STB_EXTERN stb_matcher *stb_lex_matcher(void); 09079 STB_EXTERN int stb_lex_item(stb_matcher *m, const char *str, int result); 09080 STB_EXTERN int stb_lex_item_wild(stb_matcher *matcher, const char *regex, int result); 09081 STB_EXTERN int stb_lex(stb_matcher *m, char *str, int *len); 09082 09083 09084 09085 #ifdef STB_DEFINE 09086 09087 static int stb__match_qstring(char *candidate, char *qstring, int qlen, int insensitive) 09088 { 09089 int i; 09090 if (insensitive) { 09091 for (i=0; i < qlen; ++i) 09092 if (qstring[i] == '?') { 09093 if (!candidate[i]) return 0; 09094 } else 09095 if (tolower(qstring[i]) != tolower(candidate[i])) 09096 return 0; 09097 } else { 09098 for (i=0; i < qlen; ++i) 09099 if (qstring[i] == '?') { 09100 if (!candidate[i]) return 0; 09101 } else 09102 if (qstring[i] != candidate[i]) 09103 return 0; 09104 } 09105 return 1; 09106 } 09107 09108 static int stb__find_qstring(char *candidate, char *qstring, int qlen, int insensitive) 09109 { 09110 char c; 09111 09112 int offset=0; 09113 while (*qstring == '?') { 09114 ++qstring; 09115 --qlen; 09116 ++candidate; 09117 if (qlen == 0) return 0; 09118 if (*candidate == 0) return -1; 09119 } 09120 09121 c = *qstring++; 09122 --qlen; 09123 if (insensitive) c = tolower(c); 09124 09125 while (candidate[offset]) { 09126 if (c == (insensitive ? tolower(candidate[offset]) : candidate[offset])) 09127 if (stb__match_qstring(candidate+offset+1, qstring, qlen, insensitive)) 09128 return offset; 09129 ++offset; 09130 } 09131 09132 return -1; 09133 } 09134 09135 int stb__wildmatch_raw2(char *expr, char *candidate, int search, int insensitive) 09136 { 09137 int where=0; 09138 int start = -1; 09139 09140 if (!search) { 09141 // parse to first '*' 09142 if (*expr != '*') 09143 start = 0; 09144 while (*expr != '*') { 09145 if (!*expr) 09146 return *candidate == 0 ? 0 : -1; 09147 if (*expr == '?') { 09148 if (!*candidate) return -1; 09149 } else { 09150 if (insensitive) { 09151 if (tolower(*candidate) != tolower(*expr)) 09152 return -1; 09153 } else 09154 if (*candidate != *expr) 09155 return -1; 09156 } 09157 ++candidate, ++expr, ++where; 09158 } 09159 } else { 09160 // 0-length search string 09161 if (!*expr) 09162 return 0; 09163 } 09164 09165 assert(search || *expr == '*'); 09166 if (!search) 09167 ++expr; 09168 09169 // implicit '*' at this point 09170 09171 while (*expr) { 09172 int o=0; 09173 // combine redundant * characters 09174 while (expr[0] == '*') ++expr; 09175 09176 // ok, at this point, expr[-1] == '*', 09177 // and expr[0] != '*' 09178 09179 if (!expr[0]) return start >= 0 ? start : 0; 09180 09181 // now find next '*' 09182 o = 0; 09183 while (expr[o] != '*') { 09184 if (expr[o] == 0) 09185 break; 09186 ++o; 09187 } 09188 // if no '*', scan to end, then match at end 09189 if (expr[o] == 0 && !search) { 09190 int z; 09191 for (z=0; z < o; ++z) 09192 if (candidate[z] == 0) 09193 return -1; 09194 while (candidate[z]) 09195 ++z; 09196 // ok, now check if they match 09197 if (stb__match_qstring(candidate+z-o, expr, o, insensitive)) 09198 return start >= 0 ? start : 0; 09199 return -1; 09200 } else { 09201 // if yes '*', then do stb__find_qmatch on the intervening chars 09202 int n = stb__find_qstring(candidate, expr, o, insensitive); 09203 if (n < 0) 09204 return -1; 09205 if (start < 0) 09206 start = where + n; 09207 expr += o; 09208 candidate += n+o; 09209 } 09210 09211 if (*expr == 0) { 09212 assert(search); 09213 return start; 09214 } 09215 09216 assert(*expr == '*'); 09217 ++expr; 09218 } 09219 09220 return start >= 0 ? start : 0; 09221 } 09222 09223 int stb__wildmatch_raw(char *expr, char *candidate, int search, int insensitive) 09224 { 09225 char buffer[256]; 09226 // handle multiple search strings 09227 char *s = strchr(expr, ';'); 09228 char *last = expr; 09229 while (s) { 09230 int z; 09231 // need to allow for non-writeable strings... assume they're small 09232 if (s - last < 256) { 09233 stb_strncpy(buffer, last, (int) (s-last+1)); 09234 z = stb__wildmatch_raw2(buffer, candidate, search, insensitive); 09235 } else { 09236 *s = 0; 09237 z = stb__wildmatch_raw2(last, candidate, search, insensitive); 09238 *s = ';'; 09239 } 09240 if (z >= 0) return z; 09241 last = s+1; 09242 s = strchr(last, ';'); 09243 } 09244 return stb__wildmatch_raw2(last, candidate, search, insensitive); 09245 } 09246 09247 int stb_wildmatch(char *expr, char *candidate) 09248 { 09249 return stb__wildmatch_raw(expr, candidate, 0,0) >= 0; 09250 } 09251 09252 int stb_wildmatchi(char *expr, char *candidate) 09253 { 09254 return stb__wildmatch_raw(expr, candidate, 0,1) >= 0; 09255 } 09256 09257 int stb_wildfind(char *expr, char *candidate) 09258 { 09259 return stb__wildmatch_raw(expr, candidate, 1,0); 09260 } 09261 09262 int stb_wildfindi(char *expr, char *candidate) 09263 { 09264 return stb__wildmatch_raw(expr, candidate, 1,1); 09265 } 09266 09267 typedef struct 09268 { 09269 stb_int16 transition[256]; 09270 } stb_dfa; 09271 09272 // an NFA node represents a state you're in; it then has 09273 // an arbitrary number of edges dangling off of it 09274 // note this isn't utf8-y 09275 typedef struct 09276 { 09277 stb_int16 match; // character/set to match 09278 stb_uint16 node; // output node to go to 09279 } stb_nfa_edge; 09280 09281 typedef struct 09282 { 09283 stb_int16 goal; // does reaching this win the prize? 09284 stb_uint8 active; // is this in the active list 09285 stb_nfa_edge *out; 09286 stb_uint16 *eps; // list of epsilon closures 09287 } stb_nfa_node; 09288 09289 #define STB__DFA_UNDEF -1 09290 #define STB__DFA_GOAL -2 09291 #define STB__DFA_END -3 09292 #define STB__DFA_MGOAL -4 09293 #define STB__DFA_VALID 0 09294 09295 #define STB__NFA_STOP_GOAL -1 09296 09297 // compiled regexp 09298 struct stb_matcher 09299 { 09300 stb_uint16 start_node; 09301 stb_int16 dfa_start; 09302 stb_uint32 *charset; 09303 int num_charset; 09304 int match_start; 09305 stb_nfa_node *nodes; 09306 int does_lex; 09307 09308 // dfa matcher 09309 stb_dfa * dfa; 09310 stb_uint32 * dfa_mapping; 09311 stb_int16 * dfa_result; 09312 int num_words_per_dfa; 09313 }; 09314 09315 static int stb__add_node(stb_matcher *matcher) 09316 { 09317 stb_nfa_node z; 09318 z.active = 0; 09319 z.eps = 0; 09320 z.goal = 0; 09321 z.out = 0; 09322 stb_arr_push(matcher->nodes, z); 09323 return stb_arr_len(matcher->nodes)-1; 09324 } 09325 09326 static void stb__add_epsilon(stb_matcher *matcher, int from, int to) 09327 { 09328 assert(from != to); 09329 if (matcher->nodes[from].eps == NULL) 09330 stb_arr_malloc((void **) &matcher->nodes[from].eps, matcher); 09331 stb_arr_push(matcher->nodes[from].eps, to); 09332 } 09333 09334 static void stb__add_edge(stb_matcher *matcher, int from, int to, int type) 09335 { 09336 stb_nfa_edge z = { (stb_int16)type, (stb_uint16)to }; 09337 if (matcher->nodes[from].out == NULL) 09338 stb_arr_malloc((void **) &matcher->nodes[from].out, matcher); 09339 stb_arr_push(matcher->nodes[from].out, z); 09340 } 09341 09342 static char *stb__reg_parse_alt(stb_matcher *m, int s, char *r, stb_uint16 *e); 09343 static char *stb__reg_parse(stb_matcher *matcher, int start, char *regex, stb_uint16 *end) 09344 { 09345 int n; 09346 int last_start = -1; 09347 stb_uint16 last_end = start; 09348 09349 while (*regex) { 09350 switch (*regex) { 09351 case '(': 09352 last_start = last_end; 09353 regex = stb__reg_parse_alt(matcher, last_end, regex+1, &last_end); 09354 if (regex == NULL || *regex != ')') 09355 return NULL; 09356 ++regex; 09357 break; 09358 09359 case '|': 09360 case ')': 09361 *end = last_end; 09362 return regex; 09363 09364 case '?': 09365 if (last_start < 0) return NULL; 09366 stb__add_epsilon(matcher, last_start, last_end); 09367 ++regex; 09368 break; 09369 09370 case '*': 09371 if (last_start < 0) return NULL; 09372 stb__add_epsilon(matcher, last_start, last_end); 09373 09374 // fall through 09375 09376 case '+': 09377 if (last_start < 0) return NULL; 09378 stb__add_epsilon(matcher, last_end, last_start); 09379 // prevent links back to last_end from chaining to last_start 09380 n = stb__add_node(matcher); 09381 stb__add_epsilon(matcher, last_end, n); 09382 last_end = n; 09383 ++regex; 09384 break; 09385 09386 case '{': // not supported! 09387 // @TODO: given {n,m}, clone last_start to last_end m times, 09388 // and include epsilons from start to first m-n blocks 09389 return NULL; 09390 09391 case '\\': 09392 ++regex; 09393 if (!*regex) return NULL; 09394 09395 // fallthrough 09396 default: // match exactly this character 09397 n = stb__add_node(matcher); 09398 stb__add_edge(matcher, last_end, n, *regex); 09399 last_start = last_end; 09400 last_end = n; 09401 ++regex; 09402 break; 09403 09404 case '$': 09405 n = stb__add_node(matcher); 09406 stb__add_edge(matcher, last_end, n, '\n'); 09407 last_start = last_end; 09408 last_end = n; 09409 ++regex; 09410 break; 09411 09412 case '.': 09413 n = stb__add_node(matcher); 09414 stb__add_edge(matcher, last_end, n, -1); 09415 last_start = last_end; 09416 last_end = n; 09417 ++regex; 09418 break; 09419 09420 case '[': { 09421 stb_uint8 flags[256]; 09422 int invert = 0,z; 09423 ++regex; 09424 if (matcher->num_charset == 0) { 09425 matcher->charset = (stb_uint *) stb_malloc(matcher, sizeof(*matcher->charset) * 256); 09426 memset(matcher->charset, 0, sizeof(*matcher->charset) * 256); 09427 } 09428 09429 memset(flags,0,sizeof(flags)); 09430 09431 // leading ^ is special 09432 if (*regex == '^') 09433 ++regex, invert = 1; 09434 09435 // leading ] is special 09436 if (*regex == ']') { 09437 flags[(int) ']'] = 1; 09438 ++regex; 09439 } 09440 while (*regex != ']') { 09441 stb_uint a; 09442 if (!*regex) return NULL; 09443 a = *regex++; 09444 if (regex[0] == '-' && regex[1] != ']') { 09445 stb_uint i,b = regex[1]; 09446 regex += 2; 09447 if (b == 0) return NULL; 09448 if (a > b) return NULL; 09449 for (i=a; i <= b; ++i) 09450 flags[i] = 1; 09451 } else 09452 flags[a] = 1; 09453 } 09454 ++regex; 09455 if (invert) { 09456 int i; 09457 for (i=0; i < 256; ++i) 09458 flags[i] = 1-flags[i]; 09459 } 09460 09461 // now check if any existing charset matches 09462 for (z=0; z < matcher->num_charset; ++z) { 09463 int i, k[2] = { 0, 1 << z}; 09464 for (i=0; i < 256; ++i) { 09465 unsigned int f = k[flags[i]]; 09466 if ((matcher->charset[i] & k[1]) != f) 09467 break; 09468 } 09469 if (i == 256) break; 09470 } 09471 09472 if (z == matcher->num_charset) { 09473 int i; 09474 ++matcher->num_charset; 09475 if (matcher->num_charset > 32) { 09476 assert(0); /* NOTREACHED */ 09477 return NULL; // too many charsets, oops 09478 } 09479 for (i=0; i < 256; ++i) 09480 if (flags[i]) 09481 matcher->charset[i] |= (1 << z); 09482 } 09483 09484 n = stb__add_node(matcher); 09485 stb__add_edge(matcher, last_end, n, -2 - z); 09486 last_start = last_end; 09487 last_end = n; 09488 break; 09489 } 09490 } 09491 } 09492 *end = last_end; 09493 return regex; 09494 } 09495 09496 static char *stb__reg_parse_alt(stb_matcher *matcher, int start, char *regex, stb_uint16 *end) 09497 { 09498 stb_uint16 last_end = start; 09499 stb_uint16 main_end; 09500 09501 int head, tail; 09502 09503 head = stb__add_node(matcher); 09504 stb__add_epsilon(matcher, start, head); 09505 09506 regex = stb__reg_parse(matcher, head, regex, &last_end); 09507 if (regex == NULL) return NULL; 09508 if (*regex == 0 || *regex == ')') { 09509 *end = last_end; 09510 return regex; 09511 } 09512 09513 main_end = last_end; 09514 tail = stb__add_node(matcher); 09515 09516 stb__add_epsilon(matcher, last_end, tail); 09517 09518 // start alternatives from the same starting node; use epsilon 09519 // transitions to combine their endings 09520 while(*regex && *regex != ')') { 09521 assert(*regex == '|'); 09522 head = stb__add_node(matcher); 09523 stb__add_epsilon(matcher, start, head); 09524 regex = stb__reg_parse(matcher, head, regex+1, &last_end); 09525 if (regex == NULL) 09526 return NULL; 09527 stb__add_epsilon(matcher, last_end, tail); 09528 } 09529 09530 *end = tail; 09531 return regex; 09532 } 09533 09534 static char *stb__wild_parse(stb_matcher *matcher, int start, char *str, stb_uint16 *end) 09535 { 09536 int n; 09537 stb_uint16 last_end; 09538 09539 last_end = stb__add_node(matcher); 09540 stb__add_epsilon(matcher, start, last_end); 09541 09542 while (*str) { 09543 switch (*str) { 09544 // fallthrough 09545 default: // match exactly this character 09546 n = stb__add_node(matcher); 09547 if (toupper(*str) == tolower(*str)) { 09548 stb__add_edge(matcher, last_end, n, *str); 09549 } else { 09550 stb__add_edge(matcher, last_end, n, tolower(*str)); 09551 stb__add_edge(matcher, last_end, n, toupper(*str)); 09552 } 09553 last_end = n; 09554 ++str; 09555 break; 09556 09557 case '?': 09558 n = stb__add_node(matcher); 09559 stb__add_edge(matcher, last_end, n, -1); 09560 last_end = n; 09561 ++str; 09562 break; 09563 09564 case '*': 09565 n = stb__add_node(matcher); 09566 stb__add_edge(matcher, last_end, n, -1); 09567 stb__add_epsilon(matcher, last_end, n); 09568 stb__add_epsilon(matcher, n, last_end); 09569 last_end = n; 09570 ++str; 09571 break; 09572 } 09573 } 09574 09575 // now require end of string to match 09576 n = stb__add_node(matcher); 09577 stb__add_edge(matcher, last_end, n, 0); 09578 last_end = n; 09579 09580 *end = last_end; 09581 return str; 09582 } 09583 09584 static int stb__opt(stb_matcher *m, int n) 09585 { 09586 for(;;) { 09587 stb_nfa_node *p = &m->nodes[n]; 09588 if (p->goal) return n; 09589 if (stb_arr_len(p->out)) return n; 09590 if (stb_arr_len(p->eps) != 1) return n; 09591 n = p->eps[0]; 09592 } 09593 } 09594 09595 static void stb__optimize(stb_matcher *m) 09596 { 09597 // if the target of any edge is a node with exactly 09598 // one out-epsilon, shorten it 09599 int i,j; 09600 for (i=0; i < stb_arr_len(m->nodes); ++i) { 09601 stb_nfa_node *p = &m->nodes[i]; 09602 for (j=0; j < stb_arr_len(p->out); ++j) 09603 p->out[j].node = stb__opt(m,p->out[j].node); 09604 for (j=0; j < stb_arr_len(p->eps); ++j) 09605 p->eps[j] = stb__opt(m,p->eps[j] ); 09606 } 09607 m->start_node = stb__opt(m,m->start_node); 09608 } 09609 09610 void stb_matcher_free(stb_matcher *f) 09611 { 09612 stb_free(f); 09613 } 09614 09615 static stb_matcher *stb__alloc_matcher(void) 09616 { 09617 stb_matcher *matcher = (stb_matcher *) stb_malloc(0,sizeof(*matcher)); 09618 09619 matcher->start_node = 0; 09620 stb_arr_malloc((void **) &matcher->nodes, matcher); 09621 matcher->num_charset = 0; 09622 matcher->match_start = 0; 09623 matcher->does_lex = 0; 09624 09625 matcher->dfa_start = STB__DFA_UNDEF; 09626 stb_arr_malloc((void **) &matcher->dfa, matcher); 09627 stb_arr_malloc((void **) &matcher->dfa_mapping, matcher); 09628 stb_arr_malloc((void **) &matcher->dfa_result, matcher); 09629 09630 stb__add_node(matcher); 09631 09632 return matcher; 09633 } 09634 09635 static void stb__lex_reset(stb_matcher *matcher) 09636 { 09637 // flush cached dfa data 09638 stb_arr_setlen(matcher->dfa, 0); 09639 stb_arr_setlen(matcher->dfa_mapping, 0); 09640 stb_arr_setlen(matcher->dfa_result, 0); 09641 matcher->dfa_start = STB__DFA_UNDEF; 09642 } 09643 09644 stb_matcher *stb_regex_matcher(char *regex) 09645 { 09646 char *z; 09647 stb_uint16 end; 09648 stb_matcher *matcher = stb__alloc_matcher(); 09649 if (*regex == '^') { 09650 matcher->match_start = 1; 09651 ++regex; 09652 } 09653 09654 z = stb__reg_parse_alt(matcher, matcher->start_node, regex, &end); 09655 09656 if (!z || *z) { 09657 stb_free(matcher); 09658 return NULL; 09659 } 09660 09661 ((matcher->nodes)[(int) end]).goal = STB__NFA_STOP_GOAL; 09662 09663 return matcher; 09664 } 09665 09666 stb_matcher *stb_lex_matcher(void) 09667 { 09668 stb_matcher *matcher = stb__alloc_matcher(); 09669 09670 matcher->match_start = 1; 09671 matcher->does_lex = 1; 09672 09673 return matcher; 09674 } 09675 09676 int stb_lex_item(stb_matcher *matcher, const char *regex, int result) 09677 { 09678 char *z; 09679 stb_uint16 end; 09680 09681 z = stb__reg_parse_alt(matcher, matcher->start_node, (char*) regex, &end); 09682 09683 if (z == NULL) 09684 return 0; 09685 09686 stb__lex_reset(matcher); 09687 09688 matcher->nodes[(int) end].goal = result; 09689 return 1; 09690 } 09691 09692 int stb_lex_item_wild(stb_matcher *matcher, const char *regex, int result) 09693 { 09694 char *z; 09695 stb_uint16 end; 09696 09697 z = stb__wild_parse(matcher, matcher->start_node, (char*) regex, &end); 09698 09699 if (z == NULL) 09700 return 0; 09701 09702 stb__lex_reset(matcher); 09703 09704 matcher->nodes[(int) end].goal = result; 09705 return 1; 09706 } 09707 09708 static void stb__clear(stb_matcher *m, stb_uint16 *list) 09709 { 09710 int i; 09711 for (i=0; i < stb_arr_len(list); ++i) 09712 m->nodes[(int) list[i]].active = 0; 09713 } 09714 09715 static int stb__clear_goalcheck(stb_matcher *m, stb_uint16 *list) 09716 { 09717 int i, t=0; 09718 for (i=0; i < stb_arr_len(list); ++i) { 09719 t += m->nodes[(int) list[i]].goal; 09720 m->nodes[(int) list[i]].active = 0; 09721 } 09722 return t; 09723 } 09724 09725 static stb_uint16 * stb__add_if_inactive(stb_matcher *m, stb_uint16 *list, int n) 09726 { 09727 if (!m->nodes[n].active) { 09728 stb_arr_push(list, n); 09729 m->nodes[n].active = 1; 09730 } 09731 return list; 09732 } 09733 09734 static stb_uint16 * stb__eps_closure(stb_matcher *m, stb_uint16 *list) 09735 { 09736 int i,n = stb_arr_len(list); 09737 09738 for(i=0; i < n; ++i) { 09739 stb_uint16 *e = m->nodes[(int) list[i]].eps; 09740 if (e) { 09741 int j,k = stb_arr_len(e); 09742 for (j=0; j < k; ++j) 09743 list = stb__add_if_inactive(m, list, e[j]); 09744 n = stb_arr_len(list); 09745 } 09746 } 09747 09748 return list; 09749 } 09750 09751 int stb_matcher_match(stb_matcher *m, char *str) 09752 { 09753 int result = 0; 09754 int i,j,y,z; 09755 stb_uint16 *previous = NULL; 09756 stb_uint16 *current = NULL; 09757 stb_uint16 *temp; 09758 09759 stb_arr_setsize(previous, 4); 09760 stb_arr_setsize(current, 4); 09761 09762 previous = stb__add_if_inactive(m, previous, m->start_node); 09763 previous = stb__eps_closure(m,previous); 09764 stb__clear(m, previous); 09765 09766 while (*str && stb_arr_len(previous)) { 09767 y = stb_arr_len(previous); 09768 for (i=0; i < y; ++i) { 09769 stb_nfa_node *n = &m->nodes[(int) previous[i]]; 09770 z = stb_arr_len(n->out); 09771 for (j=0; j < z; ++j) { 09772 if (n->out[j].match >= 0) { 09773 if (n->out[j].match == *str) 09774 current = stb__add_if_inactive(m, current, n->out[j].node); 09775 } else if (n->out[j].match == -1) { 09776 if (*str != '\n') 09777 current = stb__add_if_inactive(m, current, n->out[j].node); 09778 } else if (n->out[j].match < -1) { 09779 int z = -n->out[j].match - 2; 09780 if (m->charset[(stb_uint8) *str] & (1 << z)) 09781 current = stb__add_if_inactive(m, current, n->out[j].node); 09782 } 09783 } 09784 } 09785 stb_arr_setlen(previous, 0); 09786 09787 temp = previous; 09788 previous = current; 09789 current = temp; 09790 09791 previous = stb__eps_closure(m,previous); 09792 stb__clear(m, previous); 09793 09794 ++str; 09795 } 09796 09797 // transition to pick up a '$' at the end 09798 y = stb_arr_len(previous); 09799 for (i=0; i < y; ++i) 09800 m->nodes[(int) previous[i]].active = 1; 09801 09802 for (i=0; i < y; ++i) { 09803 stb_nfa_node *n = &m->nodes[(int) previous[i]]; 09804 z = stb_arr_len(n->out); 09805 for (j=0; j < z; ++j) { 09806 if (n->out[j].match == '\n') 09807 current = stb__add_if_inactive(m, current, n->out[j].node); 09808 } 09809 } 09810 09811 previous = stb__eps_closure(m,previous); 09812 stb__clear(m, previous); 09813 09814 y = stb_arr_len(previous); 09815 for (i=0; i < y; ++i) 09816 if (m->nodes[(int) previous[i]].goal) 09817 result = 1; 09818 09819 stb_arr_free(previous); 09820 stb_arr_free(current); 09821 09822 return result && *str == 0; 09823 } 09824 09825 stb_int16 stb__get_dfa_node(stb_matcher *m, stb_uint16 *list) 09826 { 09827 stb_uint16 node; 09828 stb_uint32 data[8], *state, *newstate; 09829 int i,j,n; 09830 09831 state = (stb_uint32 *) stb_temp(data, m->num_words_per_dfa * 4); 09832 memset(state, 0, m->num_words_per_dfa*4); 09833 09834 n = stb_arr_len(list); 09835 for (i=0; i < n; ++i) { 09836 int x = list[i]; 09837 state[x >> 5] |= 1 << (x & 31); 09838 } 09839 09840 // @TODO use a hash table 09841 n = stb_arr_len(m->dfa_mapping); 09842 i=j=0; 09843 for(; j < n; ++i, j += m->num_words_per_dfa) { 09844 // @TODO special case for <= 32 09845 if (!memcmp(state, m->dfa_mapping + j, m->num_words_per_dfa*4)) { 09846 node = i; 09847 goto done; 09848 } 09849 } 09850 09851 assert(stb_arr_len(m->dfa) == i); 09852 node = i; 09853 09854 newstate = stb_arr_addn(m->dfa_mapping, m->num_words_per_dfa); 09855 memcpy(newstate, state, m->num_words_per_dfa*4); 09856 09857 // set all transitions to 'unknown' 09858 stb_arr_add(m->dfa); 09859 memset(m->dfa[i].transition, -1, sizeof(m->dfa[i].transition)); 09860 09861 if (m->does_lex) { 09862 int result = -1; 09863 n = stb_arr_len(list); 09864 for (i=0; i < n; ++i) { 09865 if (m->nodes[(int) list[i]].goal > result) 09866 result = m->nodes[(int) list[i]].goal; 09867 } 09868 09869 stb_arr_push(m->dfa_result, result); 09870 } 09871 09872 done: 09873 stb_tempfree(data, state); 09874 return node; 09875 } 09876 09877 static int stb__matcher_dfa(stb_matcher *m, char *str_c, int *len) 09878 { 09879 stb_uint8 *str = (stb_uint8 *) str_c; 09880 stb_int16 node,prevnode; 09881 stb_dfa *trans; 09882 int match_length = 0; 09883 stb_int16 match_result=0; 09884 09885 if (m->dfa_start == STB__DFA_UNDEF) { 09886 stb_uint16 *list; 09887 09888 m->num_words_per_dfa = (stb_arr_len(m->nodes)+31) >> 5; 09889 stb__optimize(m); 09890 09891 list = stb__add_if_inactive(m, NULL, m->start_node); 09892 list = stb__eps_closure(m,list); 09893 if (m->does_lex) { 09894 m->dfa_start = stb__get_dfa_node(m,list); 09895 stb__clear(m, list); 09896 // DON'T allow start state to be a goal state! 09897 // this allows people to specify regexes that can match 0 09898 // characters without them actually matching (also we don't 09899 // check _before_ advancing anyway 09900 if (m->dfa_start <= STB__DFA_MGOAL) 09901 m->dfa_start = -(m->dfa_start - STB__DFA_MGOAL); 09902 } else { 09903 if (stb__clear_goalcheck(m, list)) 09904 m->dfa_start = STB__DFA_GOAL; 09905 else 09906 m->dfa_start = stb__get_dfa_node(m,list); 09907 } 09908 stb_arr_free(list); 09909 } 09910 09911 prevnode = STB__DFA_UNDEF; 09912 node = m->dfa_start; 09913 trans = m->dfa; 09914 09915 if (m->dfa_start == STB__DFA_GOAL) 09916 return 1; 09917 09918 for(;;) { 09919 assert(node >= STB__DFA_VALID); 09920 09921 // fast inner DFA loop; especially if STB__DFA_VALID is 0 09922 09923 do { 09924 prevnode = node; 09925 node = trans[node].transition[*str++]; 09926 } while (node >= STB__DFA_VALID); 09927 09928 assert(node >= STB__DFA_MGOAL - stb_arr_len(m->dfa)); 09929 assert(node < stb_arr_len(m->dfa)); 09930 09931 // special case for lex: need _longest_ match, so notice goal 09932 // state without stopping 09933 if (node <= STB__DFA_MGOAL) { 09934 match_length = (int) (str - (stb_uint8 *) str_c); 09935 node = -(node - STB__DFA_MGOAL); 09936 match_result = node; 09937 continue; 09938 } 09939 09940 // slow NFA->DFA conversion 09941 09942 // or we hit the goal or the end of the string, but those 09943 // can only happen once per search... 09944 09945 if (node == STB__DFA_UNDEF) { 09946 // build a list -- @TODO special case <= 32 states 09947 // heck, use a more compact data structure for <= 16 and <= 8 ?! 09948 09949 // @TODO keep states/newstates around instead of reallocating them 09950 stb_uint16 *states = NULL; 09951 stb_uint16 *newstates = NULL; 09952 int i,j,y,z; 09953 stb_uint32 *flags = &m->dfa_mapping[prevnode * m->num_words_per_dfa]; 09954 assert(prevnode != STB__DFA_UNDEF); 09955 stb_arr_setsize(states, 4); 09956 stb_arr_setsize(newstates,4); 09957 for (j=0; j < m->num_words_per_dfa; ++j) { 09958 for (i=0; i < 32; ++i) { 09959 if (*flags & (1 << i)) 09960 stb_arr_push(states, j*32+i); 09961 } 09962 ++flags; 09963 } 09964 // states is now the states we were in in the previous node; 09965 // so now we can compute what node it transitions to on str[-1] 09966 09967 y = stb_arr_len(states); 09968 for (i=0; i < y; ++i) { 09969 stb_nfa_node *n = &m->nodes[(int) states[i]]; 09970 z = stb_arr_len(n->out); 09971 for (j=0; j < z; ++j) { 09972 if (n->out[j].match >= 0) { 09973 if (n->out[j].match == str[-1] || (str[-1] == 0 && n->out[j].match == '\n')) 09974 newstates = stb__add_if_inactive(m, newstates, n->out[j].node); 09975 } else if (n->out[j].match == -1) { 09976 if (str[-1] != '\n' && str[-1]) 09977 newstates = stb__add_if_inactive(m, newstates, n->out[j].node); 09978 } else if (n->out[j].match < -1) { 09979 int z = -n->out[j].match - 2; 09980 if (m->charset[str[-1]] & (1 << z)) 09981 newstates = stb__add_if_inactive(m, newstates, n->out[j].node); 09982 } 09983 } 09984 } 09985 // AND add in the start state! 09986 if (!m->match_start || (str[-1] == '\n' && !m->does_lex)) 09987 newstates = stb__add_if_inactive(m, newstates, m->start_node); 09988 // AND epsilon close it 09989 newstates = stb__eps_closure(m, newstates); 09990 // if it's a goal state, then that's all there is to it 09991 if (stb__clear_goalcheck(m, newstates)) { 09992 if (m->does_lex) { 09993 match_length = (int) (str - (stb_uint8 *) str_c); 09994 node = stb__get_dfa_node(m,newstates); 09995 match_result = node; 09996 node = -node + STB__DFA_MGOAL; 09997 trans = m->dfa; // could have gotten realloc()ed 09998 } else 09999 node = STB__DFA_GOAL; 10000 } else if (str[-1] == 0 || stb_arr_len(newstates) == 0) { 10001 node = STB__DFA_END; 10002 } else { 10003 node = stb__get_dfa_node(m,newstates); 10004 trans = m->dfa; // could have gotten realloc()ed 10005 } 10006 trans[prevnode].transition[str[-1]] = node; 10007 if (node <= STB__DFA_MGOAL) 10008 node = -(node - STB__DFA_MGOAL); 10009 stb_arr_free(newstates); 10010 stb_arr_free(states); 10011 } 10012 10013 if (node == STB__DFA_GOAL) { 10014 return 1; 10015 } 10016 if (node == STB__DFA_END) { 10017 if (m->does_lex) { 10018 if (match_result) { 10019 if (len) *len = match_length; 10020 return m->dfa_result[(int) match_result]; 10021 } 10022 } 10023 return 0; 10024 } 10025 10026 assert(node != STB__DFA_UNDEF); 10027 } 10028 } 10029 10030 int stb_matcher_find(stb_matcher *m, char *str) 10031 { 10032 assert(m->does_lex == 0); 10033 return stb__matcher_dfa(m, str, NULL); 10034 } 10035 10036 int stb_lex(stb_matcher *m, char *str, int *len) 10037 { 10038 assert(m->does_lex); 10039 return stb__matcher_dfa(m, str, len); 10040 } 10041 10042 #ifdef STB_PERFECT_HASH 10043 int stb_regex(char *regex, char *str) 10044 { 10045 static stb_perfect p; 10046 static stb_matcher ** matchers; 10047 static char ** regexps; 10048 static char ** regexp_cache; 10049 static unsigned short *mapping; 10050 int z = stb_perfect_hash(&p, (int)(size_t) regex); 10051 if (z >= 0) { 10052 if (strcmp(regex, regexp_cache[(int) mapping[z]])) { 10053 int i = mapping[z]; 10054 stb_matcher_free(matchers[i]); 10055 free(regexp_cache[i]); 10056 regexps[i] = regex; 10057 regexp_cache[i] = stb_p_strdup(regex); 10058 matchers[i] = stb_regex_matcher(regex); 10059 } 10060 } else { 10061 int i,n; 10062 if (regex == NULL) { 10063 for (i=0; i < stb_arr_len(matchers); ++i) { 10064 stb_matcher_free(matchers[i]); 10065 free(regexp_cache[i]); 10066 } 10067 stb_arr_free(matchers); 10068 stb_arr_free(regexps); 10069 stb_arr_free(regexp_cache); 10070 stb_perfect_destroy(&p); 10071 free(mapping); mapping = NULL; 10072 return -1; 10073 } 10074 stb_arr_push(regexps, regex); 10075 stb_arr_push(regexp_cache, stb_p_strdup(regex)); 10076 stb_arr_push(matchers, stb_regex_matcher(regex)); 10077 stb_perfect_destroy(&p); 10078 n = stb_perfect_create(&p, (unsigned int *) (char **) regexps, stb_arr_len(regexps)); 10079 mapping = (unsigned short *) realloc(mapping, n * sizeof(*mapping)); 10080 for (i=0; i < stb_arr_len(regexps); ++i) 10081 mapping[stb_perfect_hash(&p, (int)(size_t) regexps[i])] = i; 10082 z = stb_perfect_hash(&p, (int)(size_t) regex); 10083 } 10084 return stb_matcher_find(matchers[(int) mapping[z]], str); 10085 } 10086 #endif 10087 #endif // STB_DEFINE 10088 10089 10090 #if 0 10091 10092 // 10093 // C source-code introspection 10094 // 10095 10096 // runtime structure 10097 typedef struct 10098 { 10099 char *name; 10100 char *type; // base type 10101 char *comment; // content of comment field 10102 int size; // size of base type 10103 int offset; // field offset 10104 int arrcount[8]; // array sizes; -1 = pointer indirection; 0 = end of list 10105 } stb_info_field; 10106 10107 typedef struct 10108 { 10109 char *structname; 10110 int size; 10111 int num_fields; 10112 stb_info_field *fields; 10113 } stb_info_struct; 10114 10115 extern stb_info_struct stb_introspect_output[]; 10116 10117 // 10118 10119 STB_EXTERN void stb_introspect_precompiled(stb_info_struct *compiled); 10120 STB_EXTERN void stb__introspect(char *path, char *file); 10121 10122 #define stb_introspect_ship() stb__introspect(NULL, NULL, stb__introspect_output) 10123 10124 #ifdef STB_SHIP 10125 #define stb_introspect() stb_introspect_ship() 10126 #define stb_introspect_path(p) stb_introspect_ship() 10127 #else 10128 // bootstrapping: define stb_introspect() (or 'path') the first time 10129 #define stb_introspect() stb__introspect(NULL, __FILE__, NULL) 10130 #define stb_introspect_auto() stb__introspect(NULL, __FILE__, stb__introspect_output) 10131 10132 #define stb_introspect_path(p) stb__introspect(p, __FILE__, NULL) 10133 #define stb_introspect_path(p) stb__introspect(p, __FILE__, NULL) 10134 #endif 10135 10136 #ifdef STB_DEFINE 10137 10138 #ifndef STB_INTROSPECT_CPP 10139 #ifdef __cplusplus 10140 #define STB_INTROSPECT_CPP 1 10141 #else 10142 #define STB_INTROSPECT_CPP 0 10143 #endif 10144 #endif 10145 10146 void stb_introspect_precompiled(stb_info_struct *compiled) 10147 { 10148 10149 } 10150 10151 10152 static void stb__introspect_filename(char *buffer, char *path) 10153 { 10154 #if STB_INTROSPECT_CPP 10155 stb_p_sprintf(buffer stb_p_size(9999), "%s/stb_introspect.cpp", path); 10156 #else 10157 stb_p_sprintf(buffer stb_p_size(9999), "%s/stb_introspect.c", path); 10158 #endif 10159 } 10160 10161 static void stb__introspect_compute(char *path, char *file) 10162 { 10163 int i; 10164 char ** include_list = NULL; 10165 char ** introspect_list = NULL; 10166 FILE *f; 10167 f = stb_p_fopen(file, "w"); 10168 if (!f) return; 10169 10170 fputs("// if you get compiler errors, change the following 0 to a 1:\n", f); 10171 fputs("#define STB_INTROSPECT_INVALID 0\n\n", f); 10172 fputs("// this will force the code to compile, and force the introspector\n", f); 10173 fputs("// to run and then exit, allowing you to recompile\n\n\n", f); 10174 fputs("#include \"stb.h\"\n\n",f ); 10175 fputs("#if STB_INTROSPECT_INVALID\n", f); 10176 fputs(" stb_info_struct stb__introspect_output[] = { (void *) 1 }\n", f); 10177 fputs("#else\n\n", f); 10178 for (i=0; i < stb_arr_len(include_list); ++i) 10179 fprintf(f, " #include \"%s\"\n", include_list[i]); 10180 10181 fputs(" stb_info_struct stb__introspect_output[] =\n{\n", f); 10182 for (i=0; i < stb_arr_len(introspect_list); ++i) 10183 fprintf(f, " stb_introspect_%s,\n", introspect_list[i]); 10184 fputs(" };\n", f); 10185 fputs("#endif\n", f); 10186 fclose(f); 10187 } 10188 10189 static stb_info_struct *stb__introspect_info; 10190 10191 #ifndef STB_SHIP 10192 10193 #endif 10194 10195 void stb__introspect(char *path, char *file, stb_info_struct *compiled) 10196 { 10197 static int first=1; 10198 if (!first) return; 10199 first=0; 10200 10201 stb__introspect_info = compiled; 10202 10203 #ifndef STB_SHIP 10204 if (path || file) { 10205 int bail_flag = compiled && compiled[0].structname == (void *) 1; 10206 int needs_building = bail_flag; 10207 struct stb__stat st; 10208 char buffer[1024], buffer2[1024]; 10209 if (!path) { 10210 stb_splitpath(buffer, file, STB_PATH); 10211 path = buffer; 10212 } 10213 // bail if the source path doesn't exist 10214 if (!stb_fexists(path)) return; 10215 10216 stb__introspect_filename(buffer2, path); 10217 10218 // get source/include files timestamps, compare to output-file timestamp; 10219 // if mismatched, regenerate 10220 10221 if (stb__stat(buffer2, &st)) 10222 needs_building = STB_TRUE; 10223 10224 { 10225 // find any file that contains an introspection command and is newer 10226 // if needs_building is already true, we don't need to do this test, 10227 // but we still need these arrays, so go ahead and get them 10228 char **all[3]; 10229 all[0] = stb_readdir_files_mask(path, "*.h"); 10230 all[1] = stb_readdir_files_mask(path, "*.c"); 10231 all[2] = stb_readdir_files_mask(path, "*.cpp"); 10232 int i,j; 10233 if (needs_building) { 10234 for (j=0; j < 3; ++j) { 10235 for (i=0; i < stb_arr_len(all[j]); ++i) { 10236 struct stb__stat st2; 10237 if (!stb__stat(all[j][i], &st2)) { 10238 if (st.st_mtime < st2.st_mtime) { 10239 char *z = stb_filec(all[j][i], NULL); 10240 int found=STB_FALSE; 10241 while (y) { 10242 y = strstr(y, "//si"); 10243 if (y && isspace(y[4])) { 10244 found = STB_TRUE; 10245 break; 10246 } 10247 } 10248 needs_building = STB_TRUE; 10249 goto done; 10250 } 10251 } 10252 } 10253 } 10254 done:; 10255 } 10256 char *z = stb_filec(all[i], NULL), *y = z; 10257 int found=STB_FALSE; 10258 while (y) { 10259 y = strstr(y, "//si"); 10260 if (y && isspace(y[4])) { 10261 found = STB_TRUE; 10262 break; 10263 } 10264 } 10265 if (found) 10266 stb_arr_push(introspect_h, stb_p_strdup(all[i])); 10267 free(z); 10268 } 10269 } 10270 stb_readdir_free(all); 10271 if (!needs_building) { 10272 for (i=0; i < stb_arr_len(introspect_h); ++i) { 10273 struct stb__stat st2; 10274 if (!stb__stat(introspect_h[i], &st2)) 10275 if (st.st_mtime < st2.st_mtime) 10276 needs_building = STB_TRUE; 10277 } 10278 } 10279 10280 if (needs_building) { 10281 stb__introspect_compute(path, buffer2); 10282 } 10283 } 10284 } 10285 #endif 10286 } 10287 #endif 10288 #endif 10289 10290 #ifdef STB_INTROSPECT 10291 // compile-time code-generator 10292 #define INTROSPECT(x) int main(int argc, char **argv) { stb__introspect(__FILE__); return 0; } 10293 #define FILE(x) 10294 10295 void stb__introspect(char *filename) 10296 { 10297 char *file = stb_file(filename, NULL); 10298 char *s = file, *t, **p; 10299 char *out_name = "stb_introspect.c"; 10300 char *out_path; 10301 STB_ARR(char) filelist = NULL; 10302 int i,n; 10303 if (!file) stb_fatal("Couldn't open %s", filename); 10304 10305 out_path = stb_splitpathdup(filename, STB_PATH); 10306 10307 // search for the macros 10308 while (*s) { 10309 char buffer[256]; 10310 while (*s && !isupper(*s)) ++s; 10311 s = stb_strtok_invert(buffer, s, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); 10312 s = stb_skipwhite(s); 10313 if (*s == '(') { 10314 ++s; 10315 t = strchr(s, ')'); 10316 if (t == NULL) stb_fatal("Error parsing %s", filename); 10317 10318 } 10319 } 10320 } 10321 10322 10323 10324 #endif 10325 10326 10328 // 10329 // STB-C sliding-window dictionary compression 10330 // 10331 // This uses a DEFLATE-style sliding window, but no bitwise entropy. 10332 // Everything is on byte boundaries, so you could then apply a byte-wise 10333 // entropy code, though that's nowhere near as effective. 10334 // 10335 // An STB-C stream begins with a 16-byte header: 10336 // 4 bytes: 0x57 0xBC 0x00 0x00 10337 // 8 bytes: big-endian size of decompressed data, 64-bits 10338 // 4 bytes: big-endian size of window (how far back decompressor may need) 10339 // 10340 // The following symbols appear in the stream (these were determined ad hoc, 10341 // not by analysis): 10342 // 10343 // [dict] 00000100 yyyyyyyy yyyyyyyy yyyyyyyy xxxxxxxx xxxxxxxx 10344 // [END] 00000101 11111010 cccccccc cccccccc cccccccc cccccccc 10345 // [dict] 00000110 yyyyyyyy yyyyyyyy yyyyyyyy xxxxxxxx 10346 // [literals] 00000111 zzzzzzzz zzzzzzzz 10347 // [literals] 00001zzz zzzzzzzz 10348 // [dict] 00010yyy yyyyyyyy yyyyyyyy xxxxxxxx xxxxxxxx 10349 // [dict] 00011yyy yyyyyyyy yyyyyyyy xxxxxxxx 10350 // [literals] 001zzzzz 10351 // [dict] 01yyyyyy yyyyyyyy xxxxxxxx 10352 // [dict] 1xxxxxxx yyyyyyyy 10353 // 10354 // xxxxxxxx: match length - 1 10355 // yyyyyyyy: backwards distance - 1 10356 // zzzzzzzz: num literals - 1 10357 // cccccccc: adler32 checksum of decompressed data 10358 // (all big-endian) 10359 10360 10361 STB_EXTERN stb_uint stb_decompress_length(stb_uchar *input); 10362 STB_EXTERN stb_uint stb_decompress(stb_uchar *out,stb_uchar *in,stb_uint len); 10363 STB_EXTERN stb_uint stb_compress (stb_uchar *out,stb_uchar *in,stb_uint len); 10364 STB_EXTERN void stb_compress_window(int z); 10365 STB_EXTERN void stb_compress_hashsize(unsigned int z); 10366 10367 STB_EXTERN int stb_compress_tofile(char *filename, char *in, stb_uint len); 10368 STB_EXTERN int stb_compress_intofile(FILE *f, char *input, stb_uint len); 10369 STB_EXTERN char *stb_decompress_fromfile(char *filename, stb_uint *len); 10370 10371 STB_EXTERN int stb_compress_stream_start(FILE *f); 10372 STB_EXTERN void stb_compress_stream_end(int close); 10373 STB_EXTERN void stb_write(char *data, int data_len); 10374 10375 #ifdef STB_DEFINE 10376 10377 stb_uint stb_decompress_length(stb_uchar *input) 10378 { 10379 return (input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11]; 10380 } 10381 10383 10384 // simple implementation that just writes whole thing into big block 10385 10386 static unsigned char *stb__barrier; 10387 static unsigned char *stb__barrier2; 10388 static unsigned char *stb__barrier3; 10389 static unsigned char *stb__barrier4; 10390 10391 static stb_uchar *stb__dout; 10392 static void stb__match(stb_uchar *data, stb_uint length) 10393 { 10394 // INVERSE of memmove... write each byte before copying the next... 10395 assert (stb__dout + length <= stb__barrier); 10396 if (stb__dout + length > stb__barrier) { stb__dout += length; return; } 10397 if (data < stb__barrier4) { stb__dout = stb__barrier+1; return; } 10398 while (length--) *stb__dout++ = *data++; 10399 } 10400 10401 static void stb__lit(stb_uchar *data, stb_uint length) 10402 { 10403 assert (stb__dout + length <= stb__barrier); 10404 if (stb__dout + length > stb__barrier) { stb__dout += length; return; } 10405 if (data < stb__barrier2) { stb__dout = stb__barrier+1; return; } 10406 memcpy(stb__dout, data, length); 10407 stb__dout += length; 10408 } 10409 10410 #define stb__in2(x) ((i[x] << 8) + i[(x)+1]) 10411 #define stb__in3(x) ((i[x] << 16) + stb__in2((x)+1)) 10412 #define stb__in4(x) ((i[x] << 24) + stb__in3((x)+1)) 10413 10414 static stb_uchar *stb_decompress_token(stb_uchar *i) 10415 { 10416 if (*i >= 0x20) { // use fewer if's for cases that expand small 10417 if (*i >= 0x80) stb__match(stb__dout-i[1]-1, i[0] - 0x80 + 1), i += 2; 10418 else if (*i >= 0x40) stb__match(stb__dout-(stb__in2(0) - 0x4000 + 1), i[2]+1), i += 3; 10419 else /* *i >= 0x20 */ stb__lit(i+1, i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1); 10420 } else { // more ifs for cases that expand large, since overhead is amortized 10421 if (*i >= 0x18) stb__match(stb__dout-(stb__in3(0) - 0x180000 + 1), i[3]+1), i += 4; 10422 else if (*i >= 0x10) stb__match(stb__dout-(stb__in3(0) - 0x100000 + 1), stb__in2(3)+1), i += 5; 10423 else if (*i >= 0x08) stb__lit(i+2, stb__in2(0) - 0x0800 + 1), i += 2 + (stb__in2(0) - 0x0800 + 1); 10424 else if (*i == 0x07) stb__lit(i+3, stb__in2(1) + 1), i += 3 + (stb__in2(1) + 1); 10425 else if (*i == 0x06) stb__match(stb__dout-(stb__in3(1)+1), i[4]+1), i += 5; 10426 else if (*i == 0x04) stb__match(stb__dout-(stb__in3(1)+1), stb__in2(4)+1), i += 6; 10427 } 10428 return i; 10429 } 10430 10431 stb_uint stb_decompress(stb_uchar *output, stb_uchar *i, stb_uint length) 10432 { 10433 stb_uint olen; 10434 if (stb__in4(0) != 0x57bC0000) return 0; 10435 if (stb__in4(4) != 0) return 0; // error! stream is > 4GB 10436 olen = stb_decompress_length(i); 10437 stb__barrier2 = i; 10438 stb__barrier3 = i+length; 10439 stb__barrier = output + olen; 10440 stb__barrier4 = output; 10441 i += 16; 10442 10443 stb__dout = output; 10444 while (1) { 10445 stb_uchar *old_i = i; 10446 i = stb_decompress_token(i); 10447 if (i == old_i) { 10448 if (*i == 0x05 && i[1] == 0xfa) { 10449 assert(stb__dout == output + olen); 10450 if (stb__dout != output + olen) return 0; 10451 if (stb_adler32(1, output, olen) != (stb_uint) stb__in4(2)) 10452 return 0; 10453 return olen; 10454 } else { 10455 assert(0); /* NOTREACHED */ 10456 return 0; 10457 } 10458 } 10459 assert(stb__dout <= output + olen); 10460 if (stb__dout > output + olen) 10461 return 0; 10462 } 10463 } 10464 10465 char *stb_decompress_fromfile(char *filename, unsigned int *len) 10466 { 10467 unsigned int n; 10468 char *q; 10469 unsigned char *p; 10470 FILE *f = stb_p_fopen(filename, "rb"); if (f == NULL) return NULL; 10471 fseek(f, 0, SEEK_END); 10472 n = ftell(f); 10473 fseek(f, 0, SEEK_SET); 10474 p = (unsigned char * ) malloc(n); if (p == NULL) return NULL; 10475 fread(p, 1, n, f); 10476 fclose(f); 10477 if (p == NULL) return NULL; 10478 if (p[0] != 0x57 || p[1] != 0xBc || p[2] || p[3]) { free(p); return NULL; } 10479 q = (char *) malloc(stb_decompress_length(p)+1); 10480 if (!q) { free(p); return NULL; } 10481 *len = stb_decompress((unsigned char *) q, p, n); 10482 if (*len) q[*len] = 0; 10483 free(p); 10484 return q; 10485 } 10486 10487 #if 0 10488 // streaming decompressor 10489 10490 static struct 10491 { 10492 stb__uchar *in_buffer; 10493 stb__uchar *match; 10494 10495 stb__uint pending_literals; 10496 stb__uint pending_match; 10497 } xx; 10498 10499 10500 10501 static void stb__match(stb_uchar *data, stb_uint length) 10502 { 10503 // INVERSE of memmove... write each byte before copying the next... 10504 assert (stb__dout + length <= stb__barrier); 10505 if (stb__dout + length > stb__barrier) { stb__dout += length; return; } 10506 if (data < stb__barrier2) { stb__dout = stb__barrier+1; return; } 10507 while (length--) *stb__dout++ = *data++; 10508 } 10509 10510 static void stb__lit(stb_uchar *data, stb_uint length) 10511 { 10512 assert (stb__dout + length <= stb__barrier); 10513 if (stb__dout + length > stb__barrier) { stb__dout += length; return; } 10514 if (data < stb__barrier2) { stb__dout = stb__barrier+1; return; } 10515 memcpy(stb__dout, data, length); 10516 stb__dout += length; 10517 } 10518 10519 static void sx_match(stb_uchar *data, stb_uint length) 10520 { 10521 xx.match = data; 10522 xx.pending_match = length; 10523 } 10524 10525 static void sx_lit(stb_uchar *data, stb_uint length) 10526 { 10527 xx.pending_lit = length; 10528 } 10529 10530 static int stb_decompress_token_state(void) 10531 { 10532 stb__uchar *i = xx.in_buffer; 10533 10534 if (*i >= 0x20) { // use fewer if's for cases that expand small 10535 if (*i >= 0x80) sx_match(stb__dout-i[1]-1, i[0] - 0x80 + 1), i += 2; 10536 else if (*i >= 0x40) sx_match(stb__dout-(stb__in2(0) - 0x4000 + 1), i[2]+1), i += 3; 10537 else /* *i >= 0x20 */ sx_lit(i+1, i[0] - 0x20 + 1), i += 1; 10538 } else { // more ifs for cases that expand large, since overhead is amortized 10539 if (*i >= 0x18) sx_match(stb__dout-(stb__in3(0) - 0x180000 + 1), i[3]+1), i += 4; 10540 else if (*i >= 0x10) sx_match(stb__dout-(stb__in3(0) - 0x100000 + 1), stb__in2(3)+1), i += 5; 10541 else if (*i >= 0x08) sx_lit(i+2, stb__in2(0) - 0x0800 + 1), i += 2; 10542 else if (*i == 0x07) sx_lit(i+3, stb__in2(1) + 1), i += 3; 10543 else if (*i == 0x06) sx_match(stb__dout-(stb__in3(1)+1), i[4]+1), i += 5; 10544 else if (*i == 0x04) sx_match(stb__dout-(stb__in3(1)+1), stb__in2(4)+1), i += 6; 10545 else return 0; 10546 } 10547 xx.in_buffer = i; 10548 return 1; 10549 } 10550 #endif 10551 10552 10553 10555 10556 static unsigned int stb_matchlen(stb_uchar *m1, stb_uchar *m2, stb_uint maxlen) 10557 { 10558 stb_uint i; 10559 for (i=0; i < maxlen; ++i) 10560 if (m1[i] != m2[i]) return i; 10561 return i; 10562 } 10563 10564 // simple implementation that just takes the source data in a big block 10565 10566 static stb_uchar *stb__out; 10567 static FILE *stb__outfile; 10568 static stb_uint stb__outbytes; 10569 10570 static void stb__write(unsigned char v) 10571 { 10572 fputc(v, stb__outfile); 10573 ++stb__outbytes; 10574 } 10575 10576 #define stb_out(v) (stb__out ? (void)(*stb__out++ = (stb_uchar) (v)) : stb__write((stb_uchar) (v))) 10577 10578 static void stb_out2(stb_uint v) 10579 { 10580 stb_out(v >> 8); 10581 stb_out(v); 10582 } 10583 10584 static void stb_out3(stb_uint v) { stb_out(v >> 16); stb_out(v >> 8); stb_out(v); } 10585 static void stb_out4(stb_uint v) { stb_out(v >> 24); stb_out(v >> 16); 10586 stb_out(v >> 8 ); stb_out(v); } 10587 10588 static void outliterals(stb_uchar *in, ptrdiff_t numlit) 10589 { 10590 while (numlit > 65536) { 10591 outliterals(in,65536); 10592 in += 65536; 10593 numlit -= 65536; 10594 } 10595 10596 if (numlit == 0) ; 10597 else if (numlit <= 32) stb_out (0x000020 + (stb_uint) numlit-1); 10598 else if (numlit <= 2048) stb_out2(0x000800 + (stb_uint) numlit-1); 10599 else /* numlit <= 65536) */ stb_out3(0x070000 + (stb_uint) numlit-1); 10600 10601 if (stb__out) { 10602 memcpy(stb__out,in,numlit); 10603 stb__out += numlit; 10604 } else 10605 fwrite(in, 1, numlit, stb__outfile); 10606 } 10607 10608 static int stb__window = 0x40000; // 256K 10609 void stb_compress_window(int z) 10610 { 10611 if (z >= 0x1000000) z = 0x1000000; // limit of implementation 10612 if (z < 0x100) z = 0x100; // insanely small 10613 stb__window = z; 10614 } 10615 10616 static int stb_not_crap(int best, int dist) 10617 { 10618 return ((best > 2 && dist <= 0x00100) 10619 || (best > 5 && dist <= 0x04000) 10620 || (best > 7 && dist <= 0x80000)); 10621 } 10622 10623 static stb_uint stb__hashsize = 32768; 10624 void stb_compress_hashsize(unsigned int y) 10625 { 10626 unsigned int z = 1024; 10627 while (z < y) z <<= 1; 10628 stb__hashsize = z >> 2; // pass in bytes, store #pointers 10629 } 10630 10631 // note that you can play with the hashing functions all you 10632 // want without needing to change the decompressor 10633 #define stb__hc(q,h,c) (((h) << 7) + ((h) >> 25) + q[c]) 10634 #define stb__hc2(q,h,c,d) (((h) << 14) + ((h) >> 18) + (q[c] << 7) + q[d]) 10635 #define stb__hc3(q,c,d,e) ((q[c] << 14) + (q[d] << 7) + q[e]) 10636 10637 static stb_uint32 stb__running_adler; 10638 10639 static int stb_compress_chunk(stb_uchar *history, 10640 stb_uchar *start, 10641 stb_uchar *end, 10642 int length, 10643 int *pending_literals, 10644 stb_uchar **chash, 10645 stb_uint mask) 10646 { 10647 int window = stb__window; 10648 stb_uint match_max; 10649 stb_uchar *lit_start = start - *pending_literals; 10650 stb_uchar *q = start; 10651 10652 #define STB__SCRAMBLE(h) (((h) + ((h) >> 16)) & mask) 10653 10654 // stop short of the end so we don't scan off the end doing 10655 // the hashing; this means we won't compress the last few bytes 10656 // unless they were part of something longer 10657 while (q < start+length && q+12 < end) { 10658 int m; 10659 stb_uint h1,h2,h3,h4, h; 10660 stb_uchar *t; 10661 int best = 2, dist=0; 10662 10663 if (q+65536 > end) 10664 match_max = (stb_uint) (end-q); 10665 else 10666 match_max = 65536u; 10667 10668 #define stb__nc(b,d) ((d) <= window && ((b) > 9 || stb_not_crap(b,d))) 10669 10670 #define STB__TRY(t,p) /* avoid retrying a match we already tried */ \ 10671 if (p ? dist != (int) (q-t) : 1) \ 10672 if ((m = (int) stb_matchlen(t, q, match_max)) > best)\ 10673 if (stb__nc(m,(int) (q-(t)))) \ 10674 best = m, dist = (int) (q - (t)) 10675 10676 // rather than search for all matches, only try 4 candidate locations, 10677 // chosen based on 4 different hash functions of different lengths. 10678 // this strategy is inspired by LZO; hashing is unrolled here using the 10679 // 'hc' macro 10680 h = stb__hc3(q,0, 1, 2); h1 = STB__SCRAMBLE(h); 10681 t = chash[h1]; if (t) STB__TRY(t,0); 10682 h = stb__hc2(q,h, 3, 4); h2 = STB__SCRAMBLE(h); 10683 h = stb__hc2(q,h, 5, 6); t = chash[h2]; if (t) STB__TRY(t,1); 10684 h = stb__hc2(q,h, 7, 8); h3 = STB__SCRAMBLE(h); 10685 h = stb__hc2(q,h, 9,10); t = chash[h3]; if (t) STB__TRY(t,1); 10686 h = stb__hc2(q,h,11,12); h4 = STB__SCRAMBLE(h); 10687 t = chash[h4]; if (t) STB__TRY(t,1); 10688 10689 // because we use a shared hash table, can only update it 10690 // _after_ we've probed all of them 10691 chash[h1] = chash[h2] = chash[h3] = chash[h4] = q; 10692 10693 if (best > 2) 10694 assert(dist > 0); 10695 10696 // see if our best match qualifies 10697 if (best < 3) { // fast path literals 10698 ++q; 10699 } else if (best > 2 && best <= 0x80 && dist <= 0x100) { 10700 outliterals(lit_start, q-lit_start); lit_start = (q += best); 10701 stb_out(0x80 + best-1); 10702 stb_out(dist-1); 10703 } else if (best > 5 && best <= 0x100 && dist <= 0x4000) { 10704 outliterals(lit_start, q-lit_start); lit_start = (q += best); 10705 stb_out2(0x4000 + dist-1); 10706 stb_out(best-1); 10707 } else if (best > 7 && best <= 0x100 && dist <= 0x80000) { 10708 outliterals(lit_start, q-lit_start); lit_start = (q += best); 10709 stb_out3(0x180000 + dist-1); 10710 stb_out(best-1); 10711 } else if (best > 8 && best <= 0x10000 && dist <= 0x80000) { 10712 outliterals(lit_start, q-lit_start); lit_start = (q += best); 10713 stb_out3(0x100000 + dist-1); 10714 stb_out2(best-1); 10715 } else if (best > 9 && dist <= 0x1000000) { 10716 if (best > 65536) best = 65536; 10717 outliterals(lit_start, q-lit_start); lit_start = (q += best); 10718 if (best <= 0x100) { 10719 stb_out(0x06); 10720 stb_out3(dist-1); 10721 stb_out(best-1); 10722 } else { 10723 stb_out(0x04); 10724 stb_out3(dist-1); 10725 stb_out2(best-1); 10726 } 10727 } else { // fallback literals if no match was a balanced tradeoff 10728 ++q; 10729 } 10730 } 10731 10732 // if we didn't get all the way, add the rest to literals 10733 if (q-start < length) 10734 q = start+length; 10735 10736 // the literals are everything from lit_start to q 10737 *pending_literals = (int) (q - lit_start); 10738 10739 stb__running_adler = stb_adler32(stb__running_adler, start, (int) (q - start)); 10740 return (int) (q - start); 10741 } 10742 10743 static int stb_compress_inner(stb_uchar *input, stb_uint length) 10744 { 10745 int literals = 0; 10746 stb_uint len,i; 10747 10748 stb_uchar **chash; 10749 chash = (stb_uchar**) malloc(stb__hashsize * sizeof(stb_uchar*)); 10750 if (chash == NULL) return 0; // failure 10751 for (i=0; i < stb__hashsize; ++i) 10752 chash[i] = NULL; 10753 10754 // stream signature 10755 stb_out(0x57); stb_out(0xbc); 10756 stb_out2(0); 10757 10758 stb_out4(0); // 64-bit length requires 32-bit leading 0 10759 stb_out4(length); 10760 stb_out4(stb__window); 10761 10762 stb__running_adler = 1; 10763 10764 len = stb_compress_chunk(input, input, input+length, length, &literals, chash, stb__hashsize-1); 10765 assert(len == length); 10766 10767 outliterals(input+length - literals, literals); 10768 10769 free(chash); 10770 10771 stb_out2(0x05fa); // end opcode 10772 10773 stb_out4(stb__running_adler); 10774 10775 return 1; // success 10776 } 10777 10778 stb_uint stb_compress(stb_uchar *out, stb_uchar *input, stb_uint length) 10779 { 10780 stb__out = out; 10781 stb__outfile = NULL; 10782 10783 stb_compress_inner(input, length); 10784 10785 return (stb_uint) (stb__out - out); 10786 } 10787 10788 int stb_compress_tofile(char *filename, char *input, unsigned int length) 10789 { 10790 //int maxlen = length + 512 + (length >> 2); // total guess 10791 //char *buffer = (char *) malloc(maxlen); 10792 //int blen = stb_compress((stb_uchar*)buffer, (stb_uchar*)input, length); 10793 10794 stb__out = NULL; 10795 stb__outfile = stb_p_fopen(filename, "wb"); 10796 if (!stb__outfile) return 0; 10797 10798 stb__outbytes = 0; 10799 10800 if (!stb_compress_inner((stb_uchar*)input, length)) 10801 return 0; 10802 10803 fclose(stb__outfile); 10804 10805 return stb__outbytes; 10806 } 10807 10808 int stb_compress_intofile(FILE *f, char *input, unsigned int length) 10809 { 10810 //int maxlen = length + 512 + (length >> 2); // total guess 10811 //char *buffer = (char*)malloc(maxlen); 10812 //int blen = stb_compress((stb_uchar*)buffer, (stb_uchar*)input, length); 10813 10814 stb__out = NULL; 10815 stb__outfile = f; 10816 if (!stb__outfile) return 0; 10817 10818 stb__outbytes = 0; 10819 10820 if (!stb_compress_inner((stb_uchar*)input, length)) 10821 return 0; 10822 10823 return stb__outbytes; 10824 } 10825 10827 10828 10829 static size_t stb_out_backpatch_id(void) 10830 { 10831 if (stb__out) 10832 return (size_t) stb__out; 10833 else 10834 return ftell(stb__outfile); 10835 } 10836 10837 static void stb_out_backpatch(size_t id, stb_uint value) 10838 { 10839 stb_uchar data[4] = { (stb_uchar)(value >> 24), (stb_uchar)(value >> 16), (stb_uchar)(value >> 8), (stb_uchar)(value) }; 10840 if (stb__out) { 10841 memcpy((void *) id, data, 4); 10842 } else { 10843 stb_uint where = ftell(stb__outfile); 10844 fseek(stb__outfile, (long) id, SEEK_SET); 10845 fwrite(data, 4, 1, stb__outfile); 10846 fseek(stb__outfile, where, SEEK_SET); 10847 } 10848 } 10849 10850 // ok, the wraparound buffer was a total failure. let's instead 10851 // use a copying-in-place buffer, which lets us share the code. 10852 // This is way less efficient but it'll do for now. 10853 10854 static struct 10855 { 10856 stb_uchar *buffer; 10857 int size; // physical size of buffer in bytes 10858 10859 int valid; // amount of valid data in bytes 10860 int start; // bytes of data already output 10861 10862 int window; 10863 int fsize; 10864 10865 int pending_literals; // bytes not-quite output but counted in start 10866 int length_id; 10867 10868 stb_uint total_bytes; 10869 10870 stb_uchar **chash; 10871 stb_uint hashmask; 10872 } xtb; 10873 10874 static int stb_compress_streaming_start(void) 10875 { 10876 stb_uint i; 10877 xtb.size = stb__window * 3; 10878 xtb.buffer = (stb_uchar*)malloc(xtb.size); 10879 if (!xtb.buffer) return 0; 10880 10881 xtb.chash = (stb_uchar**)malloc(sizeof(*xtb.chash) * stb__hashsize); 10882 if (!xtb.chash) { 10883 free(xtb.buffer); 10884 return 0; 10885 } 10886 10887 for (i=0; i < stb__hashsize; ++i) 10888 xtb.chash[i] = NULL; 10889 10890 xtb.hashmask = stb__hashsize-1; 10891 10892 xtb.valid = 0; 10893 xtb.start = 0; 10894 xtb.window = stb__window; 10895 xtb.fsize = stb__window; 10896 xtb.pending_literals = 0; 10897 xtb.total_bytes = 0; 10898 10899 // stream signature 10900 stb_out(0x57); stb_out(0xbc); stb_out2(0); 10901 10902 stb_out4(0); // 64-bit length requires 32-bit leading 0 10903 10904 xtb.length_id = (int) stb_out_backpatch_id(); 10905 stb_out4(0); // we don't know the output length yet 10906 10907 stb_out4(stb__window); 10908 10909 stb__running_adler = 1; 10910 10911 return 1; 10912 } 10913 10914 static int stb_compress_streaming_end(void) 10915 { 10916 // flush out any remaining data 10917 stb_compress_chunk(xtb.buffer, xtb.buffer+xtb.start, xtb.buffer+xtb.valid, 10918 xtb.valid-xtb.start, &xtb.pending_literals, xtb.chash, xtb.hashmask); 10919 10920 // write out pending literals 10921 outliterals(xtb.buffer + xtb.valid - xtb.pending_literals, xtb.pending_literals); 10922 10923 stb_out2(0x05fa); // end opcode 10924 stb_out4(stb__running_adler); 10925 10926 stb_out_backpatch(xtb.length_id, xtb.total_bytes); 10927 10928 free(xtb.buffer); 10929 free(xtb.chash); 10930 return 1; 10931 } 10932 10933 void stb_write(char *data, int data_len) 10934 { 10935 stb_uint i; 10936 10937 // @TODO: fast path for filling the buffer and doing nothing else 10938 // if (xtb.valid + data_len < xtb.size) 10939 10940 xtb.total_bytes += data_len; 10941 10942 while (data_len) { 10943 // fill buffer 10944 if (xtb.valid < xtb.size) { 10945 int amt = xtb.size - xtb.valid; 10946 if (data_len < amt) amt = data_len; 10947 memcpy(xtb.buffer + xtb.valid, data, amt); 10948 data_len -= amt; 10949 data += amt; 10950 xtb.valid += amt; 10951 } 10952 if (xtb.valid < xtb.size) 10953 return; 10954 10955 // at this point, the buffer is full 10956 10957 // if we can process some data, go for it; make sure 10958 // we leave an 'fsize's worth of data, though 10959 if (xtb.start + xtb.fsize < xtb.valid) { 10960 int amount = (xtb.valid - xtb.fsize) - xtb.start; 10961 int n; 10962 assert(amount > 0); 10963 n = stb_compress_chunk(xtb.buffer, xtb.buffer + xtb.start, xtb.buffer + xtb.valid, 10964 amount, &xtb.pending_literals, xtb.chash, xtb.hashmask); 10965 xtb.start += n; 10966 } 10967 10968 assert(xtb.start + xtb.fsize >= xtb.valid); 10969 // at this point, our future size is too small, so we 10970 // need to flush some history. we, in fact, flush exactly 10971 // one window's worth of history 10972 10973 { 10974 int flush = xtb.window; 10975 assert(xtb.start >= flush); 10976 assert(xtb.valid >= flush); 10977 10978 // if 'pending literals' extends back into the shift region, 10979 // write them out 10980 if (xtb.start - xtb.pending_literals < flush) { 10981 outliterals(xtb.buffer + xtb.start - xtb.pending_literals, xtb.pending_literals); 10982 xtb.pending_literals = 0; 10983 } 10984 10985 // now shift the window 10986 memmove(xtb.buffer, xtb.buffer + flush, xtb.valid - flush); 10987 xtb.start -= flush; 10988 xtb.valid -= flush; 10989 10990 for (i=0; i <= xtb.hashmask; ++i) 10991 if (xtb.chash[i] < xtb.buffer + flush) 10992 xtb.chash[i] = NULL; 10993 else 10994 xtb.chash[i] -= flush; 10995 } 10996 // and now that we've made room for more data, go back to the top 10997 } 10998 } 10999 11000 int stb_compress_stream_start(FILE *f) 11001 { 11002 stb__out = NULL; 11003 stb__outfile = f; 11004 11005 if (f == NULL) 11006 return 0; 11007 11008 if (!stb_compress_streaming_start()) 11009 return 0; 11010 11011 return 1; 11012 } 11013 11014 void stb_compress_stream_end(int close) 11015 { 11016 stb_compress_streaming_end(); 11017 if (close && stb__outfile) { 11018 fclose(stb__outfile); 11019 } 11020 } 11021 11022 #endif // STB_DEFINE 11023 11025 // 11026 // File abstraction... tired of not having this... we can write 11027 // compressors to be layers over these that auto-close their children. 11028 11029 11030 typedef struct stbfile 11031 { 11032 int (*getbyte)(struct stbfile *); // -1 on EOF 11033 unsigned int (*getdata)(struct stbfile *, void *block, unsigned int len); 11034 11035 int (*putbyte)(struct stbfile *, int byte); 11036 unsigned int (*putdata)(struct stbfile *, void *block, unsigned int len); 11037 11038 unsigned int (*size)(struct stbfile *); 11039 11040 unsigned int (*tell)(struct stbfile *); 11041 void (*backpatch)(struct stbfile *, unsigned int tell, void *block, unsigned int len); 11042 11043 void (*close)(struct stbfile *); 11044 11045 FILE *f; // file to fread/fwrite 11046 unsigned char *buffer; // input/output buffer 11047 unsigned char *indata, *inend; // input buffer 11048 union { 11049 int various; 11050 void *ptr; 11051 }; 11052 } stbfile; 11053 11054 STB_EXTERN unsigned int stb_getc(stbfile *f); // read 11055 STB_EXTERN int stb_putc(stbfile *f, int ch); // write 11056 STB_EXTERN unsigned int stb_getdata(stbfile *f, void *buffer, unsigned int len); // read 11057 STB_EXTERN unsigned int stb_putdata(stbfile *f, void *buffer, unsigned int len); // write 11058 STB_EXTERN unsigned int stb_tell(stbfile *f); // read 11059 STB_EXTERN unsigned int stb_size(stbfile *f); // read/write 11060 STB_EXTERN void stb_backpatch(stbfile *f, unsigned int tell, void *buffer, unsigned int len); // write 11061 11062 #ifdef STB_DEFINE 11063 11064 unsigned int stb_getc(stbfile *f) { return f->getbyte(f); } 11065 int stb_putc(stbfile *f, int ch) { return f->putbyte(f, ch); } 11066 11067 unsigned int stb_getdata(stbfile *f, void *buffer, unsigned int len) 11068 { 11069 return f->getdata(f, buffer, len); 11070 } 11071 unsigned int stb_putdata(stbfile *f, void *buffer, unsigned int len) 11072 { 11073 return f->putdata(f, buffer, len); 11074 } 11075 void stb_close(stbfile *f) 11076 { 11077 f->close(f); 11078 free(f); 11079 } 11080 unsigned int stb_tell(stbfile *f) { return f->tell(f); } 11081 unsigned int stb_size(stbfile *f) { return f->size(f); } 11082 void stb_backpatch(stbfile *f, unsigned int tell, void *buffer, unsigned int len) 11083 { 11084 f->backpatch(f,tell,buffer,len); 11085 } 11086 11087 // FILE * implementation 11088 static int stb__fgetbyte(stbfile *f) { return fgetc(f->f); } 11089 static int stb__fputbyte(stbfile *f, int ch) { return fputc(ch, f->f)==0; } 11090 static unsigned int stb__fgetdata(stbfile *f, void *buffer, unsigned int len) { return (unsigned int) fread(buffer,1,len,f->f); } 11091 static unsigned int stb__fputdata(stbfile *f, void *buffer, unsigned int len) { return (unsigned int) fwrite(buffer,1,len,f->f); } 11092 static unsigned int stb__fsize(stbfile *f) { return (unsigned int) stb_filelen(f->f); } 11093 static unsigned int stb__ftell(stbfile *f) { return (unsigned int) ftell(f->f); } 11094 static void stb__fbackpatch(stbfile *f, unsigned int where, void *buffer, unsigned int len) 11095 { 11096 fseek(f->f, where, SEEK_SET); 11097 fwrite(buffer, 1, len, f->f); 11098 fseek(f->f, 0, SEEK_END); 11099 } 11100 static void stb__fclose(stbfile *f) { fclose(f->f); } 11101 11102 stbfile *stb_openf(FILE *f) 11103 { 11104 stbfile m = { stb__fgetbyte, stb__fgetdata, 11105 stb__fputbyte, stb__fputdata, 11106 stb__fsize, stb__ftell, stb__fbackpatch, stb__fclose, 11107 0,0,0, }; 11108 stbfile *z = (stbfile *) malloc(sizeof(*z)); 11109 if (z) { 11110 *z = m; 11111 z->f = f; 11112 } 11113 return z; 11114 } 11115 11116 static int stb__nogetbyte(stbfile *f) { assert(0); return -1; } 11117 static unsigned int stb__nogetdata(stbfile *f, void *buffer, unsigned int len) { assert(0); return 0; } 11118 static int stb__noputbyte(stbfile *f, int ch) { assert(0); return 0; } 11119 static unsigned int stb__noputdata(stbfile *f, void *buffer, unsigned int len) { assert(0); return 0; } 11120 static void stb__nobackpatch(stbfile *f, unsigned int where, void *buffer, unsigned int len) { assert(0); } 11121 11122 static int stb__bgetbyte(stbfile *s) 11123 { 11124 if (s->indata < s->inend) 11125 return *s->indata++; 11126 else 11127 return -1; 11128 } 11129 11130 static unsigned int stb__bgetdata(stbfile *s, void *buffer, unsigned int len) 11131 { 11132 if (s->indata + len > s->inend) 11133 len = (unsigned int) (s->inend - s->indata); 11134 memcpy(buffer, s->indata, len); 11135 s->indata += len; 11136 return len; 11137 } 11138 static unsigned int stb__bsize(stbfile *s) { return (unsigned int) (s->inend - s->buffer); } 11139 static unsigned int stb__btell(stbfile *s) { return (unsigned int) (s->indata - s->buffer); } 11140 11141 static void stb__bclose(stbfile *s) 11142 { 11143 if (s->various) 11144 free(s->buffer); 11145 } 11146 11147 stbfile *stb_open_inbuffer(void *buffer, unsigned int len) 11148 { 11149 stbfile m = { stb__bgetbyte, stb__bgetdata, 11150 stb__noputbyte, stb__noputdata, 11151 stb__bsize, stb__btell, stb__nobackpatch, stb__bclose }; 11152 stbfile *z = (stbfile *) malloc(sizeof(*z)); 11153 if (z) { 11154 *z = m; 11155 z->buffer = (unsigned char *) buffer; 11156 z->indata = z->buffer; 11157 z->inend = z->indata + len; 11158 } 11159 return z; 11160 } 11161 11162 stbfile *stb_open_inbuffer_free(void *buffer, unsigned int len) 11163 { 11164 stbfile *z = stb_open_inbuffer(buffer, len); 11165 if (z) 11166 z->various = 1; // free 11167 return z; 11168 } 11169 11170 #ifndef STB_VERSION 11171 // if we've been cut-and-pasted elsewhere, you get a limited 11172 // version of stb_open, without the 'k' flag and utf8 support 11173 static void stb__fclose2(stbfile *f) 11174 { 11175 fclose(f->f); 11176 } 11177 11178 stbfile *stb_open(char *filename, char *mode) 11179 { 11180 FILE *f = stb_p_fopen(filename, mode); 11181 stbfile *s; 11182 if (f == NULL) return NULL; 11183 s = stb_openf(f); 11184 if (s) 11185 s->close = stb__fclose2; 11186 return s; 11187 } 11188 #else 11189 // the full version depends on some code in stb.h; this 11190 // also includes the memory buffer output format implemented with stb_arr 11191 static void stb__fclose2(stbfile *f) 11192 { 11193 stb_fclose(f->f, f->various); 11194 } 11195 11196 stbfile *stb_open(char *filename, char *mode) 11197 { 11198 FILE *f = stb_fopen(filename, mode[0] == 'k' ? mode+1 : mode); 11199 stbfile *s; 11200 if (f == NULL) return NULL; 11201 s = stb_openf(f); 11202 if (s) { 11203 s->close = stb__fclose2; 11204 s->various = mode[0] == 'k' ? stb_keep_if_different : stb_keep_yes; 11205 } 11206 return s; 11207 } 11208 11209 static int stb__aputbyte(stbfile *f, int ch) 11210 { 11211 stb_arr_push(f->buffer, ch); 11212 return 1; 11213 } 11214 static unsigned int stb__aputdata(stbfile *f, void *data, unsigned int len) 11215 { 11216 memcpy(stb_arr_addn(f->buffer, (int) len), data, len); 11217 return len; 11218 } 11219 static unsigned int stb__asize(stbfile *f) { return stb_arr_len(f->buffer); } 11220 static void stb__abackpatch(stbfile *f, unsigned int where, void *data, unsigned int len) 11221 { 11222 memcpy(f->buffer+where, data, len); 11223 } 11224 static void stb__aclose(stbfile *f) 11225 { 11226 *(unsigned char **) f->ptr = f->buffer; 11227 } 11228 11229 stbfile *stb_open_outbuffer(unsigned char **update_on_close) 11230 { 11231 stbfile m = { stb__nogetbyte, stb__nogetdata, 11232 stb__aputbyte, stb__aputdata, 11233 stb__asize, stb__asize, stb__abackpatch, stb__aclose }; 11234 stbfile *z = (stbfile *) malloc(sizeof(*z)); 11235 if (z) { 11236 z->ptr = update_on_close; 11237 *z = m; 11238 } 11239 return z; 11240 } 11241 #endif 11242 #endif 11243 11244 11246 // 11247 // Arithmetic coder... based on cbloom's notes on the subject, should be 11248 // less code than a huffman code. 11249 11250 typedef struct 11251 { 11252 unsigned int range_low; 11253 unsigned int range_high; 11254 unsigned int code, range; // decode 11255 int buffered_u8; 11256 int pending_ffs; 11257 stbfile *output; 11258 } stb_arith; 11259 11260 STB_EXTERN void stb_arith_init_encode(stb_arith *a, stbfile *out); 11261 STB_EXTERN void stb_arith_init_decode(stb_arith *a, stbfile *in); 11262 STB_EXTERN stbfile *stb_arith_encode_close(stb_arith *a); 11263 STB_EXTERN stbfile *stb_arith_decode_close(stb_arith *a); 11264 11265 STB_EXTERN void stb_arith_encode(stb_arith *a, unsigned int totalfreq, unsigned int freq, unsigned int cumfreq); 11266 STB_EXTERN void stb_arith_encode_log2(stb_arith *a, unsigned int totalfreq2, unsigned int freq, unsigned int cumfreq); 11267 STB_EXTERN unsigned int stb_arith_decode_value(stb_arith *a, unsigned int totalfreq); 11268 STB_EXTERN void stb_arith_decode_advance(stb_arith *a, unsigned int totalfreq, unsigned int freq, unsigned int cumfreq); 11269 STB_EXTERN unsigned int stb_arith_decode_value_log2(stb_arith *a, unsigned int totalfreq2); 11270 STB_EXTERN void stb_arith_decode_advance_log2(stb_arith *a, unsigned int totalfreq2, unsigned int freq, unsigned int cumfreq); 11271 11272 STB_EXTERN void stb_arith_encode_byte(stb_arith *a, int byte); 11273 STB_EXTERN int stb_arith_decode_byte(stb_arith *a); 11274 11275 // this is a memory-inefficient way of doing things, but it's 11276 // fast(?) and simple 11277 typedef struct 11278 { 11279 unsigned short cumfreq; 11280 unsigned short samples; 11281 } stb_arith_symstate_item; 11282 11283 typedef struct 11284 { 11285 int num_sym; 11286 unsigned int pow2; 11287 int countdown; 11288 stb_arith_symstate_item data[1]; 11289 } stb_arith_symstate; 11290 11291 #ifdef STB_DEFINE 11292 void stb_arith_init_encode(stb_arith *a, stbfile *out) 11293 { 11294 a->range_low = 0; 11295 a->range_high = 0xffffffff; 11296 a->pending_ffs = -1; // means no buffered character currently, to speed up normal case 11297 a->output = out; 11298 } 11299 11300 static void stb__arith_carry(stb_arith *a) 11301 { 11302 int i; 11303 assert(a->pending_ffs != -1); // can't carry with no data 11304 stb_putc(a->output, a->buffered_u8); 11305 for (i=0; i < a->pending_ffs; ++i) 11306 stb_putc(a->output, 0); 11307 } 11308 11309 static void stb__arith_putbyte(stb_arith *a, int byte) 11310 { 11311 if (a->pending_ffs) { 11312 if (a->pending_ffs == -1) { // means no buffered data; encoded for fast path efficiency 11313 if (byte == 0xff) 11314 stb_putc(a->output, byte); // just write it immediately 11315 else { 11316 a->buffered_u8 = byte; 11317 a->pending_ffs = 0; 11318 } 11319 } else if (byte == 0xff) { 11320 ++a->pending_ffs; 11321 } else { 11322 int i; 11323 stb_putc(a->output, a->buffered_u8); 11324 for (i=0; i < a->pending_ffs; ++i) 11325 stb_putc(a->output, 0xff); 11326 } 11327 } else if (byte == 0xff) { 11328 ++a->pending_ffs; 11329 } else { 11330 // fast path 11331 stb_putc(a->output, a->buffered_u8); 11332 a->buffered_u8 = byte; 11333 } 11334 } 11335 11336 static void stb__arith_flush(stb_arith *a) 11337 { 11338 if (a->pending_ffs >= 0) { 11339 int i; 11340 stb_putc(a->output, a->buffered_u8); 11341 for (i=0; i < a->pending_ffs; ++i) 11342 stb_putc(a->output, 0xff); 11343 } 11344 } 11345 11346 static void stb__renorm_encoder(stb_arith *a) 11347 { 11348 stb__arith_putbyte(a, a->range_low >> 24); 11349 a->range_low <<= 8; 11350 a->range_high = (a->range_high << 8) | 0xff; 11351 } 11352 11353 static void stb__renorm_decoder(stb_arith *a) 11354 { 11355 int c = stb_getc(a->output); 11356 a->code = (a->code << 8) + (c >= 0 ? c : 0); // if EOF, insert 0 11357 } 11358 11359 void stb_arith_encode(stb_arith *a, unsigned int totalfreq, unsigned int freq, unsigned int cumfreq) 11360 { 11361 unsigned int range = a->range_high - a->range_low; 11362 unsigned int old = a->range_low; 11363 range /= totalfreq; 11364 a->range_low += range * cumfreq; 11365 a->range_high = a->range_low + range*freq; 11366 if (a->range_low < old) 11367 stb__arith_carry(a); 11368 while (a->range_high - a->range_low < 0x1000000) 11369 stb__renorm_encoder(a); 11370 } 11371 11372 void stb_arith_encode_log2(stb_arith *a, unsigned int totalfreq2, unsigned int freq, unsigned int cumfreq) 11373 { 11374 unsigned int range = a->range_high - a->range_low; 11375 unsigned int old = a->range_low; 11376 range >>= totalfreq2; 11377 a->range_low += range * cumfreq; 11378 a->range_high = a->range_low + range*freq; 11379 if (a->range_low < old) 11380 stb__arith_carry(a); 11381 while (a->range_high - a->range_low < 0x1000000) 11382 stb__renorm_encoder(a); 11383 } 11384 11385 unsigned int stb_arith_decode_value(stb_arith *a, unsigned int totalfreq) 11386 { 11387 unsigned int freqsize = a->range / totalfreq; 11388 unsigned int z = a->code / freqsize; 11389 return z >= totalfreq ? totalfreq-1 : z; 11390 } 11391 11392 void stb_arith_decode_advance(stb_arith *a, unsigned int totalfreq, unsigned int freq, unsigned int cumfreq) 11393 { 11394 unsigned int freqsize = a->range / totalfreq; // @OPTIMIZE, share with above divide somehow? 11395 a->code -= freqsize * cumfreq; 11396 a->range = freqsize * freq; 11397 while (a->range < 0x1000000) 11398 stb__renorm_decoder(a); 11399 } 11400 11401 unsigned int stb_arith_decode_value_log2(stb_arith *a, unsigned int totalfreq2) 11402 { 11403 unsigned int freqsize = a->range >> totalfreq2; 11404 unsigned int z = a->code / freqsize; 11405 return z >= (1U<<totalfreq2) ? (1U<<totalfreq2)-1 : z; 11406 } 11407 11408 void stb_arith_decode_advance_log2(stb_arith *a, unsigned int totalfreq2, unsigned int freq, unsigned int cumfreq) 11409 { 11410 unsigned int freqsize = a->range >> totalfreq2; 11411 a->code -= freqsize * cumfreq; 11412 a->range = freqsize * freq; 11413 while (a->range < 0x1000000) 11414 stb__renorm_decoder(a); 11415 } 11416 11417 stbfile *stb_arith_encode_close(stb_arith *a) 11418 { 11419 // put exactly as many bytes as we'll read, so we can turn on/off arithmetic coding in a stream 11420 stb__arith_putbyte(a, a->range_low >> 24); 11421 stb__arith_putbyte(a, a->range_low >> 16); 11422 stb__arith_putbyte(a, a->range_low >> 8); 11423 stb__arith_putbyte(a, a->range_low >> 0); 11424 stb__arith_flush(a); 11425 return a->output; 11426 } 11427 11428 stbfile *stb_arith_decode_close(stb_arith *a) 11429 { 11430 return a->output; 11431 } 11432 #endif 11433 11435 // 11436 // Threads 11437 // 11438 11439 #ifndef _WIN32 11440 #ifdef STB_THREADS 11441 #error "threads not implemented except for Windows" 11442 #endif 11443 #endif 11444 11445 // call this function to free any global variables for memory testing 11446 STB_EXTERN void stb_thread_cleanup(void); 11447 11448 typedef void * (*stb_thread_func)(void *); 11449 11450 // do not rely on these types, this is an implementation detail. 11451 // compare against STB_THREAD_NULL and ST_SEMAPHORE_NULL 11452 typedef void *stb_thread; 11453 typedef void *stb_semaphore; 11454 typedef void *stb_mutex; 11455 typedef struct stb__sync *stb_sync; 11456 11457 #define STB_SEMAPHORE_NULL NULL 11458 #define STB_THREAD_NULL NULL 11459 #define STB_MUTEX_NULL NULL 11460 #define STB_SYNC_NULL NULL 11461 11462 // get the number of processors (limited to those in the affinity mask for this process). 11463 STB_EXTERN int stb_processor_count(void); 11464 // force to run on a single core -- needed for RDTSC to work, e.g. for iprof 11465 STB_EXTERN void stb_force_uniprocessor(void); 11466 11467 // stb_work functions: queue up work to be done by some worker threads 11468 11469 // set number of threads to serve the queue; you can change this on the fly, 11470 // but if you decrease it, it won't decrease until things currently on the 11471 // queue are finished 11472 STB_EXTERN void stb_work_numthreads(int n); 11473 // set maximum number of units in the queue; you can only set this BEFORE running any work functions 11474 STB_EXTERN int stb_work_maxunits(int n); 11475 // enqueue some work to be done (can do this from any thread, or even from a piece of work); 11476 // return value of f is stored in *return_code if non-NULL 11477 STB_EXTERN int stb_work(stb_thread_func f, void *d, volatile void **return_code); 11478 // as above, but stb_sync_reach is called on 'rel' after work is complete 11479 STB_EXTERN int stb_work_reach(stb_thread_func f, void *d, volatile void **return_code, stb_sync rel); 11480 11481 11482 // necessary to call this when using volatile to order writes/reads 11483 STB_EXTERN void stb_barrier(void); 11484 11485 // support for independent queues with their own threads 11486 11487 typedef struct stb__workqueue stb_workqueue; 11488 11489 STB_EXTERN stb_workqueue*stb_workq_new(int numthreads, int max_units); 11490 STB_EXTERN stb_workqueue*stb_workq_new_flags(int numthreads, int max_units, int no_add_mutex, int no_remove_mutex); 11491 STB_EXTERN void stb_workq_delete(stb_workqueue *q); 11492 STB_EXTERN void stb_workq_numthreads(stb_workqueue *q, int n); 11493 STB_EXTERN int stb_workq(stb_workqueue *q, stb_thread_func f, void *d, volatile void **return_code); 11494 STB_EXTERN int stb_workq_reach(stb_workqueue *q, stb_thread_func f, void *d, volatile void **return_code, stb_sync rel); 11495 STB_EXTERN int stb_workq_length(stb_workqueue *q); 11496 11497 STB_EXTERN stb_thread stb_create_thread (stb_thread_func f, void *d); 11498 STB_EXTERN stb_thread stb_create_thread2(stb_thread_func f, void *d, volatile void **return_code, stb_semaphore rel); 11499 STB_EXTERN void stb_destroy_thread(stb_thread t); 11500 11501 STB_EXTERN stb_semaphore stb_sem_new(int max_val); 11502 STB_EXTERN stb_semaphore stb_sem_new_extra(int max_val, int start_val); 11503 STB_EXTERN void stb_sem_delete (stb_semaphore s); 11504 STB_EXTERN void stb_sem_waitfor(stb_semaphore s); 11505 STB_EXTERN void stb_sem_release(stb_semaphore s); 11506 11507 STB_EXTERN stb_mutex stb_mutex_new(void); 11508 STB_EXTERN void stb_mutex_delete(stb_mutex m); 11509 STB_EXTERN void stb_mutex_begin(stb_mutex m); 11510 STB_EXTERN void stb_mutex_end(stb_mutex m); 11511 11512 STB_EXTERN stb_sync stb_sync_new(void); 11513 STB_EXTERN void stb_sync_delete(stb_sync s); 11514 STB_EXTERN int stb_sync_set_target(stb_sync s, int count); 11515 STB_EXTERN void stb_sync_reach_and_wait(stb_sync s); // wait for 'target' reachers 11516 STB_EXTERN int stb_sync_reach(stb_sync s); 11517 11518 typedef struct stb__threadqueue stb_threadqueue; 11519 #define STB_THREADQ_DYNAMIC 0 11520 STB_EXTERN stb_threadqueue *stb_threadq_new(int item_size, int num_items, int many_add, int many_remove); 11521 STB_EXTERN void stb_threadq_delete(stb_threadqueue *tq); 11522 STB_EXTERN int stb_threadq_get(stb_threadqueue *tq, void *output); 11523 STB_EXTERN void stb_threadq_get_block(stb_threadqueue *tq, void *output); 11524 STB_EXTERN int stb_threadq_add(stb_threadqueue *tq, void *input); 11525 // can return FALSE if STB_THREADQ_DYNAMIC and attempt to grow fails 11526 STB_EXTERN int stb_threadq_add_block(stb_threadqueue *tq, void *input); 11527 11528 #ifdef STB_THREADS 11529 #ifdef STB_DEFINE 11530 11531 typedef struct 11532 { 11533 stb_thread_func f; 11534 void *d; 11535 volatile void **return_val; 11536 stb_semaphore sem; 11537 } stb__thread; 11538 11539 // this is initialized along all possible paths to create threads, therefore 11540 // it's always initialized before any other threads are create, therefore 11541 // it's free of races AS LONG AS you only create threads through stb_* 11542 static stb_mutex stb__threadmutex, stb__workmutex; 11543 11544 static void stb__threadmutex_init(void) 11545 { 11546 if (stb__threadmutex == STB_SEMAPHORE_NULL) { 11547 stb__threadmutex = stb_mutex_new(); 11548 stb__workmutex = stb_mutex_new(); 11549 } 11550 } 11551 11552 #ifdef STB_THREAD_TEST 11553 volatile float stb__t1=1, stb__t2; 11554 11555 static void stb__wait(int n) 11556 { 11557 float z = 0; 11558 int i; 11559 for (i=0; i < n; ++i) 11560 z += 1 / (stb__t1+i); 11561 stb__t2 = z; 11562 } 11563 #else 11564 #define stb__wait(x) 11565 #endif 11566 11567 #ifdef _WIN32 11568 11569 // avoid including windows.h -- note that our definitions aren't 11570 // exactly the same (we don't define the security descriptor struct) 11571 // so if you want to include windows.h, make sure you do it first. 11572 #include <process.h> 11573 11574 #ifndef _WINDOWS_ // check windows.h guard 11575 #define STB__IMPORT STB_EXTERN __declspec(dllimport) 11576 #define STB__DW unsigned long 11577 11578 STB__IMPORT int __stdcall TerminateThread(void *, STB__DW); 11579 STB__IMPORT void * __stdcall CreateSemaphoreA(void *sec, long,long,char*); 11580 STB__IMPORT int __stdcall CloseHandle(void *); 11581 STB__IMPORT STB__DW __stdcall WaitForSingleObject(void *, STB__DW); 11582 STB__IMPORT int __stdcall ReleaseSemaphore(void *, long, long *); 11583 STB__IMPORT void __stdcall Sleep(STB__DW); 11584 #endif 11585 11586 // necessary to call this when using volatile to order writes/reads 11587 void stb_barrier(void) 11588 { 11589 #ifdef MemoryBarrier 11590 MemoryBarrier(); 11591 #else 11592 long temp; 11593 __asm xchg temp,eax; 11594 #endif 11595 } 11596 11597 static void stb__thread_run(void *t) 11598 { 11599 void *res; 11600 stb__thread info = * (stb__thread *) t; 11601 free(t); 11602 res = info.f(info.d); 11603 if (info.return_val) 11604 *info.return_val = res; 11605 if (info.sem != STB_SEMAPHORE_NULL) 11606 stb_sem_release(info.sem); 11607 } 11608 11609 static stb_thread stb_create_thread_raw(stb_thread_func f, void *d, volatile void **return_code, stb_semaphore rel) 11610 { 11611 #ifdef _MT 11612 #if defined(STB_FASTMALLOC) && !defined(STB_FASTMALLOC_ITS_OKAY_I_ONLY_MALLOC_IN_ONE_THREAD) 11613 stb_fatal("Error! Cannot use STB_FASTMALLOC with threads.\n"); 11614 return STB_THREAD_NULL; 11615 #else 11616 unsigned long id; 11617 stb__thread *data = (stb__thread *) malloc(sizeof(*data)); 11618 if (!data) return NULL; 11619 stb__threadmutex_init(); 11620 data->f = f; 11621 data->d = d; 11622 data->return_val = return_code; 11623 data->sem = rel; 11624 id = _beginthread(stb__thread_run, 0, data); 11625 if (id == -1) return NULL; 11626 return (void *) id; 11627 #endif 11628 #else 11629 #ifdef STB_NO_STB_STRINGS 11630 stb_fatal("Invalid compilation"); 11631 #else 11632 stb_fatal("Must compile mult-threaded to use stb_thread/stb_work."); 11633 #endif 11634 return NULL; 11635 #endif 11636 } 11637 11638 // trivial win32 wrappers 11639 void stb_destroy_thread(stb_thread t) { TerminateThread(t,0); } 11640 stb_semaphore stb_sem_new(int maxv) {return CreateSemaphoreA(NULL,0,maxv,NULL); } 11641 stb_semaphore stb_sem_new_extra(int maxv,int start){return CreateSemaphoreA(NULL,start,maxv,NULL); } 11642 void stb_sem_delete(stb_semaphore s) { if (s != NULL) CloseHandle(s); } 11643 void stb_sem_waitfor(stb_semaphore s) { WaitForSingleObject(s, 0xffffffff); } // INFINITE 11644 void stb_sem_release(stb_semaphore s) { ReleaseSemaphore(s,1,NULL); } 11645 static void stb__thread_sleep(int ms) { Sleep(ms); } 11646 11647 #ifndef _WINDOWS_ 11648 STB__IMPORT int __stdcall GetProcessAffinityMask(void *, STB__DW *, STB__DW *); 11649 STB__IMPORT void * __stdcall GetCurrentProcess(void); 11650 STB__IMPORT int __stdcall SetProcessAffinityMask(void *, STB__DW); 11651 #endif 11652 11653 int stb_processor_count(void) 11654 { 11655 unsigned long proc,sys; 11656 GetProcessAffinityMask(GetCurrentProcess(), &proc, &sys); 11657 return stb_bitcount(proc); 11658 } 11659 11660 void stb_force_uniprocessor(void) 11661 { 11662 unsigned long proc,sys; 11663 GetProcessAffinityMask(GetCurrentProcess(), &proc, &sys); 11664 if (stb_bitcount(proc) > 1) { 11665 int z; 11666 for (z=0; z < 32; ++z) 11667 if (proc & (1 << z)) 11668 break; 11669 if (z < 32) { 11670 proc = 1 << z; 11671 SetProcessAffinityMask(GetCurrentProcess(), proc); 11672 } 11673 } 11674 } 11675 11676 #ifdef _WINDOWS_ 11677 #define STB_MUTEX_NATIVE 11678 void *stb_mutex_new(void) 11679 { 11680 CRITICAL_SECTION *p = (CRITICAL_SECTION *) malloc(sizeof(*p)); 11681 if (p) 11682 #if _WIN32_WINNT >= 0x0500 11683 InitializeCriticalSectionAndSpinCount(p, 500); 11684 #else 11685 InitializeCriticalSection(p); 11686 #endif 11687 return p; 11688 } 11689 11690 void stb_mutex_delete(void *p) 11691 { 11692 if (p) { 11693 DeleteCriticalSection((CRITICAL_SECTION *) p); 11694 free(p); 11695 } 11696 } 11697 11698 void stb_mutex_begin(void *p) 11699 { 11700 stb__wait(500); 11701 if (p) 11702 EnterCriticalSection((CRITICAL_SECTION *) p); 11703 } 11704 11705 void stb_mutex_end(void *p) 11706 { 11707 if (p) 11708 LeaveCriticalSection((CRITICAL_SECTION *) p); 11709 stb__wait(500); 11710 } 11711 #endif // _WINDOWS_ 11712 11713 #if 0 11714 // for future reference, 11715 // InterlockedCompareExchange for x86: 11716 int cas64_mp(void * dest, void * xcmp, void * xxchg) { 11717 __asm 11718 { 11719 mov esi, [xxchg] ; exchange 11720 mov ebx, [esi + 0] 11721 mov ecx, [esi + 4] 11722 11723 mov esi, [xcmp] ; comparand 11724 mov eax, [esi + 0] 11725 mov edx, [esi + 4] 11726 11727 mov edi, [dest] ; destination 11728 lock cmpxchg8b [edi] 11729 jz yyyy; 11730 11731 mov [esi + 0], eax; 11732 mov [esi + 4], edx; 11733 11734 yyyy: 11735 xor eax, eax; 11736 setz al; 11737 }; 11738 11739 inline unsigned __int64 _InterlockedCompareExchange64(volatile unsigned __int64 *dest 11740 ,unsigned __int64 exchange 11741 ,unsigned __int64 comperand) 11742 { 11743 //value returned in eax::edx 11744 __asm { 11745 lea esi,comperand; 11746 lea edi,exchange; 11747 11748 mov eax,[esi]; 11749 mov edx,4[esi]; 11750 mov ebx,[edi]; 11751 mov ecx,4[edi]; 11752 mov esi,dest; 11753 lock CMPXCHG8B [esi]; 11754 } 11755 #endif // #if 0 11756 11757 #endif // _WIN32 11758 11759 stb_thread stb_create_thread2(stb_thread_func f, void *d, volatile void **return_code, stb_semaphore rel) 11760 { 11761 return stb_create_thread_raw(f,d,return_code,rel); 11762 } 11763 11764 stb_thread stb_create_thread(stb_thread_func f, void *d) 11765 { 11766 return stb_create_thread2(f,d,NULL,STB_SEMAPHORE_NULL); 11767 } 11768 11769 // mutex implemented by wrapping semaphore 11770 #ifndef STB_MUTEX_NATIVE 11771 stb_mutex stb_mutex_new(void) { return stb_sem_new_extra(1,1); } 11772 void stb_mutex_delete(stb_mutex m) { stb_sem_delete (m); } 11773 void stb_mutex_begin(stb_mutex m) { stb__wait(500); if (m) stb_sem_waitfor(m); } 11774 void stb_mutex_end(stb_mutex m) { if (m) stb_sem_release(m); stb__wait(500); } 11775 #endif 11776 11777 // thread merge operation 11778 struct stb__sync 11779 { 11780 int target; // target number of threads to hit it 11781 int sofar; // total threads that hit it 11782 int waiting; // total threads waiting 11783 11784 stb_mutex start; // mutex to prevent starting again before finishing previous 11785 stb_mutex mutex; // mutex while tweaking state 11786 stb_semaphore release; // semaphore wake up waiting threads 11787 // we have to wake them up one at a time, rather than using a single release 11788 // call, because win32 semaphores don't let you dynamically change the max count! 11789 }; 11790 11791 stb_sync stb_sync_new(void) 11792 { 11793 stb_sync s = (stb_sync) malloc(sizeof(*s)); 11794 if (!s) return s; 11795 11796 s->target = s->sofar = s->waiting = 0; 11797 s->mutex = stb_mutex_new(); 11798 s->start = stb_mutex_new(); 11799 s->release = stb_sem_new(1); 11800 if (s->mutex == STB_MUTEX_NULL || s->release == STB_SEMAPHORE_NULL || s->start == STB_MUTEX_NULL) { 11801 stb_mutex_delete(s->mutex); 11802 stb_mutex_delete(s->mutex); 11803 stb_sem_delete(s->release); 11804 free(s); 11805 return NULL; 11806 } 11807 return s; 11808 } 11809 11810 void stb_sync_delete(stb_sync s) 11811 { 11812 if (s->waiting) { 11813 // it's bad to delete while there are threads waiting! 11814 // shall we wait for them to reach, or just bail? just bail 11815 assert(0); 11816 } 11817 stb_mutex_delete(s->mutex); 11818 stb_mutex_delete(s->release); 11819 free(s); 11820 } 11821 11822 int stb_sync_set_target(stb_sync s, int count) 11823 { 11824 // don't allow setting a target until the last one is fully released; 11825 // note that this can lead to inefficient pipelining, and maybe we'd 11826 // be better off ping-ponging between two internal syncs? 11827 // I tried seeing how often this happened using TryEnterCriticalSection 11828 // and could _never_ get it to happen in imv(stb), even with more threads 11829 // than processors. So who knows! 11830 stb_mutex_begin(s->start); 11831 11832 // this mutex is pointless, since it's not valid for threads 11833 // to call reach() before anyone calls set_target() anyway 11834 stb_mutex_begin(s->mutex); 11835 11836 assert(s->target == 0); // enforced by start mutex 11837 s->target = count; 11838 s->sofar = 0; 11839 s->waiting = 0; 11840 stb_mutex_end(s->mutex); 11841 return STB_TRUE; 11842 } 11843 11844 void stb__sync_release(stb_sync s) 11845 { 11846 if (s->waiting) 11847 stb_sem_release(s->release); 11848 else { 11849 s->target = 0; 11850 stb_mutex_end(s->start); 11851 } 11852 } 11853 11854 int stb_sync_reach(stb_sync s) 11855 { 11856 int n; 11857 stb_mutex_begin(s->mutex); 11858 assert(s->sofar < s->target); 11859 n = ++s->sofar; // record this value to avoid possible race if we did 'return s->sofar'; 11860 if (s->sofar == s->target) 11861 stb__sync_release(s); 11862 stb_mutex_end(s->mutex); 11863 return n; 11864 } 11865 11866 void stb_sync_reach_and_wait(stb_sync s) 11867 { 11868 stb_mutex_begin(s->mutex); 11869 assert(s->sofar < s->target); 11870 ++s->sofar; 11871 if (s->sofar == s->target) { 11872 stb__sync_release(s); 11873 stb_mutex_end(s->mutex); 11874 } else { 11875 ++s->waiting; // we're waiting, so one more waiter 11876 stb_mutex_end(s->mutex); // release the mutex to other threads 11877 11878 stb_sem_waitfor(s->release); // wait for merge completion 11879 11880 stb_mutex_begin(s->mutex); // on merge completion, grab the mutex 11881 --s->waiting; // we're done waiting 11882 stb__sync_release(s); // restart the next waiter 11883 stb_mutex_end(s->mutex); // and now we're done 11884 // this ends the same as the first case, but it's a lot 11885 // clearer to understand without sharing the code 11886 } 11887 } 11888 11889 struct stb__threadqueue 11890 { 11891 stb_mutex add, remove; 11892 stb_semaphore nonempty, nonfull; 11893 int head_blockers; // number of threads blocking--used to know whether to release(avail) 11894 int tail_blockers; 11895 int head, tail, array_size, growable; 11896 int item_size; 11897 char *data; 11898 }; 11899 11900 static int stb__tq_wrap(volatile stb_threadqueue *z, int p) 11901 { 11902 if (p == z->array_size) 11903 return p - z->array_size; 11904 else 11905 return p; 11906 } 11907 11908 int stb__threadq_get_raw(stb_threadqueue *tq2, void *output, int block) 11909 { 11910 volatile stb_threadqueue *tq = (volatile stb_threadqueue *) tq2; 11911 if (tq->head == tq->tail && !block) return 0; 11912 11913 stb_mutex_begin(tq->remove); 11914 11915 while (tq->head == tq->tail) { 11916 if (!block) { 11917 stb_mutex_end(tq->remove); 11918 return 0; 11919 } 11920 ++tq->head_blockers; 11921 stb_mutex_end(tq->remove); 11922 11923 stb_sem_waitfor(tq->nonempty); 11924 11925 stb_mutex_begin(tq->remove); 11926 --tq->head_blockers; 11927 } 11928 11929 memcpy(output, tq->data + tq->head*tq->item_size, tq->item_size); 11930 stb_barrier(); 11931 tq->head = stb__tq_wrap(tq, tq->head+1); 11932 11933 stb_sem_release(tq->nonfull); 11934 if (tq->head_blockers) // can't check if actually non-empty due to race? 11935 stb_sem_release(tq->nonempty); // if there are other blockers, wake one 11936 11937 stb_mutex_end(tq->remove); 11938 return STB_TRUE; 11939 } 11940 11941 int stb__threadq_grow(volatile stb_threadqueue *tq) 11942 { 11943 int n; 11944 char *p; 11945 assert(tq->remove != STB_MUTEX_NULL); // must have this to allow growth! 11946 stb_mutex_begin(tq->remove); 11947 11948 n = tq->array_size * 2; 11949 p = (char *) realloc(tq->data, n * tq->item_size); 11950 if (p == NULL) { 11951 stb_mutex_end(tq->remove); 11952 stb_mutex_end(tq->add); 11953 return STB_FALSE; 11954 } 11955 if (tq->tail < tq->head) { 11956 memcpy(p + tq->array_size * tq->item_size, p, tq->tail * tq->item_size); 11957 tq->tail += tq->array_size; 11958 } 11959 tq->data = p; 11960 tq->array_size = n; 11961 11962 stb_mutex_end(tq->remove); 11963 return STB_TRUE; 11964 } 11965 11966 int stb__threadq_add_raw(stb_threadqueue *tq2, void *input, int block) 11967 { 11968 int tail,pos; 11969 volatile stb_threadqueue *tq = (volatile stb_threadqueue *) tq2; 11970 stb_mutex_begin(tq->add); 11971 for(;;) { 11972 pos = tq->tail; 11973 tail = stb__tq_wrap(tq, pos+1); 11974 if (tail != tq->head) break; 11975 11976 // full 11977 if (tq->growable) { 11978 if (!stb__threadq_grow(tq)) { 11979 stb_mutex_end(tq->add); 11980 return STB_FALSE; // out of memory 11981 } 11982 } else if (!block) { 11983 stb_mutex_end(tq->add); 11984 return STB_FALSE; 11985 } else { 11986 ++tq->tail_blockers; 11987 stb_mutex_end(tq->add); 11988 11989 stb_sem_waitfor(tq->nonfull); 11990 11991 stb_mutex_begin(tq->add); 11992 --tq->tail_blockers; 11993 } 11994 } 11995 memcpy(tq->data + tq->item_size * pos, input, tq->item_size); 11996 stb_barrier(); 11997 tq->tail = tail; 11998 stb_sem_release(tq->nonempty); 11999 if (tq->tail_blockers) // can't check if actually non-full due to race? 12000 stb_sem_release(tq->nonfull); 12001 stb_mutex_end(tq->add); 12002 return STB_TRUE; 12003 } 12004 12005 int stb_threadq_length(stb_threadqueue *tq2) 12006 { 12007 int a,b,n; 12008 volatile stb_threadqueue *tq = (volatile stb_threadqueue *) tq2; 12009 stb_mutex_begin(tq->add); 12010 a = tq->head; 12011 b = tq->tail; 12012 n = tq->array_size; 12013 stb_mutex_end(tq->add); 12014 if (a > b) b += n; 12015 return b-a; 12016 } 12017 12018 int stb_threadq_get(stb_threadqueue *tq, void *output) 12019 { 12020 return stb__threadq_get_raw(tq, output, STB_FALSE); 12021 } 12022 12023 void stb_threadq_get_block(stb_threadqueue *tq, void *output) 12024 { 12025 stb__threadq_get_raw(tq, output, STB_TRUE); 12026 } 12027 12028 int stb_threadq_add(stb_threadqueue *tq, void *input) 12029 { 12030 return stb__threadq_add_raw(tq, input, STB_FALSE); 12031 } 12032 12033 int stb_threadq_add_block(stb_threadqueue *tq, void *input) 12034 { 12035 return stb__threadq_add_raw(tq, input, STB_TRUE); 12036 } 12037 12038 void stb_threadq_delete(stb_threadqueue *tq) 12039 { 12040 if (tq) { 12041 free(tq->data); 12042 stb_mutex_delete(tq->add); 12043 stb_mutex_delete(tq->remove); 12044 stb_sem_delete(tq->nonempty); 12045 stb_sem_delete(tq->nonfull); 12046 free(tq); 12047 } 12048 } 12049 12050 #define STB_THREADQUEUE_DYNAMIC 0 12051 stb_threadqueue *stb_threadq_new(int item_size, int num_items, int many_add, int many_remove) 12052 { 12053 int error=0; 12054 stb_threadqueue *tq = (stb_threadqueue *) malloc(sizeof(*tq)); 12055 if (tq == NULL) return NULL; 12056 12057 if (num_items == STB_THREADQUEUE_DYNAMIC) { 12058 tq->growable = STB_TRUE; 12059 num_items = 32; 12060 } else 12061 tq->growable = STB_FALSE; 12062 12063 tq->item_size = item_size; 12064 tq->array_size = num_items+1; 12065 12066 tq->add = tq->remove = STB_MUTEX_NULL; 12067 tq->nonempty = tq->nonfull = STB_SEMAPHORE_NULL; 12068 tq->data = NULL; 12069 if (many_add) 12070 { tq->add = stb_mutex_new(); if (tq->add == STB_MUTEX_NULL) goto error; } 12071 if (many_remove || tq->growable) 12072 { tq->remove = stb_mutex_new(); if (tq->remove == STB_MUTEX_NULL) goto error; } 12073 tq->nonempty = stb_sem_new(1); if (tq->nonempty == STB_SEMAPHORE_NULL) goto error; 12074 tq->nonfull = stb_sem_new(1); if (tq->nonfull == STB_SEMAPHORE_NULL) goto error; 12075 tq->data = (char *) malloc(tq->item_size * tq->array_size); 12076 if (tq->data == NULL) goto error; 12077 12078 tq->head = tq->tail = 0; 12079 tq->head_blockers = tq->tail_blockers = 0; 12080 12081 return tq; 12082 12083 error: 12084 stb_threadq_delete(tq); 12085 return NULL; 12086 } 12087 12088 typedef struct 12089 { 12090 stb_thread_func f; 12091 void *d; 12092 volatile void **retval; 12093 stb_sync sync; 12094 } stb__workinfo; 12095 12096 //static volatile stb__workinfo *stb__work; 12097 12098 struct stb__workqueue 12099 { 12100 int numthreads; 12101 stb_threadqueue *tq; 12102 }; 12103 12104 static stb_workqueue *stb__work_global; 12105 12106 static void *stb__thread_workloop(void *p) 12107 { 12108 volatile stb_workqueue *q = (volatile stb_workqueue *) p; 12109 for(;;) { 12110 void *z; 12111 stb__workinfo w; 12112 stb_threadq_get_block(q->tq, &w); 12113 if (w.f == NULL) // null work is a signal to end the thread 12114 return NULL; 12115 z = w.f(w.d); 12116 if (w.retval) { stb_barrier(); *w.retval = z; } 12117 if (w.sync != STB_SYNC_NULL) stb_sync_reach(w.sync); 12118 } 12119 } 12120 12121 stb_workqueue *stb_workq_new(int num_threads, int max_units) 12122 { 12123 return stb_workq_new_flags(num_threads, max_units, 0,0); 12124 } 12125 12126 stb_workqueue *stb_workq_new_flags(int numthreads, int max_units, int no_add_mutex, int no_remove_mutex) 12127 { 12128 stb_workqueue *q = (stb_workqueue *) malloc(sizeof(*q)); 12129 if (q == NULL) return NULL; 12130 q->tq = stb_threadq_new(sizeof(stb__workinfo), max_units, !no_add_mutex, !no_remove_mutex); 12131 if (q->tq == NULL) { free(q); return NULL; } 12132 q->numthreads = 0; 12133 stb_workq_numthreads(q, numthreads); 12134 return q; 12135 } 12136 12137 void stb_workq_delete(stb_workqueue *q) 12138 { 12139 while (stb_workq_length(q) != 0) 12140 stb__thread_sleep(1); 12141 stb_threadq_delete(q->tq); 12142 free(q); 12143 } 12144 12145 static int stb__work_maxitems = STB_THREADQUEUE_DYNAMIC; 12146 12147 static void stb_work_init(int num_threads) 12148 { 12149 if (stb__work_global == NULL) { 12150 stb__threadmutex_init(); 12151 stb_mutex_begin(stb__workmutex); 12152 stb_barrier(); 12153 if (*(stb_workqueue * volatile *) &stb__work_global == NULL) 12154 stb__work_global = stb_workq_new(num_threads, stb__work_maxitems); 12155 stb_mutex_end(stb__workmutex); 12156 } 12157 } 12158 12159 static int stb__work_raw(stb_workqueue *q, stb_thread_func f, void *d, volatile void **return_code, stb_sync rel) 12160 { 12161 stb__workinfo w; 12162 if (q == NULL) { 12163 stb_work_init(1); 12164 q = stb__work_global; 12165 } 12166 w.f = f; 12167 w.d = d; 12168 w.retval = return_code; 12169 w.sync = rel; 12170 return stb_threadq_add(q->tq, &w); 12171 } 12172 12173 int stb_workq_length(stb_workqueue *q) 12174 { 12175 return stb_threadq_length(q->tq); 12176 } 12177 12178 int stb_workq(stb_workqueue *q, stb_thread_func f, void *d, volatile void **return_code) 12179 { 12180 if (f == NULL) return 0; 12181 return stb_workq_reach(q, f, d, return_code, NULL); 12182 } 12183 12184 int stb_workq_reach(stb_workqueue *q, stb_thread_func f, void *d, volatile void **return_code, stb_sync rel) 12185 { 12186 if (f == NULL) return 0; 12187 return stb__work_raw(q, f, d, return_code, rel); 12188 } 12189 12190 static void stb__workq_numthreads(stb_workqueue *q, int n) 12191 { 12192 while (q->numthreads < n) { 12193 stb_create_thread(stb__thread_workloop, q); 12194 ++q->numthreads; 12195 } 12196 while (q->numthreads > n) { 12197 stb__work_raw(q, NULL, NULL, NULL, NULL); 12198 --q->numthreads; 12199 } 12200 } 12201 12202 void stb_workq_numthreads(stb_workqueue *q, int n) 12203 { 12204 stb_mutex_begin(stb__threadmutex); 12205 stb__workq_numthreads(q,n); 12206 stb_mutex_end(stb__threadmutex); 12207 } 12208 12209 int stb_work_maxunits(int n) 12210 { 12211 if (stb__work_global == NULL) { 12212 stb__work_maxitems = n; 12213 stb_work_init(1); 12214 } 12215 return stb__work_maxitems; 12216 } 12217 12218 int stb_work(stb_thread_func f, void *d, volatile void **return_code) 12219 { 12220 return stb_workq(stb__work_global, f,d,return_code); 12221 } 12222 12223 int stb_work_reach(stb_thread_func f, void *d, volatile void **return_code, stb_sync rel) 12224 { 12225 return stb_workq_reach(stb__work_global, f,d,return_code,rel); 12226 } 12227 12228 void stb_work_numthreads(int n) 12229 { 12230 if (stb__work_global == NULL) 12231 stb_work_init(n); 12232 else 12233 stb_workq_numthreads(stb__work_global, n); 12234 } 12235 #endif // STB_DEFINE 12236 12237 12239 // 12240 // Background disk I/O 12241 // 12242 // 12243 12244 #define STB_BGIO_READ_ALL (-1) 12245 STB_EXTERN int stb_bgio_read (char *filename, int offset, int len, stb_uchar **result, int *olen); 12246 STB_EXTERN int stb_bgio_readf (FILE *f , int offset, int len, stb_uchar **result, int *olen); 12247 STB_EXTERN int stb_bgio_read_to (char *filename, int offset, int len, stb_uchar *buffer, int *olen); 12248 STB_EXTERN int stb_bgio_readf_to(FILE *f , int offset, int len, stb_uchar *buffer, int *olen); 12249 12250 typedef struct 12251 { 12252 int have_data; 12253 int is_valid; 12254 int is_dir; 12255 time_t filetime; 12256 stb_int64 filesize; 12257 } stb_bgstat; 12258 12259 STB_EXTERN int stb_bgio_stat (char *filename, stb_bgstat *result); 12260 12261 #ifdef STB_DEFINE 12262 12263 static stb_workqueue *stb__diskio; 12264 static stb_mutex stb__diskio_mutex; 12265 12266 void stb_thread_cleanup(void) 12267 { 12268 if (stb__work_global) stb_workq_delete(stb__work_global); stb__work_global = NULL; 12269 if (stb__threadmutex) stb_mutex_delete(stb__threadmutex); stb__threadmutex = NULL; 12270 if (stb__workmutex) stb_mutex_delete(stb__workmutex); stb__workmutex = NULL; 12271 if (stb__diskio) stb_workq_delete(stb__diskio); stb__diskio = NULL; 12272 if (stb__diskio_mutex)stb_mutex_delete(stb__diskio_mutex);stb__diskio_mutex= NULL; 12273 } 12274 12275 12276 typedef struct 12277 { 12278 char *filename; 12279 FILE *f; 12280 int offset; 12281 int len; 12282 12283 stb_bgstat *stat_out; 12284 stb_uchar *output; 12285 stb_uchar **result; 12286 int *len_output; 12287 int *flag; 12288 } stb__disk_command; 12289 12290 #define STB__MAX_DISK_COMMAND 100 12291 static stb__disk_command stb__dc_queue[STB__MAX_DISK_COMMAND]; 12292 static int stb__dc_offset; 12293 12294 void stb__io_init(void) 12295 { 12296 if (!stb__diskio) { 12297 stb__threadmutex_init(); 12298 stb_mutex_begin(stb__threadmutex); 12299 stb_barrier(); 12300 if (*(stb_thread * volatile *) &stb__diskio == NULL) { 12301 stb__diskio_mutex = stb_mutex_new(); 12302 // use many threads so OS can try to schedule seeks 12303 stb__diskio = stb_workq_new_flags(16,STB__MAX_DISK_COMMAND,STB_FALSE,STB_FALSE); 12304 } 12305 stb_mutex_end(stb__threadmutex); 12306 } 12307 } 12308 12309 static void * stb__io_error(stb__disk_command *dc) 12310 { 12311 if (dc->len_output) *dc->len_output = 0; 12312 if (dc->result) *dc->result = NULL; 12313 if (dc->flag) *dc->flag = -1; 12314 return NULL; 12315 } 12316 12317 static void * stb__io_task(void *p) 12318 { 12319 stb__disk_command *dc = (stb__disk_command *) p; 12320 int len; 12321 FILE *f; 12322 stb_uchar *buf; 12323 12324 if (dc->stat_out) { 12325 struct _stati64 s; 12326 if (!_stati64(dc->filename, &s)) { 12327 dc->stat_out->filesize = s.st_size; 12328 dc->stat_out->filetime = s.st_mtime; 12329 dc->stat_out->is_dir = s.st_mode & _S_IFDIR; 12330 dc->stat_out->is_valid = (s.st_mode & _S_IFREG) || dc->stat_out->is_dir; 12331 } else 12332 dc->stat_out->is_valid = 0; 12333 stb_barrier(); 12334 dc->stat_out->have_data = 1; 12335 free(dc->filename); 12336 return 0; 12337 } 12338 if (dc->f) { 12339 #ifdef WIN32 12340 f = _fdopen(_dup(_fileno(dc->f)), "rb"); 12341 #else 12342 f = fdopen(dup(fileno(dc->f)), "rb"); 12343 #endif 12344 if (!f) 12345 return stb__io_error(dc); 12346 } else { 12347 f = fopen(dc->filename, "rb"); 12348 free(dc->filename); 12349 if (!f) 12350 return stb__io_error(dc); 12351 } 12352 12353 len = dc->len; 12354 if (len < 0) { 12355 fseek(f, 0, SEEK_END); 12356 len = ftell(f) - dc->offset; 12357 } 12358 12359 if (fseek(f, dc->offset, SEEK_SET)) { 12360 fclose(f); 12361 return stb__io_error(dc); 12362 } 12363 12364 if (dc->output) 12365 buf = dc->output; 12366 else { 12367 buf = (stb_uchar *) malloc(len); 12368 if (buf == NULL) { 12369 fclose(f); 12370 return stb__io_error(dc); 12371 } 12372 } 12373 12374 len = fread(buf, 1, len, f); 12375 fclose(f); 12376 if (dc->len_output) *dc->len_output = len; 12377 if (dc->result) *dc->result = buf; 12378 if (dc->flag) *dc->flag = 1; 12379 12380 return NULL; 12381 } 12382 12383 int stb__io_add(char *fname, FILE *f, int off, int len, stb_uchar *out, stb_uchar **result, int *olen, int *flag, stb_bgstat *stat) 12384 { 12385 int res; 12386 stb__io_init(); 12387 // do memory allocation outside of mutex 12388 if (fname) fname = stb_p_strdup(fname); 12389 stb_mutex_begin(stb__diskio_mutex); 12390 { 12391 stb__disk_command *dc = &stb__dc_queue[stb__dc_offset]; 12392 dc->filename = fname; 12393 dc->f = f; 12394 dc->offset = off; 12395 dc->len = len; 12396 dc->output = out; 12397 dc->result = result; 12398 dc->len_output = olen; 12399 dc->flag = flag; 12400 dc->stat_out = stat; 12401 res = stb_workq(stb__diskio, stb__io_task, dc, NULL); 12402 if (res) 12403 stb__dc_offset = (stb__dc_offset + 1 == STB__MAX_DISK_COMMAND ? 0 : stb__dc_offset+1); 12404 } 12405 stb_mutex_end(stb__diskio_mutex); 12406 return res; 12407 } 12408 12409 int stb_bgio_read(char *filename, int offset, int len, stb_uchar **result, int *olen) 12410 { 12411 return stb__io_add(filename,NULL,offset,len,NULL,result,olen,NULL,NULL); 12412 } 12413 12414 int stb_bgio_readf(FILE *f, int offset, int len, stb_uchar **result, int *olen) 12415 { 12416 return stb__io_add(NULL,f,offset,len,NULL,result,olen,NULL,NULL); 12417 } 12418 12419 int stb_bgio_read_to(char *filename, int offset, int len, stb_uchar *buffer, int *olen) 12420 { 12421 return stb__io_add(filename,NULL,offset,len,buffer,NULL,olen,NULL,NULL); 12422 } 12423 12424 int stb_bgio_readf_to(FILE *f, int offset, int len, stb_uchar *buffer, int *olen) 12425 { 12426 return stb__io_add(NULL,f,offset,len,buffer,NULL,olen,NULL,NULL); 12427 } 12428 12429 STB_EXTERN int stb_bgio_stat (char *filename, stb_bgstat *result) 12430 { 12431 result->have_data = 0; 12432 return stb__io_add(filename,NULL,0,0,0,NULL,0,NULL, result); 12433 } 12434 #endif 12435 #endif 12436 12437 12438 12440 // 12441 // Fast malloc implementation 12442 // 12443 // This is a clone of TCMalloc, but without the thread support. 12444 // 1. large objects are allocated directly, page-aligned 12445 // 2. small objects are allocated in homogeonous heaps, 0 overhead 12446 // 12447 // We keep an allocation table for pages a la TCMalloc. This would 12448 // require 4MB for the entire address space, but we only allocate 12449 // the parts that are in use. The overhead from using homogenous heaps 12450 // everywhere is 3MB. (That is, if you allocate 1 object of each size, 12451 // you'll use 3MB.) 12452 12453 #if defined(STB_DEFINE) && ((defined(_WIN32) && !defined(_M_AMD64)) || defined(STB_FASTMALLOC)) 12454 12455 #ifdef _WIN32 12456 #ifndef _WINDOWS_ 12457 #ifndef STB__IMPORT 12458 #define STB__IMPORT STB_EXTERN __declspec(dllimport) 12459 #define STB__DW unsigned long 12460 #endif 12461 STB__IMPORT void * __stdcall VirtualAlloc(void *p, unsigned long size, unsigned long type, unsigned long protect); 12462 STB__IMPORT int __stdcall VirtualFree(void *p, unsigned long size, unsigned long freetype); 12463 #endif 12464 #define stb__alloc_pages_raw(x) (stb_uint32) VirtualAlloc(NULL, (x), 0x3000, 0x04) 12465 #define stb__dealloc_pages_raw(p) VirtualFree((void *) p, 0, 0x8000) 12466 #else 12467 #error "Platform not currently supported" 12468 #endif 12469 12470 typedef struct stb__span 12471 { 12472 int start, len; 12473 struct stb__span *next, *prev; 12474 void *first_free; 12475 unsigned short list; // 1..256 free; 257..511 sizeclass; 0=large block 12476 short allocations; // # outstanding allocations for sizeclass 12477 } stb__span; // 24 12478 12479 static stb__span **stb__span_for_page; 12480 static int stb__firstpage, stb__lastpage; 12481 static void stb__update_page_range(int first, int last) 12482 { 12483 stb__span **sfp; 12484 int i, f,l; 12485 if (first >= stb__firstpage && last <= stb__lastpage) return; 12486 if (stb__span_for_page == NULL) { 12487 f = first; 12488 l = f+stb_max(last-f, 16384); 12489 l = stb_min(l, 1<<20); 12490 } else if (last > stb__lastpage) { 12491 f = stb__firstpage; 12492 l = f + (stb__lastpage - f) * 2; 12493 l = stb_clamp(last, l,1<<20); 12494 } else { 12495 l = stb__lastpage; 12496 f = l - (l - stb__firstpage) * 2; 12497 f = stb_clamp(f, 0,first); 12498 } 12499 sfp = (stb__span **) stb__alloc_pages_raw(sizeof(void *) * (l-f)); 12500 for (i=f; i < stb__firstpage; ++i) sfp[i - f] = NULL; 12501 for ( ; i < stb__lastpage ; ++i) sfp[i - f] = stb__span_for_page[i - stb__firstpage]; 12502 for ( ; i < l ; ++i) sfp[i - f] = NULL; 12503 if (stb__span_for_page) stb__dealloc_pages_raw(stb__span_for_page); 12504 stb__firstpage = f; 12505 stb__lastpage = l; 12506 stb__span_for_page = sfp; 12507 } 12508 12509 static stb__span *stb__span_free=NULL; 12510 static stb__span *stb__span_first, *stb__span_end; 12511 static stb__span *stb__span_alloc(void) 12512 { 12513 stb__span *s = stb__span_free; 12514 if (s) 12515 stb__span_free = s->next; 12516 else { 12517 if (!stb__span_first) { 12518 stb__span_first = (stb__span *) stb__alloc_pages_raw(65536); 12519 if (stb__span_first == NULL) return NULL; 12520 stb__span_end = stb__span_first + (65536 / sizeof(stb__span)); 12521 } 12522 s = stb__span_first++; 12523 if (stb__span_first == stb__span_end) stb__span_first = NULL; 12524 } 12525 return s; 12526 } 12527 12528 static stb__span *stb__spanlist[512]; 12529 12530 static void stb__spanlist_unlink(stb__span *s) 12531 { 12532 if (s->prev) 12533 s->prev->next = s->next; 12534 else { 12535 int n = s->list; 12536 assert(stb__spanlist[n] == s); 12537 stb__spanlist[n] = s->next; 12538 } 12539 if (s->next) 12540 s->next->prev = s->prev; 12541 s->next = s->prev = NULL; 12542 s->list = 0; 12543 } 12544 12545 static void stb__spanlist_add(int n, stb__span *s) 12546 { 12547 s->list = n; 12548 s->next = stb__spanlist[n]; 12549 s->prev = NULL; 12550 stb__spanlist[n] = s; 12551 if (s->next) s->next->prev = s; 12552 } 12553 12554 #define stb__page_shift 12 12555 #define stb__page_size (1 << stb__page_shift) 12556 #define stb__page_number(x) ((x) >> stb__page_shift) 12557 #define stb__page_address(x) ((x) << stb__page_shift) 12558 12559 static void stb__set_span_for_page(stb__span *s) 12560 { 12561 int i; 12562 for (i=0; i < s->len; ++i) 12563 stb__span_for_page[s->start + i - stb__firstpage] = s; 12564 } 12565 12566 static stb__span *stb__coalesce(stb__span *a, stb__span *b) 12567 { 12568 assert(a->start + a->len == b->start); 12569 if (a->list) stb__spanlist_unlink(a); 12570 if (b->list) stb__spanlist_unlink(b); 12571 a->len += b->len; 12572 b->len = 0; 12573 b->next = stb__span_free; 12574 stb__span_free = b; 12575 stb__set_span_for_page(a); 12576 return a; 12577 } 12578 12579 static void stb__free_span(stb__span *s) 12580 { 12581 stb__span *n = NULL; 12582 if (s->start > stb__firstpage) { 12583 n = stb__span_for_page[s->start-1 - stb__firstpage]; 12584 if (n && n->allocations == -2 && n->start + n->len == s->start) s = stb__coalesce(n,s); 12585 } 12586 if (s->start + s->len < stb__lastpage) { 12587 n = stb__span_for_page[s->start + s->len - stb__firstpage]; 12588 if (n && n->allocations == -2 && s->start + s->len == n->start) s = stb__coalesce(s,n); 12589 } 12590 s->allocations = -2; 12591 stb__spanlist_add(s->len > 256 ? 256 : s->len, s); 12592 } 12593 12594 static stb__span *stb__alloc_pages(int num) 12595 { 12596 stb__span *s = stb__span_alloc(); 12597 int p; 12598 if (!s) return NULL; 12599 p = stb__alloc_pages_raw(num << stb__page_shift); 12600 if (p == 0) { s->next = stb__span_free; stb__span_free = s; return 0; } 12601 assert(stb__page_address(stb__page_number(p)) == p); 12602 p = stb__page_number(p); 12603 stb__update_page_range(p, p+num); 12604 s->start = p; 12605 s->len = num; 12606 s->next = NULL; 12607 s->prev = NULL; 12608 stb__set_span_for_page(s); 12609 return s; 12610 } 12611 12612 static stb__span *stb__alloc_span(int pagecount) 12613 { 12614 int i; 12615 stb__span *p = NULL; 12616 for(i=pagecount; i < 256; ++i) 12617 if (stb__spanlist[i]) { 12618 p = stb__spanlist[i]; 12619 break; 12620 } 12621 if (!p) { 12622 p = stb__spanlist[256]; 12623 while (p && p->len < pagecount) 12624 p = p->next; 12625 } 12626 if (!p) { 12627 p = stb__alloc_pages(pagecount < 16 ? 16 : pagecount); 12628 if (p == NULL) return 0; 12629 } else 12630 stb__spanlist_unlink(p); 12631 12632 if (p->len > pagecount) { 12633 stb__span *q = stb__span_alloc(); 12634 if (q) { 12635 q->start = p->start + pagecount; 12636 q->len = p->len - pagecount; 12637 p->len = pagecount; 12638 for (i=0; i < q->len; ++i) 12639 stb__span_for_page[q->start+i - stb__firstpage] = q; 12640 stb__spanlist_add(q->len > 256 ? 256 : q->len, q); 12641 } 12642 } 12643 return p; 12644 } 12645 12646 #define STB__MAX_SMALL_SIZE 32768 12647 #define STB__MAX_SIZE_CLASSES 256 12648 12649 static unsigned char stb__class_base[32]; 12650 static unsigned char stb__class_shift[32]; 12651 static unsigned char stb__pages_for_class[STB__MAX_SIZE_CLASSES]; 12652 static int stb__size_for_class[STB__MAX_SIZE_CLASSES]; 12653 12654 stb__span *stb__get_nonempty_sizeclass(int c) 12655 { 12656 int s = c + 256, i, size, tsize; // remap to span-list index 12657 char *z; 12658 void *q; 12659 stb__span *p = stb__spanlist[s]; 12660 if (p) { 12661 if (p->first_free) return p; // fast path: it's in the first one in list 12662 for (p=p->next; p; p=p->next) 12663 if (p->first_free) { 12664 // move to front for future queries 12665 stb__spanlist_unlink(p); 12666 stb__spanlist_add(s, p); 12667 return p; 12668 } 12669 } 12670 // no non-empty ones, so allocate a new one 12671 p = stb__alloc_span(stb__pages_for_class[c]); 12672 if (!p) return NULL; 12673 // create the free list up front 12674 size = stb__size_for_class[c]; 12675 tsize = stb__pages_for_class[c] << stb__page_shift; 12676 i = 0; 12677 z = (char *) stb__page_address(p->start); 12678 q = NULL; 12679 while (i + size <= tsize) { 12680 * (void **) z = q; q = z; 12681 z += size; 12682 i += size; 12683 } 12684 p->first_free = q; 12685 p->allocations = 0; 12686 stb__spanlist_add(s,p); 12687 return p; 12688 } 12689 12690 static int stb__sizeclass(size_t sz) 12691 { 12692 int z = stb_log2_floor(sz); // -1 below to group e.g. 13,14,15,16 correctly 12693 return stb__class_base[z] + ((sz-1) >> stb__class_shift[z]); 12694 } 12695 12696 static void stb__init_sizeclass(void) 12697 { 12698 int i, size, overhead; 12699 int align_shift = 2; // allow 4-byte and 12-byte blocks as well, vs. TCMalloc 12700 int next_class = 1; 12701 int last_log = 0; 12702 12703 for (i = 0; i < align_shift; i++) { 12704 stb__class_base [i] = next_class; 12705 stb__class_shift[i] = align_shift; 12706 } 12707 12708 for (size = 1 << align_shift; size <= STB__MAX_SMALL_SIZE; size += 1 << align_shift) { 12709 i = stb_log2_floor(size); 12710 if (i > last_log) { 12711 if (size == 16) ++align_shift; // switch from 4-byte to 8-byte alignment 12712 else if (size >= 128 && align_shift < 8) ++align_shift; 12713 stb__class_base[i] = next_class - ((size-1) >> align_shift); 12714 stb__class_shift[i] = align_shift; 12715 last_log = i; 12716 } 12717 stb__size_for_class[next_class++] = size; 12718 } 12719 12720 for (i=1; i <= STB__MAX_SMALL_SIZE; ++i) 12721 assert(i <= stb__size_for_class[stb__sizeclass(i)]); 12722 12723 overhead = 0; 12724 for (i = 1; i < next_class; i++) { 12725 int s = stb__size_for_class[i]; 12726 size = stb__page_size; 12727 while (size % s > size >> 3) 12728 size += stb__page_size; 12729 stb__pages_for_class[i] = (unsigned char) (size >> stb__page_shift); 12730 overhead += size; 12731 } 12732 assert(overhead < (4 << 20)); // make sure it's under 4MB of overhead 12733 } 12734 12735 #ifdef STB_DEBUG 12736 #define stb__smemset(a,b,c) memset((void *) a, b, c) 12737 #elif defined(STB_FASTMALLOC_INIT) 12738 #define stb__smemset(a,b,c) memset((void *) a, b, c) 12739 #else 12740 #define stb__smemset(a,b,c) 12741 #endif 12742 void *stb_smalloc(size_t sz) 12743 { 12744 stb__span *s; 12745 if (sz == 0) return NULL; 12746 if (stb__size_for_class[1] == 0) stb__init_sizeclass(); 12747 if (sz > STB__MAX_SMALL_SIZE) { 12748 s = stb__alloc_span((sz + stb__page_size - 1) >> stb__page_shift); 12749 if (s == NULL) return NULL; 12750 s->list = 0; 12751 s->next = s->prev = NULL; 12752 s->allocations = -32767; 12753 stb__smemset(stb__page_address(s->start), 0xcd, (sz+3)&~3); 12754 return (void *) stb__page_address(s->start); 12755 } else { 12756 void *p; 12757 int c = stb__sizeclass(sz); 12758 s = stb__spanlist[256+c]; 12759 if (!s || !s->first_free) 12760 s = stb__get_nonempty_sizeclass(c); 12761 if (s == NULL) return NULL; 12762 p = s->first_free; 12763 s->first_free = * (void **) p; 12764 ++s->allocations; 12765 stb__smemset(p,0xcd, sz); 12766 return p; 12767 } 12768 } 12769 12770 int stb_ssize(void *p) 12771 { 12772 stb__span *s; 12773 if (p == NULL) return 0; 12774 s = stb__span_for_page[stb__page_number((stb_uint) p) - stb__firstpage]; 12775 if (s->list >= 256) { 12776 return stb__size_for_class[s->list - 256]; 12777 } else { 12778 assert(s->list == 0); 12779 return s->len << stb__page_shift; 12780 } 12781 } 12782 12783 void stb_sfree(void *p) 12784 { 12785 stb__span *s; 12786 if (p == NULL) return; 12787 s = stb__span_for_page[stb__page_number((stb_uint) p) - stb__firstpage]; 12788 if (s->list >= 256) { 12789 stb__smemset(p, 0xfe, stb__size_for_class[s->list-256]); 12790 * (void **) p = s->first_free; 12791 s->first_free = p; 12792 if (--s->allocations == 0) { 12793 stb__spanlist_unlink(s); 12794 stb__free_span(s); 12795 } 12796 } else { 12797 assert(s->list == 0); 12798 stb__smemset(p, 0xfe, stb_ssize(p)); 12799 stb__free_span(s); 12800 } 12801 } 12802 12803 void *stb_srealloc(void *p, size_t sz) 12804 { 12805 size_t cur_size; 12806 if (p == NULL) return stb_smalloc(sz); 12807 if (sz == 0) { stb_sfree(p); return NULL; } 12808 cur_size = stb_ssize(p); 12809 if (sz > cur_size || sz <= (cur_size >> 1)) { 12810 void *q; 12811 if (sz > cur_size && sz < (cur_size << 1)) sz = cur_size << 1; 12812 q = stb_smalloc(sz); if (q == NULL) return NULL; 12813 memcpy(q, p, sz < cur_size ? sz : cur_size); 12814 stb_sfree(p); 12815 return q; 12816 } 12817 return p; 12818 } 12819 12820 void *stb_scalloc(size_t n, size_t sz) 12821 { 12822 void *p; 12823 if (n == 0 || sz == 0) return NULL; 12824 if (stb_log2_ceil(n) + stb_log2_ceil(n) >= 32) return NULL; 12825 p = stb_smalloc(n*sz); 12826 if (p) memset(p, 0, n*sz); 12827 return p; 12828 } 12829 12830 char *stb_sstrdup(char *s) 12831 { 12832 int n = strlen(s); 12833 char *p = (char *) stb_smalloc(n+1); 12834 if (p) stb_p_strcpy_s(p,n+1,s); 12835 return p; 12836 } 12837 #endif // STB_DEFINE 12838 12839 12840 12842 // 12843 // Source code constants 12844 // 12845 // This is a trivial system to let you specify constants in source code, 12846 // then while running you can change the constants. 12847 // 12848 // Note that you can't wrap the #defines, because we need to know their 12849 // names. So we provide a pre-wrapped version without 'STB_' for convenience; 12850 // to request it, #define STB_CONVENIENT_H, yielding: 12851 // KI -- integer 12852 // KU -- unsigned integer 12853 // KF -- float 12854 // KD -- double 12855 // KS -- string constant 12856 // 12857 // Defaults to functioning in debug build, not in release builds. 12858 // To force on, define STB_ALWAYS_H 12859 12860 #ifdef STB_CONVENIENT_H 12861 #define KI(x) STB_I(x) 12862 #define KU(x) STB_UI(x) 12863 #define KF(x) STB_F(x) 12864 #define KD(x) STB_D(x) 12865 #define KS(x) STB_S(x) 12866 #endif 12867 12868 STB_EXTERN void stb_source_path(char *str); 12869 #ifdef STB_DEFINE 12870 char *stb__source_path; 12871 void stb_source_path(char *path) 12872 { 12873 stb__source_path = path; 12874 } 12875 12876 char *stb__get_sourcefile_path(char *file) 12877 { 12878 static char filebuf[512]; 12879 if (stb__source_path) { 12880 stb_p_sprintf(filebuf stb_p_size(sizeof(filebuf)), "%s/%s", stb__source_path, file); 12881 if (stb_fexists(filebuf)) return filebuf; 12882 } 12883 12884 if (stb_fexists(file)) return file; 12885 12886 stb_p_sprintf(filebuf stb_p_size(sizeof(filebuf)), "../%s", file); 12887 if (!stb_fexists(filebuf)) return filebuf; 12888 12889 return file; 12890 } 12891 #endif 12892 12893 #define STB_F(x) ((float) STB_H(x)) 12894 #define STB_UI(x) ((unsigned int) STB_I(x)) 12895 12896 #if !defined(STB_DEBUG) && !defined(STB_ALWAYS_H) 12897 #define STB_D(x) ((double) (x)) 12898 #define STB_I(x) ((int) (x)) 12899 #define STB_S(x) ((char *) (x)) 12900 #else 12901 #define STB_D(x) stb__double_constant(__FILE__, __LINE__-1, (x)) 12902 #define STB_I(x) stb__int_constant(__FILE__, __LINE__-1, (x)) 12903 #define STB_S(x) stb__string_constant(__FILE__, __LINE__-1, (x)) 12904 12905 STB_EXTERN double stb__double_constant(char *file, int line, double x); 12906 STB_EXTERN int stb__int_constant(char *file, int line, int x); 12907 STB_EXTERN char * stb__string_constant(char *file, int line, char *str); 12908 12909 #ifdef STB_DEFINE 12910 12911 enum 12912 { 12913 STB__CTYPE_int, 12914 STB__CTYPE_uint, 12915 STB__CTYPE_float, 12916 STB__CTYPE_double, 12917 STB__CTYPE_string, 12918 }; 12919 12920 typedef struct 12921 { 12922 int line; 12923 int type; 12924 union { 12925 int ival; 12926 double dval; 12927 char *sval; 12928 }; 12929 } stb__Entry; 12930 12931 typedef struct 12932 { 12933 stb__Entry *entries; 12934 char *filename; 12935 time_t timestamp; 12936 char **file_data; 12937 int file_len; 12938 unsigned short *line_index; 12939 } stb__FileEntry; 12940 12941 static void stb__constant_parse(stb__FileEntry *f, int i) 12942 { 12943 char *s; 12944 int n; 12945 if (!stb_arr_valid(f->entries, i)) return; 12946 n = f->entries[i].line; 12947 if (n >= f->file_len) return; 12948 s = f->file_data[n]; 12949 switch (f->entries[i].type) { 12950 case STB__CTYPE_float: 12951 while (*s) { 12952 if (!strncmp(s, "STB_D(", 6)) { s+=6; goto matched_float; } 12953 if (!strncmp(s, "STB_F(", 6)) { s+=6; goto matched_float; } 12954 if (!strncmp(s, "KD(", 3)) { s+=3; goto matched_float; } 12955 if (!strncmp(s, "KF(", 3)) { s+=3; goto matched_float; } 12956 ++s; 12957 } 12958 break; 12959 matched_float: 12960 f->entries[i].dval = strtod(s, NULL); 12961 break; 12962 case STB__CTYPE_int: 12963 while (*s) { 12964 if (!strncmp(s, "STB_I(", 6)) { s+=6; goto matched_int; } 12965 if (!strncmp(s, "STB_UI(", 7)) { s+=7; goto matched_int; } 12966 if (!strncmp(s, "KI(", 3)) { s+=3; goto matched_int; } 12967 if (!strncmp(s, "KU(", 3)) { s+=3; goto matched_int; } 12968 ++s; 12969 } 12970 break; 12971 matched_int: { 12972 int neg=0; 12973 s = stb_skipwhite(s); 12974 while (*s == '-') { neg = !neg; s = stb_skipwhite(s+1); } // handle '- - 5', pointlessly 12975 if (s[0] == '0' && tolower(s[1]) == 'x') 12976 f->entries[i].ival = strtol(s, NULL, 16); 12977 else if (s[0] == '0') 12978 f->entries[i].ival = strtol(s, NULL, 8); 12979 else 12980 f->entries[i].ival = strtol(s, NULL, 10); 12981 if (neg) f->entries[i].ival = -f->entries[i].ival; 12982 break; 12983 } 12984 case STB__CTYPE_string: 12985 // @TODO 12986 break; 12987 } 12988 } 12989 12990 static stb_sdict *stb__constant_file_hash; 12991 12992 stb__Entry *stb__constant_get_entry(char *filename, int line, int type) 12993 { 12994 int i; 12995 stb__FileEntry *f; 12996 if (stb__constant_file_hash == NULL) 12997 stb__constant_file_hash = stb_sdict_new(STB_TRUE); 12998 f = (stb__FileEntry*) stb_sdict_get(stb__constant_file_hash, filename); 12999 if (f == NULL) { 13000 char *s = stb__get_sourcefile_path(filename); 13001 if (s == NULL || !stb_fexists(s)) return 0; 13002 f = (stb__FileEntry *) malloc(sizeof(*f)); 13003 f->timestamp = stb_ftimestamp(s); 13004 f->file_data = stb_stringfile(s, &f->file_len); 13005 f->filename = stb_p_strdup(s); // cache the full path 13006 f->entries = NULL; 13007 f->line_index = 0; 13008 stb_arr_setlen(f->line_index, f->file_len); 13009 memset(f->line_index, 0xff, stb_arr_storage(f->line_index)); 13010 } else { 13011 time_t t = stb_ftimestamp(f->filename); 13012 if (f->timestamp != t) { 13013 f->timestamp = t; 13014 free(f->file_data); 13015 f->file_data = stb_stringfile(f->filename, &f->file_len); 13016 stb_arr_setlen(f->line_index, f->file_len); 13017 for (i=0; i < stb_arr_len(f->entries); ++i) 13018 stb__constant_parse(f, i); 13019 } 13020 } 13021 13022 if (line >= f->file_len) return 0; 13023 13024 if (f->line_index[line] >= stb_arr_len(f->entries)) { 13025 // need a new entry 13026 int n = stb_arr_len(f->entries); 13027 stb__Entry e; 13028 e.line = line; 13029 if (line < f->file_len) 13030 f->line_index[line] = n; 13031 e.type = type; 13032 stb_arr_push(f->entries, e); 13033 stb__constant_parse(f, n); 13034 } 13035 return f->entries + f->line_index[line]; 13036 } 13037 13038 double stb__double_constant(char *file, int line, double x) 13039 { 13040 stb__Entry *e = stb__constant_get_entry(file, line, STB__CTYPE_float); 13041 if (!e) return x; 13042 return e->dval; 13043 } 13044 13045 int stb__int_constant(char *file, int line, int x) 13046 { 13047 stb__Entry *e = stb__constant_get_entry(file, line, STB__CTYPE_int); 13048 if (!e) return x; 13049 return e->ival; 13050 } 13051 13052 char * stb__string_constant(char *file, int line, char *x) 13053 { 13054 stb__Entry *e = stb__constant_get_entry(file, line, STB__CTYPE_string); 13055 if (!e) return x; 13056 return e->sval; 13057 } 13058 13059 #endif // STB_DEFINE 13060 #endif // !STB_DEBUG && !STB_ALWAYS_H 13061 13062 13063 #ifdef STB_STUA 13064 #error "STUA is no longer supported" 13065 13066 // 13067 // stua: little scripting language 13068 // 13069 // define STB_STUA to compile it 13070 // 13071 // see http://nothings.org/stb/stb_stua.html for documentation 13072 // 13073 // basic parsing model: 13074 // 13075 // lexical analysis 13076 // use stb_lex() to parse tokens; keywords get their own tokens 13077 // 13078 // parsing: 13079 // recursive descent parser. too much of a hassle to make an unambiguous 13080 // LR(1) grammar, and one-pass generation is clumsier (recursive descent 13081 // makes it easier to e.g. compile nested functions). on the other hand, 13082 // dictionary syntax required hackery to get extra lookahead. 13083 // 13084 // codegen: 13085 // output into an evaluation tree, using array indices as 'pointers' 13086 // 13087 // run: 13088 // traverse the tree; support for 'break/continue/return' is tricky 13089 // 13090 // garbage collection: 13091 // stu__mark and sweep; explicit stack with non-stu__compile_global_scope roots 13092 13093 typedef stb_int32 stua_obj; 13094 13095 typedef stb_idict stua_dict; 13096 13097 STB_EXTERN void stua_run_script(char *s); 13098 STB_EXTERN void stua_uninit(void); 13099 13100 extern stua_obj stua_globals; 13101 13102 STB_EXTERN double stua_number(stua_obj z); 13103 13104 STB_EXTERN stua_obj stua_getnil(void); 13105 STB_EXTERN stua_obj stua_getfalse(void); 13106 STB_EXTERN stua_obj stua_gettrue(void); 13107 STB_EXTERN stua_obj stua_string(char *z); 13108 STB_EXTERN stua_obj stua_make_number(double d); 13109 STB_EXTERN stua_obj stua_box(int type, void *data, int size); 13110 13111 enum 13112 { 13113 STUA_op_negate=129, 13114 STUA_op_shl, STUA_op_ge, 13115 STUA_op_shr, STUA_op_le, 13116 STUA_op_shru, 13117 STUA_op_last 13118 }; 13119 13120 #define STUA_NO_VALUE 2 // equivalent to a tagged NULL 13121 STB_EXTERN stua_obj (*stua_overload)(int op, stua_obj a, stua_obj b, stua_obj c); 13122 13123 STB_EXTERN stua_obj stua_error(char *err, ...); 13124 13125 STB_EXTERN stua_obj stua_pushroot(stua_obj o); 13126 STB_EXTERN void stua_poproot ( void ); 13127 13128 13129 #ifdef STB_DEFINE 13130 // INTERPRETER 13131 13132 // 31-bit floating point implementation 13133 // force the (1 << 30) bit (2nd highest bit) to be zero by re-biasing the exponent; 13134 // then shift and set the bottom bit 13135 13136 static stua_obj stu__floatp(float *f) 13137 { 13138 unsigned int n = *(unsigned int *) f; 13139 unsigned int e = n & (0xff << 23); 13140 13141 assert(sizeof(int) == 4 && sizeof(float) == 4); 13142 13143 if (!e) // zero? 13144 n = n; // no change 13145 else if (e < (64 << 23)) // underflow of the packed encoding? 13146 n = (n & 0x80000000); // signed 0 13147 else if (e > (190 << 23)) // overflow of the encoding? (or INF or NAN) 13148 n = (n & 0x80000000) + (127 << 23); // new INF encoding 13149 else 13150 n -= 0x20000000; 13151 13152 // now we need to shuffle the bits so that the spare bit is at the bottom 13153 assert((n & 0x40000000) == 0); 13154 return (n & 0x80000000) + (n << 1) + 1; 13155 } 13156 13157 static unsigned char stu__getfloat_addend[256]; 13158 static float stu__getfloat(stua_obj v) 13159 { 13160 unsigned int n; 13161 unsigned int e = ((unsigned int) v) >> 24; 13162 13163 n = (int) v >> 1; // preserve high bit 13164 n += stu__getfloat_addend[e] << 24; 13165 return *(float *) &n; 13166 } 13167 13168 stua_obj stua_float(float f) 13169 { 13170 return stu__floatp(&f); 13171 } 13172 13173 static void stu__float_init(void) 13174 { 13175 int i; 13176 stu__getfloat_addend[0] = 0; // do nothing to biased exponent of 0 13177 for (i=1; i < 127; ++i) 13178 stu__getfloat_addend[i] = 32; // undo the -0x20000000 13179 stu__getfloat_addend[127] = 64; // convert packed INF to INF (0x3f -> 0x7f) 13180 13181 for (i=0; i < 128; ++i) // for signed floats, remove the bit we just shifted down 13182 stu__getfloat_addend[128+i] = stu__getfloat_addend[i] - 64; 13183 } 13184 13185 // Tagged data type implementation 13186 13187 // TAGS: 13188 #define stu__int_tag 0 // of 2 bits // 00 int 13189 #define stu__float_tag 1 // of 1 bit // 01 float 13190 #define stu__ptr_tag 2 // of 2 bits // 10 boxed 13191 // 11 float 13192 13193 #define stu__tag(x) ((x) & 3) 13194 #define stu__number(x) (stu__tag(x) != stu__ptr_tag) 13195 #define stu__isint(x) (stu__tag(x) == stu__int_tag) 13196 13197 #define stu__int(x) ((x) >> 2) 13198 #define stu__float(x) (stu__getfloat(x)) 13199 13200 #define stu__makeint(v) ((v)*4+stu__int_tag) 13201 13202 // boxed data, and tag support for boxed data 13203 13204 enum 13205 { 13206 STU___float = 1, STU___int = 2, 13207 STU___number = 3, STU___string = 4, 13208 STU___function = 5, STU___dict = 6, 13209 STU___boolean = 7, STU___error = 8, 13210 }; 13211 13212 // boxed data 13213 #define STU__BOX short type, stua_gc 13214 typedef struct stu__box { STU__BOX; } stu__box; 13215 13216 stu__box stu__nil = { 0, 1 }; 13217 stu__box stu__true = { STU___boolean, 1, }; 13218 stu__box stu__false = { STU___boolean, 1, }; 13219 13220 #define stu__makeptr(v) ((stua_obj) (v) + stu__ptr_tag) 13221 13222 #define stua_nil stu__makeptr(&stu__nil) 13223 #define stua_true stu__makeptr(&stu__true) 13224 #define stua_false stu__makeptr(&stu__false) 13225 13226 stua_obj stua_getnil(void) { return stua_nil; } 13227 stua_obj stua_getfalse(void) { return stua_false; } 13228 stua_obj stua_gettrue(void) { return stua_true; } 13229 13230 #define stu__ptr(x) ((stu__box *) ((x) - stu__ptr_tag)) 13231 13232 #define stu__checkt(t,x) ((t) == STU___float ? ((x) & 1) == stu__float_tag : \ 13233 (t) == STU___int ? stu__isint(x) : \ 13234 (t) == STU___number ? stu__number(x) : \ 13235 stu__tag(x) == stu__ptr_tag && stu__ptr(x)->type == (t)) 13236 13237 typedef struct 13238 { 13239 STU__BOX; 13240 void *ptr; 13241 } stu__wrapper; 13242 13243 // implementation of a 'function' or function + closure 13244 13245 typedef struct stu__func 13246 { 13247 STU__BOX; 13248 stua_obj closure_source; // 0 - regular function; 4 - C function 13249 // if closure, pointer to source function 13250 union { 13251 stua_obj closure_data; // partial-application data 13252 void *store; // pointer to free that holds 'code' 13253 stua_obj (*func)(stua_dict *context); 13254 } f; 13255 // closure ends here 13256 short *code; 13257 int num_param; 13258 stua_obj *param; // list of parameter strings 13259 } stu__func; 13260 13261 // apply this to 'short *code' to get at data 13262 #define stu__const(f) ((stua_obj *) (f)) 13263 13264 static void stu__free_func(stu__func *f) 13265 { 13266 if (f->closure_source == 0) free(f->f.store); 13267 if ((stb_uint) f->closure_source <= 4) free(f->param); 13268 free(f); 13269 } 13270 13271 #define stu__pd(x) ((stua_dict *) stu__ptr(x)) 13272 #define stu__pw(x) ((stu__wrapper *) stu__ptr(x)) 13273 #define stu__pf(x) ((stu__func *) stu__ptr(x)) 13274 13275 13276 // garbage-collection 13277 13278 13279 static stu__box ** stu__gc_ptrlist; 13280 static stua_obj * stu__gc_root_stack; 13281 13282 stua_obj stua_pushroot(stua_obj o) { stb_arr_push(stu__gc_root_stack, o); return o; } 13283 void stua_poproot ( void ) { stb_arr_pop(stu__gc_root_stack); } 13284 13285 static stb_sdict *stu__strings; 13286 static void stu__mark(stua_obj z) 13287 { 13288 int i; 13289 stu__box *p = stu__ptr(z); 13290 if (p->stua_gc == 1) return; // already marked 13291 assert(p->stua_gc == 0); 13292 p->stua_gc = 1; 13293 switch(p->type) { 13294 case STU___function: { 13295 stu__func *f = (stu__func *) p; 13296 if ((stb_uint) f->closure_source <= 4) { 13297 if (f->closure_source == 0) { 13298 for (i=1; i <= f->code[0]; ++i) 13299 if (!stu__number(((stua_obj *) f->code)[-i])) 13300 stu__mark(((stua_obj *) f->code)[-i]); 13301 } 13302 for (i=0; i < f->num_param; ++i) 13303 stu__mark(f->param[i]); 13304 } else { 13305 stu__mark(f->closure_source); 13306 stu__mark(f->f.closure_data); 13307 } 13308 break; 13309 } 13310 case STU___dict: { 13311 stua_dict *e = (stua_dict *) p; 13312 for (i=0; i < e->limit; ++i) 13313 if (e->table[i].k != STB_IEMPTY && e->table[i].k != STB_IDEL) { 13314 if (!stu__number(e->table[i].k)) stu__mark((int) e->table[i].k); 13315 if (!stu__number(e->table[i].v)) stu__mark((int) e->table[i].v); 13316 } 13317 break; 13318 } 13319 } 13320 } 13321 13322 static int stu__num_allocs, stu__size_allocs; 13323 static stua_obj stu__flow_val = stua_nil; // used for break & return 13324 13325 static void stua_gc(int force) 13326 { 13327 int i; 13328 if (!force && stu__num_allocs == 0 && stu__size_allocs == 0) return; 13329 stu__num_allocs = stu__size_allocs = 0; 13330 //printf("[gc]\n"); 13331 13332 // clear marks 13333 for (i=0; i < stb_arr_len(stu__gc_ptrlist); ++i) 13334 stu__gc_ptrlist[i]->stua_gc = 0; 13335 13336 // stu__mark everything reachable 13337 stu__nil.stua_gc = stu__true.stua_gc = stu__false.stua_gc = 1; 13338 stu__mark(stua_globals); 13339 if (!stu__number(stu__flow_val)) 13340 stu__mark(stu__flow_val); 13341 for (i=0; i < stb_arr_len(stu__gc_root_stack); ++i) 13342 if (!stu__number(stu__gc_root_stack[i])) 13343 stu__mark(stu__gc_root_stack[i]); 13344 13345 // sweep unreachables 13346 for (i=0; i < stb_arr_len(stu__gc_ptrlist);) { 13347 stu__box *z = stu__gc_ptrlist[i]; 13348 if (!z->stua_gc) { 13349 switch (z->type) { 13350 case STU___dict: stb_idict_destroy((stua_dict *) z); break; 13351 case STU___error: free(((stu__wrapper *) z)->ptr); break; 13352 case STU___string: stb_sdict_remove(stu__strings, (char*) ((stu__wrapper *) z)->ptr, NULL); free(z); break; 13353 case STU___function: stu__free_func((stu__func *) z); break; 13354 } 13355 // swap in the last item over this, and repeat 13356 z = stb_arr_pop(stu__gc_ptrlist); 13357 stu__gc_ptrlist[i] = z; 13358 } else 13359 ++i; 13360 } 13361 } 13362 13363 static void stu__consider_gc(stua_obj x) 13364 { 13365 if (stu__size_allocs < 100000) return; 13366 if (stu__num_allocs < 10 && stu__size_allocs < 1000000) return; 13367 stb_arr_push(stu__gc_root_stack, x); 13368 stua_gc(0); 13369 stb_arr_pop(stu__gc_root_stack); 13370 } 13371 13372 static stua_obj stu__makeobj(int type, void *data, int size, int safe_to_gc) 13373 { 13374 stua_obj x = stu__makeptr(data); 13375 ((stu__box *) data)->type = type; 13376 stb_arr_push(stu__gc_ptrlist, (stu__box *) data); 13377 stu__num_allocs += 1; 13378 stu__size_allocs += size; 13379 if (safe_to_gc) stu__consider_gc(x); 13380 return x; 13381 } 13382 13383 stua_obj stua_box(int type, void *data, int size) 13384 { 13385 stu__wrapper *p = (stu__wrapper *) malloc(sizeof(*p)); 13386 p->ptr = data; 13387 return stu__makeobj(type, p, size, 0); 13388 } 13389 13390 // a stu string can be directly compared for equality, because 13391 // they go into a hash table 13392 stua_obj stua_string(char *z) 13393 { 13394 stu__wrapper *b = (stu__wrapper *) stb_sdict_get(stu__strings, z); 13395 if (b == NULL) { 13396 int o = stua_box(STU___string, NULL, strlen(z) + sizeof(*b)); 13397 b = stu__pw(o); 13398 stb_sdict_add(stu__strings, z, b); 13399 stb_sdict_getkey(stu__strings, z, (char **) &b->ptr); 13400 } 13401 return stu__makeptr(b); 13402 } 13403 13404 // stb_obj dictionary is just an stb_idict 13405 static void stu__set(stua_dict *d, stua_obj k, stua_obj v) 13406 { if (stb_idict_set(d, k, v)) stu__size_allocs += 8; } 13407 13408 static stua_obj stu__get(stua_dict *d, stua_obj k, stua_obj res) 13409 { 13410 stb_idict_get_flag(d, k, &res); 13411 return res; 13412 } 13413 13414 static stua_obj make_string(char *z, int len) 13415 { 13416 stua_obj s; 13417 char temp[256], *q = (char *) stb_temp(temp, len+1), *p = q; 13418 while (len > 0) { 13419 if (*z == '\\') { 13420 if (z[1] == 'n') *p = '\n'; 13421 else if (z[1] == 'r') *p = '\r'; 13422 else if (z[1] == 't') *p = '\t'; 13423 else *p = z[1]; 13424 p += 1; z += 2; len -= 2; 13425 } else { 13426 *p++ = *z++; len -= 1; 13427 } 13428 } 13429 *p = 0; 13430 s = stua_string(q); 13431 stb_tempfree(temp, q); 13432 return s; 13433 } 13434 13435 enum token_names 13436 { 13437 T__none=128, 13438 ST_shl = STUA_op_shl, ST_ge = STUA_op_ge, 13439 ST_shr = STUA_op_shr, ST_le = STUA_op_le, 13440 ST_shru = STUA_op_shru, STU__negate = STUA_op_negate, 13441 ST__reset_numbering = STUA_op_last, 13442 ST_white, 13443 ST_id, ST_float, ST_decimal, ST_hex, ST_char,ST_string, ST_number, 13444 // make sure the keywords come _AFTER_ ST_id, so stb_lex prefer them 13445 ST_if, ST_while, ST_for, ST_eq, ST_nil, 13446 ST_then, ST_do, ST_in, ST_ne, ST_true, 13447 ST_else, ST_break, ST_let, ST_and, ST_false, 13448 ST_elseif, ST_continue, ST_into, ST_or, ST_repeat, 13449 ST_end, ST_as, ST_return, ST_var, ST_func, 13450 ST_catch, ST__frame, 13451 ST__max_terminals, 13452 13453 STU__defaultparm, STU__seq, 13454 }; 13455 13456 static stua_dict * stu__globaldict; 13457 stua_obj stua_globals; 13458 13459 static enum 13460 { 13461 FLOW_normal, FLOW_continue, FLOW_break, FLOW_return, FLOW_error, 13462 } stu__flow; 13463 13464 stua_obj stua_error(char *z, ...) 13465 { 13466 stua_obj a; 13467 char temp[4096], *x; 13468 va_list v; va_start(v,z); vsprintf(temp, z, v); va_end(v); 13469 x = stb_p_strdup(temp); 13470 a = stua_box(STU___error, x, strlen(x)); 13471 stu__flow = FLOW_error; 13472 stu__flow_val = a; 13473 return stua_nil; 13474 } 13475 13476 double stua_number(stua_obj z) 13477 { 13478 return stu__tag(z) == stu__int_tag ? stu__int(z) : stu__float(z); 13479 } 13480 13481 stua_obj stua_make_number(double d) 13482 { 13483 double e = floor(d); 13484 if (e == d && e < (1 << 29) && e >= -(1 << 29)) 13485 return stu__makeint((int) e); 13486 else 13487 return stua_float((float) d); 13488 } 13489 13490 stua_obj (*stua_overload)(int op, stua_obj a, stua_obj b, stua_obj c) = NULL; 13491 13492 static stua_obj stu__op(int op, stua_obj a, stua_obj b, stua_obj c) 13493 { 13494 stua_obj r = STUA_NO_VALUE; 13495 if (op == '+') { 13496 if (stu__checkt(STU___string, a) && stu__checkt(STU___string, b)) { 13497 ;// @TODO: string concatenation 13498 } else if (stu__checkt(STU___function, a) && stu__checkt(STU___dict, b)) { 13499 stu__func *f = (stu__func *) malloc(12); 13500 assert(offsetof(stu__func, code)==12); 13501 f->closure_source = a; 13502 f->f.closure_data = b; 13503 return stu__makeobj(STU___function, f, 16, 1); 13504 } 13505 } 13506 if (stua_overload) r = stua_overload(op,a,b,c); 13507 if (stu__flow != FLOW_error && r == STUA_NO_VALUE) 13508 stua_error("Typecheck for operator %d", op), r=stua_nil; 13509 return r; 13510 } 13511 13512 #define STU__EVAL2(a,b) \ 13513 a = stu__eval(stu__f[n+1]); if (stu__flow) break; stua_pushroot(a); \ 13514 b = stu__eval(stu__f[n+2]); stua_poproot(); if (stu__flow) break; 13515 13516 #define STU__FB(op) \ 13517 STU__EVAL2(a,b) \ 13518 if (stu__tag(a) == stu__int_tag && stu__tag(b) == stu__int_tag) \ 13519 return ((a) op (b)); \ 13520 if (stu__number(a) && stu__number(b)) \ 13521 return stua_make_number(stua_number(a) op stua_number(b)); \ 13522 return stu__op(stu__f[n], a,b, stua_nil) 13523 13524 #define STU__F(op) \ 13525 STU__EVAL2(a,b) \ 13526 if (stu__number(a) && stu__number(b)) \ 13527 return stua_make_number(stua_number(a) op stua_number(b)); \ 13528 return stu__op(stu__f[n], a,b, stua_nil) 13529 13530 #define STU__I(op) \ 13531 STU__EVAL2(a,b) \ 13532 if (stu__tag(a) == stu__int_tag && stu__tag(b) == stu__int_tag) \ 13533 return stu__makeint(stu__int(a) op stu__int(b)); \ 13534 return stu__op(stu__f[n], a,b, stua_nil) 13535 13536 #define STU__C(op) \ 13537 STU__EVAL2(a,b) \ 13538 if (stu__number(a) && stu__number(b)) \ 13539 return (stua_number(a) op stua_number(b)) ? stua_true : stua_false; \ 13540 return stu__op(stu__f[n], a,b, stua_nil) 13541 13542 #define STU__CE(op) \ 13543 STU__EVAL2(a,b) \ 13544 return (a op b) ? stua_true : stua_false 13545 13546 static short *stu__f; 13547 static stua_obj stu__f_obj; 13548 static stua_dict *stu__c; 13549 static stua_obj stu__funceval(stua_obj fo, stua_obj co); 13550 13551 static int stu__cond(stua_obj x) 13552 { 13553 if (stu__flow) return 0; 13554 if (!stu__checkt(STU___boolean, x)) 13555 x = stu__op('!', x, stua_nil, stua_nil); 13556 if (x == stua_true ) return 1; 13557 if (x == stua_false) return 0; 13558 stu__flow = FLOW_error; 13559 return 0; 13560 } 13561 13562 // had to manually eliminate tailcall recursion for debugging complex stuff 13563 #define TAILCALL(x) n = (x); goto top; 13564 static stua_obj stu__eval(int n) 13565 { 13566 top: 13567 if (stu__flow >= FLOW_return) return stua_nil; // is this needed? 13568 if (n < 0) return stu__const(stu__f)[n]; 13569 assert(n != 0 && n != 1); 13570 switch (stu__f[n]) { 13571 stua_obj a,b,c; 13572 case ST_catch: a = stu__eval(stu__f[n+1]); 13573 if (stu__flow == FLOW_error) { a=stu__flow_val; stu__flow = FLOW_normal; } 13574 return a; 13575 case ST_var: b = stu__eval(stu__f[n+2]); if (stu__flow) break; 13576 stu__set(stu__c, stu__const(stu__f)[stu__f[n+1]], b); 13577 return b; 13578 case STU__seq: stu__eval(stu__f[n+1]); if (stu__flow) break; 13579 TAILCALL(stu__f[n+2]); 13580 case ST_if: if (!stu__cond(stu__eval(stu__f[n+1]))) return stua_nil; 13581 TAILCALL(stu__f[n+2]); 13582 case ST_else: a = stu__cond(stu__eval(stu__f[n+1])); 13583 TAILCALL(stu__f[n + 2 + !a]); 13584 #define STU__HANDLE_BREAK \ 13585 if (stu__flow >= FLOW_break) { \ 13586 if (stu__flow == FLOW_break) { \ 13587 a = stu__flow_val; \ 13588 stu__flow = FLOW_normal; \ 13589 stu__flow_val = stua_nil; \ 13590 return a; \ 13591 } \ 13592 return stua_nil; \ 13593 } 13594 case ST_as: stu__eval(stu__f[n+3]); 13595 STU__HANDLE_BREAK 13596 // fallthrough! 13597 case ST_while: a = stua_nil; stua_pushroot(a); 13598 while (stu__cond(stu__eval(stu__f[n+1]))) { 13599 stua_poproot(); 13600 a = stu__eval(stu__f[n+2]); 13601 STU__HANDLE_BREAK 13602 stu__flow = FLOW_normal; // clear 'continue' flag 13603 stua_pushroot(a); 13604 if (stu__f[n+3]) stu__eval(stu__f[n+3]); 13605 STU__HANDLE_BREAK 13606 stu__flow = FLOW_normal; // clear 'continue' flag 13607 } 13608 stua_poproot(); 13609 return a; 13610 case ST_break: stu__flow = FLOW_break; stu__flow_val = stu__eval(stu__f[n+1]); break; 13611 case ST_continue:stu__flow = FLOW_continue; break; 13612 case ST_return: stu__flow = FLOW_return; stu__flow_val = stu__eval(stu__f[n+1]); break; 13613 case ST__frame: return stu__f_obj; 13614 case '[': STU__EVAL2(a,b); 13615 if (stu__checkt(STU___dict, a)) 13616 return stu__get(stu__pd(a), b, stua_nil); 13617 return stu__op(stu__f[n], a, b, stua_nil); 13618 case '=': a = stu__eval(stu__f[n+2]); if (stu__flow) break; 13619 n = stu__f[n+1]; 13620 if (stu__f[n] == ST_id) { 13621 if (!stb_idict_update(stu__c, stu__const(stu__f)[stu__f[n+1]], a)) 13622 if (!stb_idict_update(stu__globaldict, stu__const(stu__f)[stu__f[n+1]], a)) 13623 return stua_error("Assignment to undefined variable"); 13624 } else if (stu__f[n] == '[') { 13625 stua_pushroot(a); 13626 b = stu__eval(stu__f[n+1]); if (stu__flow) { stua_poproot(); break; } 13627 stua_pushroot(b); 13628 c = stu__eval(stu__f[n+2]); stua_poproot(); stua_poproot(); 13629 if (stu__flow) break; 13630 if (!stu__checkt(STU___dict, b)) return stua_nil; 13631 stu__set(stu__pd(b), c, a); 13632 } else { 13633 return stu__op(stu__f[n], stu__eval(n), a, stua_nil); 13634 } 13635 return a; 13636 case STU__defaultparm: 13637 a = stu__eval(stu__f[n+2]); 13638 stu__flow = FLOW_normal; 13639 if (stb_idict_add(stu__c, stu__const(stu__f)[stu__f[n+1]], a)) 13640 stu__size_allocs += 8; 13641 return stua_nil; 13642 case ST_id: a = stu__get(stu__c, stu__const(stu__f)[stu__f[n+1]], STUA_NO_VALUE); // try local variable 13643 return a != STUA_NO_VALUE // else try stu__compile_global_scope variable 13644 ? a : stu__get(stu__globaldict, stu__const(stu__f)[stu__f[n+1]], stua_nil); 13645 case STU__negate:a = stu__eval(stu__f[n+1]); if (stu__flow) break; 13646 return stu__isint(a) ? -a : stu__op(stu__f[n], a, stua_nil, stua_nil); 13647 case '~': a = stu__eval(stu__f[n+1]); if (stu__flow) break; 13648 return stu__isint(a) ? (~a)&~3 : stu__op(stu__f[n], a, stua_nil, stua_nil); 13649 case '!': a = stu__eval(stu__f[n+1]); if (stu__flow) break; 13650 a = stu__cond(a); if (stu__flow) break; 13651 return a ? stua_true : stua_false; 13652 case ST_eq: STU__CE(==); case ST_le: STU__C(<=); case '<': STU__C(<); 13653 case ST_ne: STU__CE(!=); case ST_ge: STU__C(>=); case '>': STU__C(>); 13654 case '+' : STU__FB(+); case '*': STU__F(*); case '&': STU__I(&); case ST_shl: STU__I(<<); 13655 case '-' : STU__FB(-); case '/': STU__F(/); case '|': STU__I(|); case ST_shr: STU__I(>>); 13656 case '%': STU__I(%); case '^': STU__I(^); 13657 case ST_shru: STU__EVAL2(a,b); 13658 if (stu__tag(a) == stu__int_tag && stu__tag(b) == stu__int_tag) 13659 return stu__makeint((unsigned) stu__int(a) >> stu__int(b)); 13660 return stu__op(stu__f[n], a,b, stua_nil); 13661 case ST_and: a = stu__eval(stu__f[n+1]); b = stu__cond(a); if (stu__flow) break; 13662 return a ? stu__eval(stu__f[n+2]) : a; 13663 case ST_or : a = stu__eval(stu__f[n+1]); b = stu__cond(a); if (stu__flow) break; 13664 return a ? b : stu__eval(stu__f[n+2]); 13665 case'(':case':': STU__EVAL2(a,b); 13666 if (!stu__checkt(STU___function, a)) 13667 return stu__op(stu__f[n], a,b, stua_nil); 13668 if (!stu__checkt(STU___dict, b)) 13669 return stua_nil; 13670 if (stu__f[n] == ':') 13671 b = stu__makeobj(STU___dict, stb_idict_copy(stu__pd(b)), stb_idict_memory_usage(stu__pd(b)), 0); 13672 a = stu__funceval(a,b); 13673 return a; 13674 case '{' : { 13675 stua_dict *d; 13676 d = stb_idict_new_size(stu__f[n+1] > 40 ? 64 : 16); 13677 if (d == NULL) 13678 return stua_nil; // breakpoint fodder 13679 c = stu__makeobj(STU___dict, d, 32, 1); 13680 stua_pushroot(c); 13681 a = stu__f[n+1]; 13682 for (b=0; b < a; ++b) { 13683 stua_obj x = stua_pushroot(stu__eval(stu__f[n+2 + b*2 + 0])); 13684 stua_obj y = stu__eval(stu__f[n+2 + b*2 + 1]); 13685 stua_poproot(); 13686 if (stu__flow) { stua_poproot(); return stua_nil; } 13687 stu__set(d, x, y); 13688 } 13689 stua_poproot(); 13690 return c; 13691 } 13692 default: if (stu__f[n] < 0) return stu__const(stu__f)[stu__f[n]]; 13693 assert(0); /* NOTREACHED */ // internal error! 13694 } 13695 return stua_nil; 13696 } 13697 13698 int stb__stua_nesting; 13699 static stua_obj stu__funceval(stua_obj fo, stua_obj co) 13700 { 13701 stu__func *f = stu__pf(fo); 13702 stua_dict *context = stu__pd(co); 13703 int i,j; 13704 stua_obj p; 13705 short *tf = stu__f; // save previous function 13706 stua_dict *tc = stu__c; 13707 13708 if (stu__flow == FLOW_error) return stua_nil; 13709 assert(stu__flow == FLOW_normal); 13710 13711 stua_pushroot(fo); 13712 stua_pushroot(co); 13713 stu__consider_gc(stua_nil); 13714 13715 while ((stb_uint) f->closure_source > 4) { 13716 // add data from closure to context 13717 stua_dict *e = (stua_dict *) stu__pd(f->f.closure_data); 13718 for (i=0; i < e->limit; ++i) 13719 if (e->table[i].k != STB_IEMPTY && e->table[i].k != STB_IDEL) 13720 if (stb_idict_add(context, e->table[i].k, e->table[i].v)) 13721 stu__size_allocs += 8; 13722 // use add so if it's already defined, we don't override it; that way 13723 // explicit parameters win over applied ones, and most recent applications 13724 // win over previous ones 13725 f = stu__pf(f->closure_source); 13726 } 13727 13728 for (j=0, i=0; i < f->num_param; ++i) 13729 // if it doesn't already exist, add it from the numbered parameters 13730 if (stb_idict_add(context, f->param[i], stu__get(context, stu__int(j), stua_nil))) 13731 ++j; 13732 13733 // @TODO: if (stu__get(context, stu__int(f->num_param+1)) != STUA_NO_VALUE) // error: too many parameters 13734 // @TODO: ditto too few parameters 13735 13736 if (f->closure_source == 4) 13737 p = f->f.func(context); 13738 else { 13739 stu__f = f->code, stu__c = context; 13740 stu__f_obj = co; 13741 ++stb__stua_nesting; 13742 if (stu__f[1]) 13743 p = stu__eval(stu__f[1]); 13744 else 13745 p = stua_nil; 13746 --stb__stua_nesting; 13747 stu__f = tf, stu__c = tc; // restore previous function 13748 if (stu__flow == FLOW_return) { 13749 stu__flow = FLOW_normal; 13750 p = stu__flow_val; 13751 stu__flow_val = stua_nil; 13752 } 13753 } 13754 13755 stua_poproot(); 13756 stua_poproot(); 13757 13758 return p; 13759 } 13760 13761 // Parser 13762 13763 static int stu__tok; 13764 static stua_obj stu__tokval; 13765 13766 static char *stu__curbuf, *stu__bufstart; 13767 13768 static stb_matcher *stu__lex_matcher; 13769 13770 static unsigned char stu__prec[ST__max_terminals], stu__end[ST__max_terminals]; 13771 13772 static void stu__nexttoken(void) 13773 { 13774 int len; 13775 13776 retry: 13777 stu__tok = stb_lex(stu__lex_matcher, stu__curbuf, &len); 13778 if (stu__tok == 0) 13779 return; 13780 switch(stu__tok) { 13781 case ST_white : stu__curbuf += len; goto retry; 13782 case T__none : stu__tok = *stu__curbuf; break; 13783 case ST_string: stu__tokval = make_string(stu__curbuf+1, len-2); break; 13784 case ST_id : stu__tokval = make_string(stu__curbuf, len); break; 13785 case ST_hex : stu__tokval = stu__makeint(strtol(stu__curbuf+2,NULL,16)); stu__tok = ST_number; break; 13786 case ST_decimal: stu__tokval = stu__makeint(strtol(stu__curbuf ,NULL,10)); stu__tok = ST_number; break; 13787 case ST_float : stu__tokval = stua_float((float) atof(stu__curbuf)) ; stu__tok = ST_number; break; 13788 case ST_char : stu__tokval = stu__curbuf[2] == '\\' ? stu__curbuf[3] : stu__curbuf[2]; 13789 if (stu__curbuf[3] == 't') stu__tokval = '\t'; 13790 if (stu__curbuf[3] == 'n') stu__tokval = '\n'; 13791 if (stu__curbuf[3] == 'r') stu__tokval = '\r'; 13792 stu__tokval = stu__makeint(stu__tokval); 13793 stu__tok = ST_number; 13794 break; 13795 } 13796 stu__curbuf += len; 13797 } 13798 13799 static struct { int stu__tok; char *regex; } stu__lexemes[] = 13800 { 13801 ST_white , "([ \t\n\r]|/\\*(.|\n)*\\*/|//[^\r\n]*([\r\n]|$))+", 13802 ST_id , "[_a-zA-Z][_a-zA-Z0-9]*", 13803 ST_hex , "0x[0-9a-fA-F]+", 13804 ST_decimal, "[0-9]+[0-9]*", 13805 ST_float , "[0-9]+\\.?[0-9]*([eE][-+]?[0-9]+)?", 13806 ST_float , "\\.[0-9]+([eE][-+]?[0-9]+)?", 13807 ST_char , "c'(\\\\.|[^\\'])'", 13808 ST_string , "\"(\\\\.|[^\\\"\n\r])*\"", 13809 ST_string , "\'(\\\\.|[^\\\'\n\r])*\'", 13810 13811 #define stua_key4(a,b,c,d) ST_##a, #a, ST_##b, #b, ST_##c, #c, ST_##d, #d, 13812 stua_key4(if,then,else,elseif) stua_key4(while,do,for,in) 13813 stua_key4(func,var,let,break) stua_key4(nil,true,false,end) 13814 stua_key4(return,continue,as,repeat) stua_key4(_frame,catch,catch,catch) 13815 13816 ST_shl, "<<", ST_and, "&&", ST_eq, "==", ST_ge, ">=", 13817 ST_shr, ">>", ST_or , "||", ST_ne, "!=", ST_le, "<=", 13818 ST_shru,">>>", ST_into, "=>", 13819 T__none, ".", 13820 }; 13821 13822 typedef struct 13823 { 13824 stua_obj *data; // constants being compiled 13825 short *code; // code being compiled 13826 stua_dict *locals; 13827 short *non_local_refs; 13828 } stu__comp_func; 13829 13830 static stu__comp_func stu__pfunc; 13831 static stu__comp_func *func_stack = NULL; 13832 static void stu__push_func_comp(void) 13833 { 13834 stb_arr_push(func_stack, stu__pfunc); 13835 stu__pfunc.data = NULL; 13836 stu__pfunc.code = NULL; 13837 stu__pfunc.locals = stb_idict_new_size(16); 13838 stu__pfunc.non_local_refs = NULL; 13839 stb_arr_push(stu__pfunc.code, 0); // number of data items 13840 stb_arr_push(stu__pfunc.code, 1); // starting execution address 13841 } 13842 13843 static void stu__pop_func_comp(void) 13844 { 13845 stb_arr_free(stu__pfunc.code); 13846 stb_arr_free(stu__pfunc.data); 13847 stb_idict_destroy(stu__pfunc.locals); 13848 stb_arr_free(stu__pfunc.non_local_refs); 13849 stu__pfunc = stb_arr_pop(func_stack); 13850 } 13851 13852 // if an id is a reference to an outer lexical scope, this 13853 // function returns the "name" of it, and updates the stack 13854 // structures to make sure the names are propagated in. 13855 static int stu__nonlocal_id(stua_obj var_obj) 13856 { 13857 stua_obj dummy, var = var_obj; 13858 int i, n = stb_arr_len(func_stack), j,k; 13859 if (stb_idict_get_flag(stu__pfunc.locals, var, &dummy)) return 0; 13860 for (i=n-1; i > 1; --i) { 13861 if (stb_idict_get_flag(func_stack[i].locals, var, &dummy)) 13862 break; 13863 } 13864 if (i <= 1) return 0; // stu__compile_global_scope 13865 j = i; // need to access variable from j'th frame 13866 for (i=0; i < stb_arr_len(stu__pfunc.non_local_refs); ++i) 13867 if (stu__pfunc.non_local_refs[i] == j) return j-n; 13868 stb_arr_push(stu__pfunc.non_local_refs, j-n); 13869 // now make sure all the parents propagate it down 13870 for (k=n-1; k > 1; --k) { 13871 if (j-k >= 0) return j-n; // comes direct from this parent 13872 for(i=0; i < stb_arr_len(func_stack[k].non_local_refs); ++i) 13873 if (func_stack[k].non_local_refs[i] == j-k) 13874 return j-n; 13875 stb_arr_push(func_stack[k].non_local_refs, j-k); 13876 } 13877 assert (k != 1); 13878 13879 return j-n; 13880 } 13881 13882 static int stu__off(void) { return stb_arr_len(stu__pfunc.code); } 13883 static void stu__cc(int a) 13884 { 13885 assert(a >= -2000 && a < 5000); 13886 stb_arr_push(stu__pfunc.code, a); 13887 } 13888 static int stu__cc1(int a) { stu__cc(a); return stu__off()-1; } 13889 static int stu__cc2(int a, int b) { stu__cc(a); stu__cc(b); return stu__off()-2; } 13890 static int stu__cc3(int a, int b, int c) { 13891 if (a == '=') assert(c != 0); 13892 stu__cc(a); stu__cc(b); stu__cc(c); return stu__off()-3; } 13893 static int stu__cc4(int a, int b, int c, int d) { stu__cc(a); stu__cc(b); stu__cc(c); stu__cc(d); return stu__off()-4; } 13894 13895 static int stu__cdv(stua_obj p) 13896 { 13897 int i; 13898 assert(p != STUA_NO_VALUE); 13899 for (i=0; i < stb_arr_len(stu__pfunc.data); ++i) 13900 if (stu__pfunc.data[i] == p) 13901 break; 13902 if (i == stb_arr_len(stu__pfunc.data)) 13903 stb_arr_push(stu__pfunc.data, p); 13904 return ~i; 13905 } 13906 13907 static int stu__cdt(void) 13908 { 13909 int z = stu__cdv(stu__tokval); 13910 stu__nexttoken(); 13911 return z; 13912 } 13913 13914 static int stu__seq(int a, int b) 13915 { 13916 return !a ? b : !b ? a : stu__cc3(STU__seq, a,b); 13917 } 13918 13919 static char stu__comp_err_str[1024]; 13920 static int stu__comp_err_line; 13921 static int stu__err(char *str, ...) 13922 { 13923 va_list v; 13924 char *s = stu__bufstart; 13925 stu__comp_err_line = 1; 13926 while (s < stu__curbuf) { 13927 if (s[0] == '\n' || s[0] == '\r') { 13928 if (s[0]+s[1] == '\n' + '\r') ++s; 13929 ++stu__comp_err_line; 13930 } 13931 ++s; 13932 } 13933 va_start(v, str); 13934 vsprintf(stu__comp_err_str, str, v); 13935 va_end(v); 13936 return 0; 13937 } 13938 13939 static int stu__accept(int p) 13940 { 13941 if (stu__tok != p) return 0; 13942 stu__nexttoken(); 13943 return 1; 13944 } 13945 13946 static int stu__demand(int p) 13947 { 13948 if (stu__accept(p)) return 1; 13949 return stu__err("Didn't find expected stu__tok"); 13950 } 13951 13952 static int stu__demandv(int p, stua_obj *val) 13953 { 13954 if (stu__tok == p || p==0) { 13955 *val = stu__tokval; 13956 stu__nexttoken(); 13957 return 1; 13958 } else 13959 return 0; 13960 } 13961 13962 static int stu__expr(int p); 13963 int stu__nexpr(int p) { stu__nexttoken(); return stu__expr(p); } 13964 static int stu__statements(int once, int as); 13965 13966 static int stu__parse_if(void) // parse both ST_if and ST_elseif 13967 { 13968 int b,c,a; 13969 a = stu__nexpr(1); if (!a) return 0; 13970 if (!stu__demand(ST_then)) return stu__err("expecting THEN"); 13971 b = stu__statements(0,0); if (!b) return 0; 13972 if (b == 1) b = -1; 13973 13974 if (stu__tok == ST_elseif) { 13975 return stu__parse_if(); 13976 } else if (stu__accept(ST_else)) { 13977 c = stu__statements(0,0); if (!c) return 0; 13978 if (!stu__demand(ST_end)) return stu__err("expecting END after else clause"); 13979 return stu__cc4(ST_else, a, b, c); 13980 } else { 13981 if (!stu__demand(ST_end)) return stu__err("expecting END in if statement"); 13982 return stu__cc3(ST_if, a, b); 13983 } 13984 } 13985 13986 int stu__varinit(int z, int in_globals) 13987 { 13988 int a,b; 13989 stu__nexttoken(); 13990 while (stu__demandv(ST_id, &b)) { 13991 if (!stb_idict_add(stu__pfunc.locals, b, 1)) 13992 if (!in_globals) return stu__err("Redefined variable %s.", stu__pw(b)->ptr); 13993 if (stu__accept('=')) { 13994 a = stu__expr(1); if (!a) return 0; 13995 } else 13996 a = stu__cdv(stua_nil); 13997 z = stu__seq(z, stu__cc3(ST_var, stu__cdv(b), a)); 13998 if (!stu__accept(',')) break; 13999 } 14000 return z; 14001 } 14002 14003 static int stu__compile_unary(int z, int outparm, int require_inparm) 14004 { 14005 int op = stu__tok, a, b; 14006 stu__nexttoken(); 14007 if (outparm) { 14008 if (require_inparm || (stu__tok && stu__tok != ST_end && stu__tok != ST_else && stu__tok != ST_elseif && stu__tok !=';')) { 14009 a = stu__expr(1); if (!a) return 0; 14010 } else 14011 a = stu__cdv(stua_nil); 14012 b = stu__cc2(op, a); 14013 } else 14014 b = stu__cc1(op); 14015 return stu__seq(z,b); 14016 } 14017 14018 static int stu__assign(void) 14019 { 14020 int z; 14021 stu__accept(ST_let); 14022 z = stu__expr(1); if (!z) return 0; 14023 if (stu__accept('=')) { 14024 int y,p = (z >= 0 ? stu__pfunc.code[z] : 0); 14025 if (z < 0 || (p != ST_id && p != '[')) return stu__err("Invalid lvalue in assignment"); 14026 y = stu__assign(); if (!y) return 0; 14027 z = stu__cc3('=', z, y); 14028 } 14029 return z; 14030 } 14031 14032 static int stu__statements(int once, int stop_while) 14033 { 14034 int a,b, c, z=0; 14035 for(;;) { 14036 switch (stu__tok) { 14037 case ST_if : a = stu__parse_if(); if (!a) return 0; 14038 z = stu__seq(z, a); 14039 break; 14040 case ST_while : if (stop_while) return (z ? z:1); 14041 a = stu__nexpr(1); if (!a) return 0; 14042 if (stu__accept(ST_as)) c = stu__statements(0,0); else c = 0; 14043 if (!stu__demand(ST_do)) return stu__err("expecting DO"); 14044 b = stu__statements(0,0); if (!b) return 0; 14045 if (!stu__demand(ST_end)) return stu__err("expecting END"); 14046 if (b == 1) b = -1; 14047 z = stu__seq(z, stu__cc4(ST_while, a, b, c)); 14048 break; 14049 case ST_repeat : stu__nexttoken(); 14050 c = stu__statements(0,1); if (!c) return 0; 14051 if (!stu__demand(ST_while)) return stu__err("expecting WHILE"); 14052 a = stu__expr(1); if (!a) return 0; 14053 if (!stu__demand(ST_do)) return stu__err("expecting DO"); 14054 b = stu__statements(0,0); if (!b) return 0; 14055 if (!stu__demand(ST_end)) return stu__err("expecting END"); 14056 if (b == 1) b = -1; 14057 z = stu__seq(z, stu__cc4(ST_as, a, b, c)); 14058 break; 14059 case ST_catch : a = stu__nexpr(1); if (!a) return 0; 14060 z = stu__seq(z, stu__cc2(ST_catch, a)); 14061 break; 14062 case ST_var : z = stu__varinit(z,0); break; 14063 case ST_return : z = stu__compile_unary(z,1,1); break; 14064 case ST_continue:z = stu__compile_unary(z,0,0); break; 14065 case ST_break : z = stu__compile_unary(z,1,0); break; 14066 case ST_into : if (z == 0 && !once) return stu__err("=> cannot be first statement in block"); 14067 a = stu__nexpr(99); 14068 b = (a >= 0? stu__pfunc.code[a] : 0); 14069 if (a < 0 || (b != ST_id && b != '[')) return stu__err("Invalid lvalue on right side of =>"); 14070 z = stu__cc3('=', a, z); 14071 break; 14072 default : if (stu__end[stu__tok]) return once ? 0 : (z ? z:1); 14073 a = stu__assign(); if (!a) return 0; 14074 stu__accept(';'); 14075 if (stu__tok && !stu__end[stu__tok]) { 14076 if (a < 0) 14077 return stu__err("Constant has no effect"); 14078 if (stu__pfunc.code[a] != '(' && stu__pfunc.code[a] != '=') 14079 return stu__err("Expression has no effect"); 14080 } 14081 z = stu__seq(z, a); 14082 break; 14083 } 14084 if (!z) return 0; 14085 stu__accept(';'); 14086 if (once && stu__tok != ST_into) return z; 14087 } 14088 } 14089 14090 static int stu__postexpr(int z, int p); 14091 static int stu__dictdef(int end, int *count) 14092 { 14093 int z,n=0,i,flags=0; 14094 short *dict=NULL; 14095 stu__nexttoken(); 14096 while (stu__tok != end) { 14097 if (stu__tok == ST_id) { 14098 stua_obj id = stu__tokval; 14099 stu__nexttoken(); 14100 if (stu__tok == '=') { 14101 flags |= 1; 14102 stb_arr_push(dict, stu__cdv(id)); 14103 z = stu__nexpr(1); if (!z) return 0; 14104 } else { 14105 z = stu__cc2(ST_id, stu__cdv(id)); 14106 z = stu__postexpr(z,1); if (!z) return 0; 14107 flags |= 2; 14108 stb_arr_push(dict, stu__cdv(stu__makeint(n++))); 14109 } 14110 } else { 14111 z = stu__expr(1); if (!z) return 0; 14112 flags |= 2; 14113 stb_arr_push(dict, stu__cdv(stu__makeint(n++))); 14114 } 14115 if (end != ')' && flags == 3) { z=stu__err("can't mix initialized and uninitialized defs"); goto done;} 14116 stb_arr_push(dict, z); 14117 if (!stu__accept(',')) break; 14118 } 14119 if (!stu__demand(end)) 14120 return stu__err(end == ')' ? "Expecting ) at end of function call" 14121 : "Expecting } at end of dictionary definition"); 14122 z = stu__cc2('{', stb_arr_len(dict)/2); 14123 for (i=0; i < stb_arr_len(dict); ++i) 14124 stu__cc(dict[i]); 14125 if (count) *count = n; 14126 done: 14127 stb_arr_free(dict); 14128 return z; 14129 } 14130 14131 static int stu__comp_id(void) 14132 { 14133 int z,d; 14134 d = stu__nonlocal_id(stu__tokval); 14135 if (d == 0) 14136 return z = stu__cc2(ST_id, stu__cdt()); 14137 // access a non-local frame by naming it with the appropriate int 14138 assert(d < 0); 14139 z = stu__cdv(d); // relative frame # is the 'variable' in our local frame 14140 z = stu__cc2(ST_id, z); // now access that dictionary 14141 return stu__cc3('[', z, stu__cdt()); // now access the variable from that dir 14142 } 14143 14144 static stua_obj stu__funcdef(stua_obj *id, stua_obj *func); 14145 static int stu__expr(int p) 14146 { 14147 int z; 14148 // unary 14149 switch (stu__tok) { 14150 case ST_number: z = stu__cdt(); break; 14151 case ST_string: z = stu__cdt(); break; // @TODO - string concatenation like C 14152 case ST_id : z = stu__comp_id(); break; 14153 case ST__frame: z = stu__cc1(ST__frame); stu__nexttoken(); break; 14154 case ST_func : z = stu__funcdef(NULL,NULL); break; 14155 case ST_if : z = stu__parse_if(); break; 14156 case ST_nil : z = stu__cdv(stua_nil); stu__nexttoken(); break; 14157 case ST_true : z = stu__cdv(stua_true); stu__nexttoken(); break; 14158 case ST_false : z = stu__cdv(stua_false); stu__nexttoken(); break; 14159 case '-' : z = stu__nexpr(99); if (z) z=stu__cc2(STU__negate,z); else return z; break; 14160 case '!' : z = stu__nexpr(99); if (z) z=stu__cc2('!',z); else return z; break; 14161 case '~' : z = stu__nexpr(99); if (z) z=stu__cc2('~',z); else return z; break; 14162 case '{' : z = stu__dictdef('}', NULL); break; 14163 default : return stu__err("Unexpected token"); 14164 case '(' : stu__nexttoken(); z = stu__statements(0,0); if (!stu__demand(')')) return stu__err("Expecting )"); 14165 } 14166 return stu__postexpr(z,p); 14167 } 14168 14169 static int stu__postexpr(int z, int p) 14170 { 14171 int q; 14172 // postfix 14173 while (stu__tok == '(' || stu__tok == '[' || stu__tok == '.') { 14174 if (stu__accept('.')) { 14175 // MUST be followed by a plain identifier! use [] for other stuff 14176 if (stu__tok != ST_id) return stu__err("Must follow . with plain name; try [] instead"); 14177 z = stu__cc3('[', z, stu__cdv(stu__tokval)); 14178 stu__nexttoken(); 14179 } else if (stu__accept('[')) { 14180 while (stu__tok != ']') { 14181 int r = stu__expr(1); if (!r) return 0; 14182 z = stu__cc3('[', z, r); 14183 if (!stu__accept(',')) break; 14184 } 14185 if (!stu__demand(']')) return stu__err("Expecting ]"); 14186 } else { 14187 int n, p = stu__dictdef(')', &n); if (!p) return 0; 14188 #if 0 // this is incorrect! 14189 if (z > 0 && stu__pfunc.code[z] == ST_id) { 14190 stua_obj q = stu__get(stu__globaldict, stu__pfunc.data[-stu__pfunc.code[z+1]-1], stua_nil); 14191 if (stu__checkt(STU___function, q)) 14192 if ((stu__pf(q))->num_param != n) 14193 return stu__err("Incorrect number of parameters"); 14194 } 14195 #endif 14196 z = stu__cc3('(', z, p); 14197 } 14198 } 14199 // binop - this implementation taken from lcc 14200 for (q=stu__prec[stu__tok]; q >= p; --q) { 14201 while (stu__prec[stu__tok] == q) { 14202 int o = stu__tok, y = stu__nexpr(p+1); if (!y) return 0; 14203 z = stu__cc3(o,z,y); 14204 } 14205 } 14206 return z; 14207 } 14208 14209 static stua_obj stu__finish_func(stua_obj *param, int start) 14210 { 14211 int n, size; 14212 stu__func *f = (stu__func *) malloc(sizeof(*f)); 14213 f->closure_source = 0; 14214 f->num_param = stb_arr_len(param); 14215 f->param = (int *) stb_copy(param, f->num_param * sizeof(*f->param)); 14216 size = stb_arr_storage(stu__pfunc.code) + stb_arr_storage(stu__pfunc.data) + sizeof(*f) + 8; 14217 f->f.store = malloc(stb_arr_storage(stu__pfunc.code) + stb_arr_storage(stu__pfunc.data)); 14218 f->code = (short *) ((char *) f->f.store + stb_arr_storage(stu__pfunc.data)); 14219 memcpy(f->code, stu__pfunc.code, stb_arr_storage(stu__pfunc.code)); 14220 f->code[1] = start; 14221 f->code[0] = stb_arr_len(stu__pfunc.data); 14222 for (n=0; n < f->code[0]; ++n) 14223 ((stua_obj *) f->code)[-1-n] = stu__pfunc.data[n]; 14224 return stu__makeobj(STU___function, f, size, 0); 14225 } 14226 14227 static int stu__funcdef(stua_obj *id, stua_obj *result) 14228 { 14229 int n,z=0,i,q; 14230 stua_obj *param = NULL; 14231 short *nonlocal; 14232 stua_obj v,f=stua_nil; 14233 assert(stu__tok == ST_func); 14234 stu__nexttoken(); 14235 if (id) { 14236 if (!stu__demandv(ST_id, id)) return stu__err("Expecting function name"); 14237 } else 14238 stu__accept(ST_id); 14239 if (!stu__demand('(')) return stu__err("Expecting ( for function parameter"); 14240 stu__push_func_comp(); 14241 while (stu__tok != ')') { 14242 if (!stu__demandv(ST_id, &v)) { z=stu__err("Expecting parameter name"); goto done; } 14243 stb_idict_add(stu__pfunc.locals, v, 1); 14244 if (stu__tok == '=') { 14245 n = stu__nexpr(1); if (!n) { z=0; goto done; } 14246 z = stu__seq(z, stu__cc3(STU__defaultparm, stu__cdv(v), n)); 14247 } else 14248 stb_arr_push(param, v); 14249 if (!stu__accept(',')) break; 14250 } 14251 if (!stu__demand(')')) { z=stu__err("Expecting ) at end of parameter list"); goto done; } 14252 n = stu__statements(0,0); if (!n) { z=0; goto done; } 14253 if (!stu__demand(ST_end)) { z=stu__err("Expecting END at end of function"); goto done; } 14254 if (n == 1) n = 0; 14255 n = stu__seq(z,n); 14256 f = stu__finish_func(param, n); 14257 if (result) { *result = f; z=1; stu__pop_func_comp(); } 14258 else { 14259 nonlocal = stu__pfunc.non_local_refs; 14260 stu__pfunc.non_local_refs = NULL; 14261 stu__pop_func_comp(); 14262 z = stu__cdv(f); 14263 if (nonlocal) { // build a closure with references to the needed frames 14264 short *initcode = NULL; 14265 for (i=0; i < stb_arr_len(nonlocal); ++i) { 14266 int k = nonlocal[i], p; 14267 stb_arr_push(initcode, stu__cdv(k)); 14268 if (k == -1) p = stu__cc1(ST__frame); 14269 else { p = stu__cdv(stu__makeint(k+1)); p = stu__cc2(ST_id, p); } 14270 stb_arr_push(initcode, p); 14271 } 14272 q = stu__cc2('{', stb_arr_len(nonlocal)); 14273 for (i=0; i < stb_arr_len(initcode); ++i) 14274 stu__cc(initcode[i]); 14275 z = stu__cc3('+', z, q); 14276 stb_arr_free(initcode); 14277 } 14278 stb_arr_free(nonlocal); 14279 } 14280 done: 14281 stb_arr_free(param); 14282 if (!z) stu__pop_func_comp(); 14283 return z; 14284 } 14285 14286 static int stu__compile_global_scope(void) 14287 { 14288 stua_obj o; 14289 int z=0; 14290 14291 stu__push_func_comp(); 14292 while (stu__tok != 0) { 14293 if (stu__tok == ST_func) { 14294 stua_obj id, f; 14295 if (!stu__funcdef(&id,&f)) 14296 goto error; 14297 stu__set(stu__globaldict, id, f); 14298 } else if (stu__tok == ST_var) { 14299 z = stu__varinit(z,1); if (!z) goto error; 14300 } else { 14301 int y = stu__statements(1,0); if (!y) goto error; 14302 z = stu__seq(z,y); 14303 } 14304 stu__accept(';'); 14305 } 14306 o = stu__finish_func(NULL, z); 14307 stu__pop_func_comp(); 14308 14309 o = stu__funceval(o, stua_globals); // initialize stu__globaldict 14310 if (stu__flow == FLOW_error) 14311 printf("Error: %s\n", ((stu__wrapper *) stu__ptr(stu__flow_val))->ptr); 14312 return 1; 14313 error: 14314 stu__pop_func_comp(); 14315 return 0; 14316 } 14317 14318 stua_obj stu__myprint(stua_dict *context) 14319 { 14320 stua_obj x = stu__get(context, stua_string("x"), stua_nil); 14321 if ((x & 1) == stu__float_tag) printf("%f", stu__getfloat(x)); 14322 else if (stu__tag(x) == stu__int_tag) printf("%d", stu__int(x)); 14323 else { 14324 stu__wrapper *s = stu__pw(x); 14325 if (s->type == STU___string || s->type == STU___error) 14326 printf("%s", s->ptr); 14327 else if (s->type == STU___dict) printf("{{dictionary}}"); 14328 else if (s->type == STU___function) printf("[[function]]"); 14329 else 14330 printf("[[ERROR:%s]]", s->ptr); 14331 } 14332 return x; 14333 } 14334 14335 void stua_init(void) 14336 { 14337 if (!stu__globaldict) { 14338 int i; 14339 stua_obj s; 14340 stu__func *f; 14341 14342 stu__prec[ST_and] = stu__prec[ST_or] = 1; 14343 stu__prec[ST_eq ] = stu__prec[ST_ne] = stu__prec[ST_le] = 14344 stu__prec[ST_ge] = stu__prec['>' ] = stu__prec['<'] = 2; 14345 stu__prec[':'] = 3; 14346 stu__prec['&'] = stu__prec['|'] = stu__prec['^'] = 4; 14347 stu__prec['+'] = stu__prec['-'] = 5; 14348 stu__prec['*'] = stu__prec['/'] = stu__prec['%'] = 14349 stu__prec[ST_shl]= stu__prec[ST_shr]= stu__prec[ST_shru]= 6; 14350 14351 stu__end[')'] = stu__end[ST_end] = stu__end[ST_else] = 1; 14352 stu__end[ST_do] = stu__end[ST_elseif] = 1; 14353 14354 stu__float_init(); 14355 stu__lex_matcher = stb_lex_matcher(); 14356 for (i=0; i < sizeof(stu__lexemes)/sizeof(stu__lexemes[0]); ++i) 14357 stb_lex_item(stu__lex_matcher, stu__lexemes[i].regex, stu__lexemes[i].stu__tok); 14358 14359 stu__globaldict = stb_idict_new_size(64); 14360 stua_globals = stu__makeobj(STU___dict, stu__globaldict, 0,0); 14361 stu__strings = stb_sdict_new(0); 14362 14363 stu__curbuf = stu__bufstart = "func _print(x) end\n" 14364 "func print()\n var x=0 while _frame[x] != nil as x=x+1 do _print(_frame[x]) end end\n"; 14365 stu__nexttoken(); 14366 if (!stu__compile_global_scope()) 14367 printf("Compile error in line %d: %s\n", stu__comp_err_line, stu__comp_err_str); 14368 14369 s = stu__get(stu__globaldict, stua_string("_print"), stua_nil); 14370 if (stu__tag(s) == stu__ptr_tag && stu__ptr(s)->type == STU___function) { 14371 f = stu__pf(s); 14372 free(f->f.store); 14373 f->closure_source = 4; 14374 f->f.func = stu__myprint; 14375 f->code = NULL; 14376 } 14377 } 14378 } 14379 14380 void stua_uninit(void) 14381 { 14382 if (stu__globaldict) { 14383 stb_idict_remove_all(stu__globaldict); 14384 stb_arr_setlen(stu__gc_root_stack, 0); 14385 stua_gc(1); 14386 stb_idict_destroy(stu__globaldict); 14387 stb_sdict_delete(stu__strings); 14388 stb_matcher_free(stu__lex_matcher); 14389 stb_arr_free(stu__gc_ptrlist); 14390 stb_arr_free(func_stack); 14391 stb_arr_free(stu__gc_root_stack); 14392 stu__globaldict = NULL; 14393 } 14394 } 14395 14396 void stua_run_script(char *s) 14397 { 14398 stua_init(); 14399 14400 stu__curbuf = stu__bufstart = s; 14401 stu__nexttoken(); 14402 14403 stu__flow = FLOW_normal; 14404 14405 if (!stu__compile_global_scope()) 14406 printf("Compile error in line %d: %s\n", stu__comp_err_line, stu__comp_err_str); 14407 stua_gc(1); 14408 } 14409 #endif // STB_DEFINE 14410 #endif // STB_STUA 14411 14412 #undef STB_EXTERN 14413 #endif // STB_INCLUDE_STB_H 14414 14415 /* 14416 ------------------------------------------------------------------------------ 14417 This software is available under 2 licenses -- choose whichever you prefer. 14418 ------------------------------------------------------------------------------ 14419 ALTERNATIVE A - MIT License 14420 Copyright (c) 2017 Sean Barrett 14421 Permission is hereby granted, free of charge, to any person obtaining a copy of 14422 this software and associated documentation files (the "Software"), to deal in 14423 the Software without restriction, including without limitation the rights to 14424 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 14425 of the Software, and to permit persons to whom the Software is furnished to do 14426 so, subject to the following conditions: 14427 The above copyright notice and this permission notice shall be included in all 14428 copies or substantial portions of the Software. 14429 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14430 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14431 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14432 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 14433 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 14434 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 14435 SOFTWARE. 14436 ------------------------------------------------------------------------------ 14437 ALTERNATIVE B - Public Domain (www.unlicense.org) 14438 This is free and unencumbered software released into the public domain. 14439 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 14440 software, either in source code form or as a compiled binary, for any purpose, 14441 commercial or non-commercial, and by any means. 14442 In jurisdictions that recognize copyright laws, the author or authors of this 14443 software dedicate any and all copyright interest in the software to the public 14444 domain. We make this dedication for the benefit of the public at large and to 14445 the detriment of our heirs and successors. We intend this dedication to be an 14446 overt act of relinquishment in perpetuity of all present and future rights to 14447 this software under copyright law. 14448 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14449 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14450 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14451 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 14452 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 14453 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14454 ------------------------------------------------------------------------------ 14455 */