static u32 util_popcount(u64 x) { #ifdef __GNUC__ return (u32)__builtin_popcountll(x); #else u32 count = 0; while (x) { x &= x-1; ++count; } return count; #endif } static bool util_is_power_of_2(u64 x) { return util_popcount(x) == 1; } static void util_zero_memory(void *mem, size_t size) { memset(mem, 0, size); } // for finding a character in a char32 string static char32_t *util_mem32chr(char32_t *s, char32_t c, size_t n) { for (size_t i = 0; i < n; ++i) { if (s[i] == c) { return &s[i]; } } return NULL; } static char32_t const *util_mem32chr_const(char32_t const *s, char32_t c, size_t n) { for (size_t i = 0; i < n; ++i) { if (s[i] == c) { return &s[i]; } } return NULL; } static bool str_is_prefix(char const *str, char const *prefix) { return strncmp(str, prefix, strlen(prefix)) == 0; } static bool streq(char const *a, char const *b) { return strcmp(a, b) == 0; } // duplicates a null-terminated string. the returned string should be passed to free() static char *str_dup(char const *src) { size_t len = strlen(src); char *ret = malloc(len + 1); if (ret) memcpy(ret, src, len + 1); return ret; } // like snprintf, but not screwed up on windows #define str_printf(str, size, ...) (str)[(size) - 1] = '\0', snprintf((str), (size) - 1, __VA_ARGS__) // like snprintf, but the size is taken to be the length of the array str. // first, check that str is actually an array #define strbuf_printf(str, ...) assert(sizeof str != 4 && sizeof str != 8), \ str_printf(str, sizeof str, __VA_ARGS__) // on 16-bit systems, this is 16383. on 32/64-bit systems, this is 1073741823 // it is unusual to have a string that long. #define STRLEN_SAFE_MAX (UINT_MAX >> 2) // safer version of strcat. dst_sz includes a null terminator. static void str_cat(char *dst, size_t dst_sz, char const *src) { size_t dst_len = strlen(dst), src_len = strlen(src); // make sure dst_len + src_len + 1 doesn't overflow if (dst_len > STRLEN_SAFE_MAX || src_len > STRLEN_SAFE_MAX) { assert(0); return; } if (dst_len >= dst_sz) { // dst doesn't actually contain a null-terminated string! assert(0); return; } if (dst_len + src_len + 1 > dst_sz) { // number of bytes left in dst, not including null terminator size_t n = dst_sz - dst_len - 1; memcpy(dst + dst_len, src, n); dst[dst_sz - 1] = 0; // dst_len + n == dst_sz - 1 } else { memcpy(dst + dst_len, src, src_len); dst[dst_len + src_len] = 0; } } // safer version of strncpy. dst_sz includes a null terminator. static void str_cpy(char *dst, size_t dst_sz, char const *src) { size_t srclen = strlen(src); size_t n = srclen; // number of bytes to copy if (dst_sz == 0) { assert(0); return; } if (dst_sz-1 < n) n = dst_sz-1; memcpy(dst, src, n); dst[n] = 0; } /* returns the first instance of needle in haystack, ignoring the case of the characters, or NULL if the haystack does not contain needle WARNING: O(strlen(haystack) * strlen(needle)) */ static char *stristr(char const *haystack, char const *needle) { size_t needle_len = strlen(needle), haystack_len = strlen(haystack), i, j; if (needle_len > haystack_len) return NULL; // a larger string can't fit in a smaller string for (i = 0; i <= haystack_len - needle_len; ++i) { char const *p = haystack + i, *q = needle; bool match = true; for (j = 0; j < needle_len; ++j) { if (tolower(*p) != tolower(*q)) { match = false; break; } ++p; ++q; } if (match) return (char *)haystack + i; } return NULL; } static void print_bytes(u8 *bytes, size_t n) { u8 *b, *end; for (b = bytes, end = bytes + n; b != end; ++b) printf("%x ", *b); printf("\n"); } /* does this predicate hold for all the characters of s. predicate is int (*)(int) instead of bool (*)(char) so that you can pass isprint, etc. to it. */ static bool str_satisfies(char const *s, int (*predicate)(int)) { char const *p; for (p = s; *p; ++p) if (!predicate(*p)) return false; return true; } // function to be passed into qsort for case insensitive sorting static int str_qsort_case_insensitive_cmp(const void *av, const void *bv) { char const *const *a = av, *const *b = bv; #if _WIN32 return _stricmp(*a, *b); #else return strcasecmp(*a, *b); #endif }