|
|
|
@ -1,4 +1,4 @@ |
|
|
|
|
/* stb.h - v2.25 - Sean's Tool Box -- public domain -- http://nothings.org/stb.h
|
|
|
|
|
/* stb.h - v2.26 - Sean's Tool Box -- public domain -- http://nothings.org/stb.h
|
|
|
|
|
no warranty is offered or implied; use this code at your own risk |
|
|
|
|
|
|
|
|
|
This is a single header file with a bunch of useful utilities |
|
|
|
@ -25,6 +25,7 @@ |
|
|
|
|
|
|
|
|
|
Version History |
|
|
|
|
|
|
|
|
|
2.26 various warning & buffixes |
|
|
|
|
2.25 various warning & bugfixes |
|
|
|
|
2.24 various warning & bugfixes |
|
|
|
|
2.23 fix 2.22 |
|
|
|
@ -186,6 +187,9 @@ CREDITS |
|
|
|
|
Mojofreem@github |
|
|
|
|
Ryan Whitworth |
|
|
|
|
Vincent Isambart |
|
|
|
|
Mike Sartain |
|
|
|
|
Eugene Opalev |
|
|
|
|
Tim Sjostrand |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
#ifndef STB__INCLUDE_STB_H |
|
|
|
@ -206,10 +210,16 @@ CREDITS |
|
|
|
|
#endif |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
#ifdef _WIN32 |
|
|
|
|
#if defined(_WIN32) && !defined(__MINGW32__) |
|
|
|
|
#ifndef _CRT_SECURE_NO_WARNINGS |
|
|
|
|
#define _CRT_SECURE_NO_WARNINGS |
|
|
|
|
#endif |
|
|
|
|
#ifndef _CRT_NONSTDC_NO_DEPRECATE |
|
|
|
|
#define _CRT_NONSTDC_NO_DEPRECATE |
|
|
|
|
#endif |
|
|
|
|
#ifndef _CRT_NON_CONFORMING_SWPRINTFS |
|
|
|
|
#define _CRT_NON_CONFORMING_SWPRINTFS |
|
|
|
|
#endif |
|
|
|
|
#if !defined(_MSC_VER) || _MSC_VER > 1700 |
|
|
|
|
#include <intrin.h> // _BitScanReverse |
|
|
|
|
#endif |
|
|
|
@ -714,20 +724,41 @@ STB_EXTERN char * stb_sstrdup(char *s); |
|
|
|
|
STB_EXTERN void stbprint(const char *fmt, ...); |
|
|
|
|
STB_EXTERN char *stb_sprintf(const char *fmt, ...); |
|
|
|
|
STB_EXTERN char *stb_mprintf(const char *fmt, ...); |
|
|
|
|
STB_EXTERN int stb_snprintf(char *s, size_t n, const char *fmt, ...); |
|
|
|
|
STB_EXTERN int stb_vsnprintf(char *s, size_t n, const char *fmt, va_list v); |
|
|
|
|
|
|
|
|
|
#ifdef STB_DEFINE |
|
|
|
|
int stb_vsnprintf(char *s, size_t n, const char *fmt, va_list v) |
|
|
|
|
{ |
|
|
|
|
int res; |
|
|
|
|
#ifdef _WIN32 |
|
|
|
|
// Could use "_vsnprintf_s(s, n, _TRUNCATE, fmt, v)" ?
|
|
|
|
|
res = _vsnprintf(s,n,fmt,v); |
|
|
|
|
#else |
|
|
|
|
res = vsnprintf(s,n,fmt,v); |
|
|
|
|
#endif |
|
|
|
|
if (n) s[n-1] = 0; |
|
|
|
|
// Unix returns length output would require, Windows returns negative when truncated.
|
|
|
|
|
return (res >= (int) n || res < 0) ? -1 : res; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int stb_snprintf(char *s, size_t n, const char *fmt, ...) |
|
|
|
|
{ |
|
|
|
|
int res; |
|
|
|
|
va_list v; |
|
|
|
|
va_start(v,fmt); |
|
|
|
|
res = stb_vsnprintf(s, n, fmt, v); |
|
|
|
|
va_end(v); |
|
|
|
|
return res; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
char *stb_sprintf(const char *fmt, ...) |
|
|
|
|
{ |
|
|
|
|
static char buffer[1024]; |
|
|
|
|
va_list v; |
|
|
|
|
va_start(v,fmt); |
|
|
|
|
#ifdef _WIN32 |
|
|
|
|
_vsnprintf(buffer, 1024, fmt, v); |
|
|
|
|
#else |
|
|
|
|
vsnprintf(buffer, 1024, fmt, v); |
|
|
|
|
#endif |
|
|
|
|
stb_vsnprintf(buffer,1024,fmt,v); |
|
|
|
|
va_end(v); |
|
|
|
|
buffer[1023] = 0; |
|
|
|
|
return buffer; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -736,13 +767,8 @@ char *stb_mprintf(const char *fmt, ...) |
|
|
|
|
static char buffer[1024]; |
|
|
|
|
va_list v; |
|
|
|
|
va_start(v,fmt); |
|
|
|
|
#ifdef _WIN32 |
|
|
|
|
_vsnprintf(buffer, 1024, fmt, v); |
|
|
|
|
#else |
|
|
|
|
vsnprintf(buffer, 1024, fmt, v); |
|
|
|
|
#endif |
|
|
|
|
stb_vsnprintf(buffer,1024,fmt,v); |
|
|
|
|
va_end(v); |
|
|
|
|
buffer[1023] = 0; |
|
|
|
|
return strdup(buffer); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -842,9 +868,8 @@ void stbprint(const char *fmt, ...) |
|
|
|
|
va_list v; |
|
|
|
|
|
|
|
|
|
va_start(v,fmt); |
|
|
|
|
res = _vsnprintf(buffer, sizeof(buffer), fmt, v); |
|
|
|
|
res = stb_vsnprintf(buffer, sizeof(buffer), fmt, v); |
|
|
|
|
va_end(v); |
|
|
|
|
buffer[sizeof(buffer)-1] = 0; |
|
|
|
|
|
|
|
|
|
if (res < 0) { |
|
|
|
|
tbuf = (char *) malloc(16384); |
|
|
|
@ -1765,6 +1790,7 @@ STB_EXTERN char * stb_strichr(char *s, char t); |
|
|
|
|
STB_EXTERN char * stb_stristr(char *s, char *t); |
|
|
|
|
STB_EXTERN int stb_prefix_count(char *s, char *t); |
|
|
|
|
STB_EXTERN char * stb_plural(int n); // "s" or ""
|
|
|
|
|
STB_EXTERN size_t stb_strscpy(char *d, const char *s, size_t n); |
|
|
|
|
|
|
|
|
|
STB_EXTERN char **stb_tokens(char *src, char *delimit, int *count); |
|
|
|
|
STB_EXTERN char **stb_tokens_nested(char *src, char *delimit, int *count, char *nest_in, char *nest_out); |
|
|
|
@ -1779,6 +1805,17 @@ STB_EXTERN char **stb_tokens_quoted(char *src, char *delimit, int *count); |
|
|
|
|
|
|
|
|
|
#ifdef STB_DEFINE |
|
|
|
|
|
|
|
|
|
size_t stb_strscpy(char *d, const char *s, size_t n) |
|
|
|
|
{ |
|
|
|
|
size_t len = strlen(s); |
|
|
|
|
if (len >= n) { |
|
|
|
|
if (n) d[0] = 0; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
strcpy(d,s); |
|
|
|
|
return len + 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
char *stb_plural(int n) |
|
|
|
|
{ |
|
|
|
|
return n == 1 ? "" : "s"; |
|
|
|
@ -3062,7 +3099,7 @@ typedef struct |
|
|
|
|
#define stb_arr_insertn(a,i,n) (stb__arr_insertn((void **) &(a), sizeof(*a), i, n)) |
|
|
|
|
|
|
|
|
|
// insert an element at i
|
|
|
|
|
#define stb_arr_insert(a,i,v) (stb__arr_insertn((void **) &(a), sizeof(*a), i, n), ((a)[i] = v)) |
|
|
|
|
#define stb_arr_insert(a,i,v) (stb__arr_insertn((void **) &(a), sizeof(*a), i, 1), ((a)[i] = v)) |
|
|
|
|
|
|
|
|
|
// delete N elements from the middle starting at index 'i'
|
|
|
|
|
#define stb_arr_deleten(a,i,n) (stb__arr_deleten((void **) &(a), sizeof(*a), i, n)) |
|
|
|
@ -3248,7 +3285,7 @@ void stb__arr_insertn_(void **pp, int size, int i, int n STB__PARAMS) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
z = stb_arr_len2(p); |
|
|
|
|
stb__arr_addlen_(&p, size, i STB__ARGS); |
|
|
|
|
stb__arr_addlen_(&p, size, n STB__ARGS); |
|
|
|
|
memmove((char *) p + (i+n)*size, (char *) p + i*size, size * (z-i)); |
|
|
|
|
} |
|
|
|
|
*pp = p; |
|
|
|
@ -3258,7 +3295,7 @@ void stb__arr_deleten_(void **pp, int size, int i, int n STB__PARAMS) |
|
|
|
|
{ |
|
|
|
|
void *p = *pp; |
|
|
|
|
if (n) { |
|
|
|
|
memmove((char *) p + i*size, (char *) p + (i+n)*size, size * (stb_arr_len2(p)-i)); |
|
|
|
|
memmove((char *) p + i*size, (char *) p + (i+n)*size, size * (stb_arr_len2(p)-(i+n))); |
|
|
|
|
stb_arrhead2(p)->len -= n; |
|
|
|
|
} |
|
|
|
|
*pp = p; |
|
|
|
@ -5863,11 +5900,18 @@ void stb_readdir_free(char **files) |
|
|
|
|
stb_arr_free(f2); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int isdotdirname(char *name) |
|
|
|
|
{ |
|
|
|
|
if (name[0] == '.') |
|
|
|
|
return (name[1] == '.') ? !name[2] : !name[1]; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
STB_EXTERN int stb_wildmatchi(char *expr, char *candidate); |
|
|
|
|
static char **readdir_raw(char *dir, int return_subdirs, char *mask) |
|
|
|
|
{ |
|
|
|
|
char **results = NULL; |
|
|
|
|
char buffer[512], with_slash[512]; |
|
|
|
|
char buffer[4096], with_slash[4096]; |
|
|
|
|
size_t n; |
|
|
|
|
|
|
|
|
|
#ifdef _MSC_VER |
|
|
|
@ -5885,25 +5929,28 @@ static char **readdir_raw(char *dir, int return_subdirs, char *mask) |
|
|
|
|
DIR *z; |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
strcpy(buffer,dir); |
|
|
|
|
n = stb_strscpy(buffer,dir,sizeof(buffer)); |
|
|
|
|
if (!n || n >= sizeof(buffer)) |
|
|
|
|
return NULL; |
|
|
|
|
stb_fixpath(buffer); |
|
|
|
|
n = strlen(buffer); |
|
|
|
|
n--; |
|
|
|
|
|
|
|
|
|
if (n > 0 && (buffer[n-1] != '/')) { |
|
|
|
|
buffer[n++] = '/'; |
|
|
|
|
} |
|
|
|
|
buffer[n] = 0; |
|
|
|
|
strcpy(with_slash, buffer); |
|
|
|
|
if (!stb_strscpy(with_slash,buffer,sizeof(with_slash))) |
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
|
|
#ifdef _MSC_VER |
|
|
|
|
strcpy(buffer+n, "*.*"); |
|
|
|
|
if (!stb_strscpy(buffer+n,"*.*",sizeof(buffer)-n)) |
|
|
|
|
return NULL; |
|
|
|
|
ws = stb__from_utf8(buffer); |
|
|
|
|
z = _wfindfirst((const wchar_t *)ws, &data); |
|
|
|
|
#else |
|
|
|
|
z = opendir(dir); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (z != none) { |
|
|
|
|
int nonempty = STB_TRUE; |
|
|
|
|
#ifndef _MSC_VER |
|
|
|
@ -5924,17 +5971,18 @@ static char **readdir_raw(char *dir, int return_subdirs, char *mask) |
|
|
|
|
is_subdir = !!(data.attrib & _A_SUBDIR); |
|
|
|
|
#else |
|
|
|
|
char *name = data->d_name; |
|
|
|
|
strcpy(buffer+n,name); |
|
|
|
|
DIR *y = opendir(buffer); |
|
|
|
|
is_subdir = (y != NULL); |
|
|
|
|
if (y != NULL) closedir(y); |
|
|
|
|
if (!stb_strscpy(buffer+n,name,sizeof(buffer)-n)) |
|
|
|
|
break; |
|
|
|
|
// Could follow DT_LNK, but would need to check for recursive links.
|
|
|
|
|
is_subdir = !!(data->d_type & DT_DIR); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (is_subdir == return_subdirs) { |
|
|
|
|
if (!is_subdir || name[0] != '.') { |
|
|
|
|
if (!is_subdir || !isdotdirname(name)) { |
|
|
|
|
if (!mask || stb_wildmatchi(mask, name)) { |
|
|
|
|
char buffer[512],*p=buffer; |
|
|
|
|
sprintf(buffer, "%s%s", with_slash, name); |
|
|
|
|
char buffer[4096],*p=buffer; |
|
|
|
|
if ( stb_snprintf(buffer, sizeof(buffer), "%s%s", with_slash, name) < 0 ) |
|
|
|
|
break; |
|
|
|
|
if (buffer[0] == '.' && buffer[1] == '/') |
|
|
|
|
p = buffer+2; |
|
|
|
|
stb_arr_push(results, strdup(p)); |
|
|
|
@ -7786,7 +7834,7 @@ stb_ps *stb_ps_remove_any(stb_ps *ps, void **value) |
|
|
|
|
void ** stb_ps_getlist(stb_ps *ps, int *count) |
|
|
|
|
{ |
|
|
|
|
int i,n=0; |
|
|
|
|
void **p; |
|
|
|
|
void **p = NULL; |
|
|
|
|
switch (3 & (int) ps) { |
|
|
|
|
case STB_ps_direct: |
|
|
|
|
if (ps == NULL) { *count = 0; return NULL; } |
|
|
|
|