12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037 |
- #if defined(GB_SYSTEM_UNIX)
- // Required for intrinsics on GCC
- #include <xmmintrin.h>
- #endif
- #if defined(GB_COMPILER_MSVC)
- #include <intrin.h>
- #endif
- #if defined(GB_SYSTEM_WINDOWS)
- #define NOMINMAX 1
- #include <windows.h>
- #undef NOMINMAX
- #endif
- #define GB_WINDOWS_H_INCLUDED
- #define GB_IMPLEMENTATION
- #include "gb/gb.h"
- #include <wchar.h>
- #include <stdio.h>
- #if defined(GB_COMPILER_MSVC)
- #include <psapi.h>
- #endif
- #include <math.h>
- #include <string.h>
- gb_inline void zero_size(void *ptr, isize len) {
- memset(ptr, 0, len);
- }
- #define zero_item(ptr) zero_size((ptr), gb_size_of(ptr))
- template <typename U, typename V>
- gb_inline U bit_cast(V &v) { return reinterpret_cast<U &>(v); }
- template <typename U, typename V>
- gb_inline U const &bit_cast(V const &v) { return reinterpret_cast<U const &>(v); }
- gb_inline i64 align_formula(i64 size, i64 align) {
- if (align > 0) {
- i64 result = size + align-1;
- return result - result%align;
- }
- return size;
- }
- gb_inline isize align_formula_isize(isize size, isize align) {
- if (align > 0) {
- isize result = size + align-1;
- return result - result%align;
- }
- return size;
- }
- GB_ALLOCATOR_PROC(heap_allocator_proc);
- gbAllocator heap_allocator(void) {
- gbAllocator a;
- a.proc = heap_allocator_proc;
- a.data = nullptr;
- return a;
- }
- GB_ALLOCATOR_PROC(heap_allocator_proc) {
- void *ptr = nullptr;
- gb_unused(allocator_data);
- gb_unused(old_size);
- // TODO(bill): Throughly test!
- switch (type) {
- #if defined(GB_COMPILER_MSVC)
- #if 0
- case gbAllocation_Alloc:
- ptr = _aligned_malloc(size, alignment);
- if (flags & gbAllocatorFlag_ClearToZero) {
- zero_size(ptr, size);
- }
- break;
- case gbAllocation_Free:
- _aligned_free(old_memory);
- break;
- case gbAllocation_Resize:
- ptr = _aligned_realloc(old_memory, size, alignment);
- break;
- #else
- case gbAllocation_Alloc: {
- isize aligned_size = align_formula_isize(size, alignment);
- // TODO(bill): Make sure this is aligned correctly
- ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, aligned_size);
- } break;
- case gbAllocation_Free:
- HeapFree(GetProcessHeap(), 0, old_memory);
- break;
- case gbAllocation_Resize: {
- isize aligned_size = align_formula_isize(size, alignment);
- ptr = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, old_memory, aligned_size);
- } break;
- #endif
- #elif defined(GB_SYSTEM_LINUX)
- // TODO(bill): *nix version that's decent
- case gbAllocation_Alloc: {
- ptr = aligned_alloc(alignment, size);
- // ptr = malloc(size+alignment);
- if (flags & gbAllocatorFlag_ClearToZero) {
- zero_size(ptr, size);
- }
- break;
- }
- case gbAllocation_Free: {
- free(old_memory);
- break;
- }
- case gbAllocation_Resize: {
- // ptr = realloc(old_memory, size);
- ptr = gb_default_resize_align(heap_allocator(), old_memory, old_size, size, alignment);
- break;
- }
- #else
- // TODO(bill): *nix version that's decent
- case gbAllocation_Alloc: {
- posix_memalign(&ptr, alignment, size);
- if (flags & gbAllocatorFlag_ClearToZero) {
- zero_size(ptr, size);
- }
- break;
- }
- case gbAllocation_Free: {
- free(old_memory);
- break;
- }
- case gbAllocation_Resize: {
- ptr = gb_default_resize_align(heap_allocator(), old_memory, old_size, size, alignment);
- break;
- }
- #endif
- case gbAllocation_FreeAll:
- break;
- }
- return ptr;
- }
- #include "unicode.cpp"
- #include "array.cpp"
- #include "string.cpp"
- #include "murmurhash3.cpp"
- #define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
- #include "range_cache.cpp"
- u32 fnv32a(void const *data, isize len) {
- u8 const *bytes = cast(u8 const *)data;
- u32 h = 0x811c9dc5;
- for (isize i = 0; i < len; i++) {
- u32 b = cast(u32)bytes[i];
- h = (h ^ b) * 0x01000193;
- }
- return h;
- }
- u64 fnv64a(void const *data, isize len) {
- u8 const *bytes = cast(u8 const *)data;
- u64 h = 0xcbf29ce484222325ull;
- for (isize i = 0; i < len; i++) {
- u64 b = cast(u64)bytes[i];
- h = (h ^ b) * 0x100000001b3ull;
- }
- return h;
- }
- u64 u64_digit_value(Rune r) {
- if ('0' <= r && r <= '9') {
- return r - '0';
- } else if ('a' <= r && r <= 'f') {
- return r - 'a' + 10;
- } else if ('A' <= r && r <= 'F') {
- return r - 'A' + 10;
- }
- return 16; // NOTE(bill): Larger than highest possible
- }
- u64 u64_from_string(String string) {
- u64 base = 10;
- bool has_prefix = false;
- if (string.len > 2 && string[0] == '0') {
- switch (string[1]) {
- case 'b': base = 2; has_prefix = true; break;
- case 'o': base = 8; has_prefix = true; break;
- case 'd': base = 10; has_prefix = true; break;
- case 'z': base = 12; has_prefix = true; break;
- case 'x': base = 16; has_prefix = true; break;
- case 'h': base = 16; has_prefix = true; break;
- }
- }
- u8 *text = string.text;
- isize len = string.len;
- if (has_prefix) {
- text += 2;
- len -= 2;
- }
- u64 result = 0ull;
- for (isize i = 0; i < len; i++) {
- Rune r = cast(Rune)text[i];
- if (r == '_') {
- continue;
- }
- u64 v = u64_digit_value(r);
- if (v >= base) {
- break;
- }
- result *= base;
- result += v;
- }
- return result;
- }
- gb_global char const global_num_to_char_table[] =
- "0123456789"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "@$";
- String u64_to_string(u64 v, char *out_buf, isize out_buf_len) {
- char buf[32] = {0};
- isize i = gb_size_of(buf);
- u64 b = 10;
- while (v >= b) {
- buf[--i] = global_num_to_char_table[v%b];
- v /= b;
- }
- buf[--i] = global_num_to_char_table[v%b];
- isize len = gb_min(gb_size_of(buf)-i, out_buf_len);
- gb_memmove(out_buf, &buf[i], len);
- return make_string(cast(u8 *)out_buf, len);
- }
- String i64_to_string(i64 a, char *out_buf, isize out_buf_len) {
- char buf[32] = {0};
- isize i = gb_size_of(buf);
- bool negative = false;
- if (a < 0) {
- negative = true;
- a = -a;
- }
- u64 v = cast(u64)a;
- u64 b = 10;
- while (v >= b) {
- buf[--i] = global_num_to_char_table[v%b];
- v /= b;
- }
- buf[--i] = global_num_to_char_table[v%b];
- if (negative) {
- buf[--i] = '-';
- }
- isize len = gb_min(gb_size_of(buf)-i, out_buf_len);
- gb_memmove(out_buf, &buf[i], len);
- return make_string(cast(u8 *)out_buf, len);
- }
- gb_global i64 const signed_integer_mins[] = {
- 0,
- -128ll,
- -32768ll,
- 0,
- -2147483648ll,
- 0,
- 0,
- 0,
- (-9223372036854775807ll - 1ll),
- };
- gb_global i64 const signed_integer_maxs[] = {
- 0,
- 127ll,
- 32767ll,
- 0,
- 2147483647ll,
- 0,
- 0,
- 0,
- 9223372036854775807ll,
- };
- gb_global u64 const unsigned_integer_maxs[] = {
- 0,
- 255ull,
- 65535ull,
- 0,
- 4294967295ull,
- 0,
- 0,
- 0,
- 18446744073709551615ull,
- };
- bool add_overflow_u64(u64 x, u64 y, u64 *result) {
- *result = x + y;
- return *result < x || *result < y;
- }
- bool sub_overflow_u64(u64 x, u64 y, u64 *result) {
- *result = x - y;
- return *result > x;
- }
- void mul_overflow_u64(u64 x, u64 y, u64 *lo, u64 *hi) {
- #if defined(GB_COMPILER_MSVC)
- *lo = _umul128(x, y, hi);
- #else
- // URL(bill): https://stackoverflow.com/questions/25095741/how-can-i-multiply-64-bit-operands-and-get-128-bit-result-portably#25096197
- u64 u1, v1, w1, t, w3, k;
- u1 = (x & 0xffffffff);
- v1 = (y & 0xffffffff);
- t = (u1 * v1);
- w3 = (t & 0xffffffff);
- k = (t >> 32);
- x >>= 32;
- t = (x * v1) + k;
- k = (t & 0xffffffff);
- w1 = (t >> 32);
- y >>= 32;
- t = (u1 * y) + k;
- k = (t >> 32);
- *hi = (x * y) + w1 + k;
- *lo = (t << 32) + w3;
- #endif
- }
- gb_global String global_module_path = {0};
- gb_global bool global_module_path_set = false;
- // Arena from Per Vognsen
- #define ALIGN_DOWN(n, a) ((n) & ~((a) - 1))
- #define ALIGN_UP(n, a) ALIGN_DOWN((n) + (a) - 1, (a))
- #define ALIGN_DOWN_PTR(p, a) (cast(void *)ALIGN_DOWN(cast(uintptr)(p), (a)))
- #define ALIGN_UP_PTR(p, a) (cast(void *)ALIGN_UP(cast(uintptr)(p), (a)))
- typedef struct Arena {
- u8 * ptr;
- u8 * end;
- u8 * prev;
- Array<u8 *> blocks;
- gbAllocator backing;
- isize block_size;
- gbMutex mutex;
- isize total_used;
- } Arena;
- #define ARENA_MIN_ALIGNMENT 16
- #define ARENA_DEFAULT_BLOCK_SIZE (8*1024*1024)
- void arena_init(Arena *arena, gbAllocator backing, isize block_size=ARENA_DEFAULT_BLOCK_SIZE) {
- arena->backing = backing;
- arena->block_size = block_size;
- array_init(&arena->blocks, backing, 0, 2);
- gb_mutex_init(&arena->mutex);
- }
- void arena_grow(Arena *arena, isize min_size) {
- // gb_mutex_lock(&arena->mutex);
- // defer (gb_mutex_unlock(&arena->mutex));
- isize size = gb_max(arena->block_size, min_size);
- size = ALIGN_UP(size, ARENA_MIN_ALIGNMENT);
- void *new_ptr = gb_alloc(arena->backing, size);
- arena->ptr = cast(u8 *)new_ptr;
- // zero_size(arena->ptr, size); // NOTE(bill): This should already be zeroed
- GB_ASSERT(arena->ptr == ALIGN_DOWN_PTR(arena->ptr, ARENA_MIN_ALIGNMENT));
- arena->end = arena->ptr + size;
- array_add(&arena->blocks, arena->ptr);
- }
- void *arena_alloc(Arena *arena, isize size, isize alignment) {
- // gb_mutex_lock(&arena->mutex);
- // defer (gb_mutex_unlock(&arena->mutex));
- arena->total_used += size;
- if (size > (arena->end - arena->ptr)) {
- arena_grow(arena, size);
- GB_ASSERT(size <= (arena->end - arena->ptr));
- }
- isize align = gb_max(alignment, ARENA_MIN_ALIGNMENT);
- void *ptr = arena->ptr;
- arena->prev = arena->ptr;
- arena->ptr = cast(u8 *)ALIGN_UP_PTR(arena->ptr + size, align);
- GB_ASSERT(arena->ptr <= arena->end);
- GB_ASSERT(ptr == ALIGN_DOWN_PTR(ptr, align));
- // zero_size(ptr, size);
- return ptr;
- }
- void arena_free_all(Arena *arena) {
- // gb_mutex_lock(&arena->mutex);
- // defer (gb_mutex_unlock(&arena->mutex));
- for_array(i, arena->blocks) {
- gb_free(arena->backing, arena->blocks[i]);
- }
- array_clear(&arena->blocks);
- arena->ptr = nullptr;
- arena->end = nullptr;
- }
- GB_ALLOCATOR_PROC(arena_allocator_proc);
- gbAllocator arena_allocator(Arena *arena) {
- gbAllocator a;
- a.proc = arena_allocator_proc;
- a.data = arena;
- return a;
- }
- GB_ALLOCATOR_PROC(arena_allocator_proc) {
- void *ptr = nullptr;
- Arena *arena = cast(Arena *)allocator_data;
- GB_ASSERT_NOT_NULL(arena);
- switch (type) {
- case gbAllocation_Alloc:
- ptr = arena_alloc(arena, size, alignment);
- break;
- case gbAllocation_Free:
- // GB_PANIC("gbAllocation_Free not supported");
- break;
- case gbAllocation_Resize:
- GB_PANIC("gbAllocation_Resize: not supported");
- break;
- case gbAllocation_FreeAll:
- arena_free_all(arena);
- break;
- }
- return ptr;
- }
- #include "string_map.cpp"
- #include "map.cpp"
- #include "ptr_set.cpp"
- #include "string_set.cpp"
- #include "priority_queue.cpp"
- #include "thread_pool.cpp"
- struct StringIntern {
- StringIntern *next;
- isize len;
- char str[1];
- };
- Map<StringIntern *> string_intern_map = {}; // Key: u64
- Arena string_intern_arena = {};
- char const *string_intern(char const *text, isize len) {
- u64 hash = gb_fnv64a(text, len);
- u64 key = hash ? hash : 1;
- StringIntern **found = map_get(&string_intern_map, hash_integer(key));
- if (found) {
- for (StringIntern *it = *found; it != nullptr; it = it->next) {
- if (it->len == len && gb_strncmp(it->str, (char *)text, len) == 0) {
- return it->str;
- }
- }
- }
- StringIntern *new_intern = cast(StringIntern *)arena_alloc(&string_intern_arena, gb_offset_of(StringIntern, str) + len + 1, gb_align_of(StringIntern));
- new_intern->len = len;
- new_intern->next = found ? *found : nullptr;
- gb_memmove(new_intern->str, text, len);
- new_intern->str[len] = 0;
- map_set(&string_intern_map, hash_integer(key), new_intern);
- return new_intern->str;
- }
- char const *string_intern(String const &string) {
- return string_intern(cast(char const *)string.text, string.len);
- }
- void init_string_interner(void) {
- map_init(&string_intern_map, heap_allocator());
- arena_init(&string_intern_arena, heap_allocator());
- }
- i32 next_pow2(i32 n) {
- if (n <= 0) {
- return 0;
- }
- n--;
- n |= n >> 1;
- n |= n >> 2;
- n |= n >> 4;
- n |= n >> 8;
- n |= n >> 16;
- n++;
- return n;
- }
- i64 next_pow2(i64 n) {
- if (n <= 0) {
- return 0;
- }
- n--;
- n |= n >> 1;
- n |= n >> 2;
- n |= n >> 4;
- n |= n >> 8;
- n |= n >> 16;
- n |= n >> 32;
- n++;
- return n;
- }
- i32 bit_set_count(u32 x) {
- x -= ((x >> 1) & 0x55555555);
- x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
- x = (((x >> 4) + x) & 0x0f0f0f0f);
- x += (x >> 8);
- x += (x >> 16);
- return cast(i32)(x & 0x0000003f);
- }
- i64 bit_set_count(u64 x) {
- u32 a = *(cast(u32 *)&x);
- u32 b = *(cast(u32 *)&x + 1);
- return bit_set_count(a) + bit_set_count(b);
- }
- u32 floor_log2(u32 x) {
- x |= x >> 1;
- x |= x >> 2;
- x |= x >> 4;
- x |= x >> 8;
- x |= x >> 16;
- return cast(u32)(bit_set_count(x) - 1);
- }
- u64 floor_log2(u64 x) {
- x |= x >> 1;
- x |= x >> 2;
- x |= x >> 4;
- x |= x >> 8;
- x |= x >> 16;
- x |= x >> 32;
- return cast(u64)(bit_set_count(x) - 1);
- }
- u32 ceil_log2(u32 x) {
- i32 y = cast(i32)(x & (x-1));
- y |= -y;
- y >>= 32-1;
- x |= x >> 1;
- x |= x >> 2;
- x |= x >> 4;
- x |= x >> 8;
- x |= x >> 16;
- return cast(u32)(bit_set_count(x) - 1 - y);
- }
- u64 ceil_log2(u64 x) {
- i64 y = cast(i64)(x & (x-1));
- y |= -y;
- y >>= 64-1;
- x |= x >> 1;
- x |= x >> 2;
- x |= x >> 4;
- x |= x >> 8;
- x |= x >> 16;
- x |= x >> 32;
- return cast(u64)(bit_set_count(x) - 1 - y);
- }
- i32 prev_pow2(i32 n) {
- if (n <= 0) {
- return 0;
- }
- n |= n >> 1;
- n |= n >> 2;
- n |= n >> 4;
- n |= n >> 8;
- n |= n >> 16;
- return n - (n >> 1);
- }
- i64 prev_pow2(i64 n) {
- if (n <= 0) {
- return 0;
- }
- n |= n >> 1;
- n |= n >> 2;
- n |= n >> 4;
- n |= n >> 8;
- n |= n >> 16;
- n |= n >> 32;
- return n - (n >> 1);
- }
- i16 f32_to_f16(f32 value) {
- union { u32 i; f32 f; } v;
- i32 i, s, e, m;
- v.f = value;
- i = (i32)v.i;
- s = (i >> 16) & 0x00008000;
- e = ((i >> 23) & 0x000000ff) - (127 - 15);
- m = i & 0x007fffff;
- if (e <= 0) {
- if (e < -10) return cast(i16)s;
- m = (m | 0x00800000) >> (1 - e);
- if (m & 0x00001000)
- m += 0x00002000;
- return cast(i16)(s | (m >> 13));
- } else if (e == 0xff - (127 - 15)) {
- if (m == 0) {
- return cast(i16)(s | 0x7c00); /* NOTE(bill): infinity */
- } else {
- /* NOTE(bill): NAN */
- m >>= 13;
- return cast(i16)(s | 0x7c00 | m | (m == 0));
- }
- } else {
- if (m & 0x00001000) {
- m += 0x00002000;
- if (m & 0x00800000) {
- m = 0;
- e += 1;
- }
- }
- if (e > 30) {
- float volatile f = 1e12f;
- int j;
- for (j = 0; j < 10; j++) {
- f *= f; /* NOTE(bill): Cause overflow */
- }
- return cast(i16)(s | 0x7c00);
- }
- return cast(i16)(s | (e << 10) | (m >> 13));
- }
- }
- f64 gb_sqrt(f64 x) {
- return sqrt(x);
- }
- // Doubly Linked Lists
- #define DLIST_SET(curr_element, next_element) do { \
- (curr_element)->next = (next_element); \
- (curr_element)->next->prev = (curr_element); \
- (curr_element) = (curr_element)->next; \
- } while (0)
- #define DLIST_APPEND(root_element, curr_element, next_element) do { \
- if ((root_element) == nullptr) { \
- (root_element) = (curr_element) = (next_element); \
- } else { \
- DLIST_SET(curr_element, next_element); \
- } \
- } while (0)
- #if defined(GB_SYSTEM_WINDOWS)
- wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) {
- u32 i, j;
- u32 len = cast(u32)string16_len(cmd_line);
- i = ((len+2)/2)*gb_size_of(void *) + gb_size_of(void *);
- wchar_t **argv = cast(wchar_t **)GlobalAlloc(GMEM_FIXED, i + (len+2)*gb_size_of(wchar_t));
- wchar_t *_argv = cast(wchar_t *)((cast(u8 *)argv)+i);
- u32 argc = 0;
- argv[argc] = _argv;
- bool in_quote = false;
- bool in_text = false;
- bool in_space = true;
- i = 0;
- j = 0;
- for (;;) {
- wchar_t a = cmd_line[i];
- if (a == 0) {
- break;
- }
- if (in_quote) {
- if (a == '\"') {
- in_quote = false;
- } else {
- _argv[j++] = a;
- }
- } else {
- switch (a) {
- case '\"':
- in_quote = true;
- in_text = true;
- if (in_space) argv[argc++] = _argv+j;
- in_space = false;
- break;
- case ' ':
- case '\t':
- case '\n':
- case '\r':
- if (in_text) _argv[j++] = '\0';
- in_text = false;
- in_space = true;
- break;
- default:
- in_text = true;
- if (in_space) argv[argc++] = _argv+j;
- _argv[j++] = a;
- in_space = false;
- break;
- }
- }
- i++;
- }
- _argv[j] = '\0';
- argv[argc] = nullptr;
- if (_argc) *_argc = argc;
- return argv;
- }
- #endif
- #if defined(GB_SYSTEM_WINDOWS)
- bool path_is_directory(String path) {
- gbAllocator a = heap_allocator();
- String16 wstr = string_to_string16(a, path);
- defer (gb_free(a, wstr.text));
- i32 attribs = GetFileAttributesW(wstr.text);
- if (attribs < 0) return false;
- return (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0;
- }
- #else
- bool path_is_directory(String path) {
- gbAllocator a = heap_allocator();
- char *copy = cast(char *)copy_string(a, path).text;
- defer (gb_free(a, copy));
- struct stat s;
- if (stat(copy, &s) == 0) {
- return (s.st_mode & S_IFDIR) != 0;
- }
- return false;
- }
- #endif
- String path_to_full_path(gbAllocator a, String path) {
- gbAllocator ha = heap_allocator();
- char *path_c = gb_alloc_str_len(ha, cast(char *)path.text, path.len);
- defer (gb_free(ha, path_c));
- char *fullpath = gb_path_get_full_name(a, path_c);
- String res = string_trim_whitespace(make_string_c(fullpath));
- #if defined(GB_SYSTEM_WINDOWS)
- for (isize i = 0; i < res.len; i++) {
- if (res.text[i] == '\\') {
- res.text[i] = '/';
- }
- }
- #endif
- return res;
- }
- struct FileInfo {
- String name;
- String fullpath;
- i64 size;
- bool is_dir;
- };
- enum ReadDirectoryError {
- ReadDirectory_None,
- ReadDirectory_InvalidPath,
- ReadDirectory_NotExists,
- ReadDirectory_Permission,
- ReadDirectory_NotDir,
- ReadDirectory_Empty,
- ReadDirectory_Unknown,
- ReadDirectory_COUNT,
- };
- i64 get_file_size(String path) {
- char *c_str = alloc_cstring(heap_allocator(), path);
- defer (gb_free(heap_allocator(), c_str));
- gbFile f = {};
- gbFileError err = gb_file_open(&f, c_str);
- defer (gb_file_close(&f));
- if (err != gbFileError_None) {
- return -1;
- }
- return gb_file_size(&f);
- }
- #if defined(GB_SYSTEM_WINDOWS)
- ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
- GB_ASSERT(fi != nullptr);
- gbAllocator a = heap_allocator();
- while (path.len > 0) {
- Rune end = path[path.len-1];
- if (end == '/') {
- path.len -= 1;
- } else if (end == '\\') {
- path.len -= 1;
- } else {
- break;
- }
- }
- if (path.len == 0) {
- return ReadDirectory_InvalidPath;
- }
- {
- char *c_str = alloc_cstring(a, path);
- defer (gb_free(a, c_str));
- gbFile f = {};
- gbFileError file_err = gb_file_open(&f, c_str);
- defer (gb_file_close(&f));
- switch (file_err) {
- case gbFileError_Invalid: return ReadDirectory_InvalidPath;
- case gbFileError_NotExists: return ReadDirectory_NotExists;
- // case gbFileError_Permission: return ReadDirectory_Permission;
- }
- }
- if (!path_is_directory(path)) {
- return ReadDirectory_NotDir;
- }
- char *new_path = gb_alloc_array(a, char, path.len+3);
- defer (gb_free(a, new_path));
- gb_memmove(new_path, path.text, path.len);
- gb_memmove(new_path+path.len, "/*", 2);
- new_path[path.len+2] = 0;
- String np = make_string(cast(u8 *)new_path, path.len+2);
- String16 wstr = string_to_string16(a, np);
- defer (gb_free(a, wstr.text));
- WIN32_FIND_DATAW file_data = {};
- HANDLE find_file = FindFirstFileW(wstr.text, &file_data);
- if (find_file == INVALID_HANDLE_VALUE) {
- return ReadDirectory_Unknown;
- }
- defer (FindClose(find_file));
- array_init(fi, a, 0, 100);
- do {
- wchar_t *filename_w = file_data.cFileName;
- i64 size = cast(i64)file_data.nFileSizeLow;
- size |= (cast(i64)file_data.nFileSizeHigh) << 32;
- String name = string16_to_string(a, make_string16_c(filename_w));
- if (name == "." || name == "..") {
- gb_free(a, name.text);
- continue;
- }
- String filepath = {};
- filepath.len = path.len+1+name.len;
- filepath.text = gb_alloc_array(a, u8, filepath.len+1);
- defer (gb_free(a, filepath.text));
- gb_memmove(filepath.text, path.text, path.len);
- gb_memmove(filepath.text+path.len, "/", 1);
- gb_memmove(filepath.text+path.len+1, name.text, name.len);
- FileInfo info = {};
- info.name = name;
- info.fullpath = path_to_full_path(a, filepath);
- info.size = size;
- info.is_dir = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
- array_add(fi, info);
- } while (FindNextFileW(find_file, &file_data));
- if (fi->count == 0) {
- return ReadDirectory_Empty;
- }
- return ReadDirectory_None;
- }
- #elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_FREEBSD)
- #include <dirent.h>
- ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
- GB_ASSERT(fi != nullptr);
- gbAllocator a = heap_allocator();
- char *c_path = alloc_cstring(a, path);
- defer (gb_free(a, c_path));
- DIR *dir = opendir(c_path);
- if (!dir) {
- switch (errno) {
- case ENOENT:
- return ReadDirectory_NotExists;
- case EACCES:
- return ReadDirectory_Permission;
- case ENOTDIR:
- return ReadDirectory_NotDir;
- default:
- // ENOMEM: out of memory
- // EMFILE: per-process limit on open fds reached
- // ENFILE: system-wide limit on total open files reached
- return ReadDirectory_Unknown;
- }
- GB_PANIC("unreachable");
- }
- array_init(fi, a, 0, 100);
- for (;;) {
- struct dirent *entry = readdir(dir);
- if (entry == nullptr) {
- break;
- }
- String name = make_string_c(entry->d_name);
- if (name == "." || name == "..") {
- continue;
- }
- String filepath = {};
- filepath.len = path.len+1+name.len;
- filepath.text = gb_alloc_array(a, u8, filepath.len+1);
- defer (gb_free(a, filepath.text));
- gb_memmove(filepath.text, path.text, path.len);
- gb_memmove(filepath.text+path.len, "/", 1);
- gb_memmove(filepath.text+path.len+1, name.text, name.len);
- filepath.text[filepath.len] = 0;
- struct stat dir_stat = {};
- if (stat((char *)filepath.text, &dir_stat)) {
- continue;
- }
- if (S_ISDIR(dir_stat.st_mode)) {
- continue;
- }
- i64 size = dir_stat.st_size;
- FileInfo info = {};
- info.name = name;
- info.fullpath = path_to_full_path(a, filepath);
- info.size = size;
- array_add(fi, info);
- }
- if (fi->count == 0) {
- return ReadDirectory_Empty;
- }
- return ReadDirectory_None;
- }
- #else
- #error Implement read_directory
- #endif
|