#if _WIN32 #include #endif static u8 util_popcount(u64 x) { #ifdef __GNUC__ return (u8)__builtin_popcountll(x); #else u8 count = 0; while (x) { x &= x-1; ++count; } return count; #endif } static u8 util_count_leading_zeroes(u64 x) { #if __GNUC__ return (u8)__builtin_clzll(x); #elif _WIN32 return (u8)__lzcnt64(x); #else u8 count = 0; for (int i = 63; i >= 0; --i) if (x & ((u64)1<> 2) // safer version of strncat. dst_sz includes a null terminator. static void strn_cat(char *dst, size_t dst_sz, char const *src, size_t src_len) { size_t dst_len = strlen(dst); // 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 strcat. dst_sz includes a null terminator. static void str_cat(char *dst, size_t dst_sz, char const *src) { strn_cat(dst, dst_sz, src, strlen(src)); } // 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; } #define strbuf_cpy(dst, src) str_cpy(dst, sizeof dst, src) // advances str to the start of the next UTF8 character static void utf8_next_char_const(char const **str) { if (**str) { do { ++*str; } while (((u8)(**str) & 0xC0) == 0x80); // while we are on a continuation byte } } /* returns the first instance of needle in haystack, where both are UTF-8 strings, 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_bytes = strlen(needle), haystack_bytes = strlen(haystack); if (needle_bytes > haystack_bytes) return NULL; char const *haystack_end = haystack + haystack_bytes; char const *needle_end = needle + needle_bytes; for (char const *haystack_start = haystack; haystack_start + needle_bytes <= haystack_end; utf8_next_char_const(&haystack_start)) { char const *p = haystack_start, *q = needle; bool match = true; // check if p matches q while (q < needle_end) { char32_t pchar = 0, qchar = 0; size_t bytes_p = unicode_utf8_to_utf32(&pchar, p, (size_t)(haystack_end - p)); size_t bytes_q = unicode_utf8_to_utf32(&qchar, q, (size_t)(needle_end - q)); if (bytes_p >= (size_t)-2 || bytes_q >= (size_t)-2) return NULL; // invalid UTF-8 bool same = pchar == qchar; if (pchar < WINT_MAX && qchar < WINT_MAX) // on Windows, there is no way of finding the lower-case version of a codepoint outside the BMP. ): same = towlower((wint_t)pchar) == towlower((wint_t)qchar); if (!same) match = false; p += bytes_p; q += bytes_q; } if (match) return (char *)haystack_start; } 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; } static int strcmp_case_insensitive(char const *a, char const *b) { #if _WIN32 return _stricmp(a, b); #else return strcasecmp(a, b); #endif } // 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; return strcmp_case_insensitive(*a, *b); } static void *qsort_ctx_arg; static int (*qsort_ctx_cmp)(void *, const void *, const void *); static int qsort_with_context_cmp(const void *a, const void *b) { return qsort_ctx_cmp(qsort_ctx_arg, a, b); } static void qsort_with_context(void *base, size_t nmemb, size_t size, int (*compar)(void *, const void *, const void *), void *arg) { // @TODO(eventually): write this yourself // just use global variables. hopefully we don't try to run this in something multithreaded! qsort_ctx_arg = arg; qsort_ctx_cmp = compar; qsort(base, nmemb, size, qsort_with_context_cmp); } // the actual file name part of the path; get rid of the containing directory. // NOTE: the returned string is part of path, so you don't need to free it or anything. static char const *path_filename(char const *path) { char const *last_path_sep = strrchr(path, PATH_SEPARATOR); if (last_path_sep) return last_path_sep + 1; // (a relative path with no path separators) return path; } static bool path_is_absolute(char const *path) { return path[0] == PATH_SEPARATOR #if _WIN32 || path[1] == ':' && path[2] == PATH_SEPARATOR #endif ; }