diff --git a/src/os/cpath/cpath.c b/src/os/cpath/cpath.c index b7ef7a9..cc74b7d 100644 --- a/src/os/cpath/cpath.c +++ b/src/os/cpath/cpath.c @@ -1,5 +1,8 @@ #include "cpath.h" #include "aliases.h" +#include "mem_allocator.h" +#include "mem_arena_allocator.h" +#include "misc_utils.h" #include "str8.h" #include #include @@ -59,56 +62,76 @@ u32 wapp_cpath_join_path(Str8 *dst, const Str8List *parts) { return CPATH_JOIN_SUCCESS; } -void dirup(char *dst, u64 levels, const char *path) { +Str8 *dirup(const Allocator *allocator, Str8RO *path, u64 levels) { + Str8 *output = NULL; + if (!allocator || !path) { + goto RETURN_DIRUP; + } + + bool absolute = wapp_str8_get(path, 0) == PATH_SEP; + Str8 separator = wapp_str8_buf(4); + wapp_str8_push_back(&separator, PATH_SEP); + + if (path->size == 0) { + output = wapp_str8_alloc_buf(allocator, 16); + if (!output) { + goto RETURN_DIRUP; + } + + wapp_str8_push_back(output, absolute ? PATH_SEP : '.'); + goto RETURN_DIRUP; + } + if (levels < 1) { - return; + output = wapp_str8_alloc_str8(allocator, path); + goto RETURN_DIRUP; } - u64 copy_count = 0; - u64 sep_count = 0; - - u64 full_length; - u64 length; - length = full_length = strlen(path); - - if (length > 1 && path[length - 1] == PATH_SEP) { - --length; + Allocator tmp_arena = wapp_mem_arena_allocator_init(MB(8)); + if (wapp_mem_allocator_invalid(&tmp_arena)) { + goto RETURN_DIRUP; } - for (i64 i = length - 1; i >= 0; --i) { - if (path[i] == PATH_SEP) { - ++sep_count; - copy_count = i + 1; + Str8List *parts = wapp_str8_split(&tmp_arena, path, &separator); + if (!parts) { + goto RETURN_DIRUP; + } - if (sep_count == levels) { - break; + if (levels >= parts->node_count) { + output = wapp_str8_alloc_buf(allocator, 16); + if (!output) { + goto LIST_CLEANUP_DIRUP; + } + + wapp_str8_push_back(output, absolute ? PATH_SEP : '.'); + } else { + for (u64 i = 0; i < levels; ++i) { + wapp_str8_list_pop_back(parts); + } + + u64 alignment = sizeof(void *) * 2; + u64 alloc_size = parts->total_size + parts->node_count * separator.size; + u64 modulo = alloc_size & (alignment - 1); + alloc_size += alignment - modulo; + + output = wapp_str8_alloc_buf(allocator, alloc_size); + if (output) { + if (absolute) { + wapp_str8_push_back(output, PATH_SEP); + } + + Str8 *joined = wapp_str8_join(&tmp_arena, parts, &separator); + if (joined) { + wapp_str8_concat_capped(output, joined); } } } - char tmp[256]; - snprintf(tmp, 2, "%c", PATH_SEP); - // NOTE (Abdelrahman): Conditions stored in variables to silence MSVC warning C5045 - bool insufficient_levels = sep_count < levels; - bool path_to_copy_is_separator = strncmp(path, tmp, copy_count) != 0; - if (insufficient_levels && path_to_copy_is_separator) { - copy_count = 0; - } +LIST_CLEANUP_DIRUP: + wapp_mem_arena_allocator_destroy(&tmp_arena); - if (dst == path) { - memset(&dst[copy_count], 0, full_length - copy_count); - } else { - u64 dst_length = strlen(dst); - memset(dst, 0, dst_length); - strncpy(dst, path, copy_count); - } - - u64 final_length = strlen(dst); - if (final_length > 1) { - dst[final_length - 1] = '\0'; - } else if (final_length == 0) { - dst[0] = '.'; - } +RETURN_DIRUP: + return output; } void join_root_and_leaf(const char *root, const char *leaf, char *dst) { diff --git a/src/os/cpath/cpath.h b/src/os/cpath/cpath.h index f3c1ee5..1f0bc0c 100644 --- a/src/os/cpath/cpath.h +++ b/src/os/cpath/cpath.h @@ -2,6 +2,7 @@ #define CPATH_H #include "aliases.h" +#include "mem_allocator.h" #include "platform.h" #include "str8.h" @@ -17,8 +18,8 @@ BEGIN_C_LINKAGE #error "Unrecognised platform" #endif -#define wapp_cpath_dirname(DST, PATH) dirup(DST, 1, PATH) -#define wapp_cpath_dirup(DST, COUNT, PATH) dirup(DST, COUNT, PATH) +#define wapp_cpath_dirname(ALLOCATOR, PATH) dirup(ALLOCATOR, PATH, 1) +#define wapp_cpath_dirup(ALLOCATOR, PATH, COUNT) dirup(ALLOCATOR, PATH, COUNT) enum { CPATH_JOIN_SUCCESS = 0, @@ -28,7 +29,7 @@ enum { }; u32 wapp_cpath_join_path(Str8 *dst, const Str8List *parts); -void dirup(char *dst, u64 levels, const char *path); +Str8 *dirup(const Allocator *allocator, Str8RO *path, u64 levels); #ifdef __cplusplus END_C_LINKAGE diff --git a/tests/cpath/test_cpath.c b/tests/cpath/test_cpath.c index d7c5db3..5f789f0 100644 --- a/tests/cpath/test_cpath.c +++ b/tests/cpath/test_cpath.c @@ -1,5 +1,8 @@ #include "test_cpath.h" #include "cpath.h" +#include "mem_allocator.h" +#include "mem_arena_allocator.h" +#include "misc_utils.h" #include "str8.h" #include "tester.h" #include @@ -84,100 +87,101 @@ TestFuncResult test_cpath_join_path(void) { } TestFuncResult test_cpath_dirname(void) { - char dst[MAIN_BUF_SIZE] = {0}; - char expected[MAIN_BUF_SIZE] = {0}; - char tmp[TMP_BUF_SIZE] = {0}; - - snprintf(tmp, 2, "%c", PATH_SEP); - wapp_cpath_dirname(dst, tmp); - bool result = strcmp(dst, tmp) == 0; - if (!result) { - goto TEST_DIRNAME_EXIT; + Allocator arena = wapp_mem_arena_allocator_init(MB(8)); + if (wapp_mem_allocator_invalid(&arena)) { + return wapp_tester_result(false); } - memset(dst, 0, strlen(dst)); - wapp_cpath_dirname(dst, "home"); - result = strcmp(dst, ".") == 0; - if (!result) { - goto TEST_DIRNAME_EXIT; - } + bool result; + Str8 *output = NULL; - memset(dst, 0, strlen(dst)); - wapp_cpath_dirname(dst, ""); - result = strcmp(dst, ".") == 0; - if (!result) { - goto TEST_DIRNAME_EXIT; - } + Str8 expected = wapp_str8_buf(MAIN_BUF_SIZE); + Str8 tmp = wapp_str8_buf(TMP_BUF_SIZE); - memset(dst, 0, strlen(dst)); - snprintf(tmp, TMP_BUF_SIZE, "%chome%ctest", PATH_SEP, PATH_SEP); - snprintf(expected, MAIN_BUF_SIZE, "%chome", PATH_SEP); - wapp_cpath_dirname(dst, tmp); - result = strcmp(dst, expected) == 0; - if (!result) { - goto TEST_DIRNAME_EXIT; - } + // CASE 1 + wapp_str8_format(&tmp, "%c", PATH_SEP); + wapp_str8_format(&expected, "%c", PATH_SEP); - memset(dst, 0, strlen(dst)); - memset(tmp, 0, strlen(tmp)); - memset(expected, 0, strlen(expected)); - snprintf(tmp, TMP_BUF_SIZE, "%chome%ctest%c", PATH_SEP, PATH_SEP, PATH_SEP); - snprintf(expected, MAIN_BUF_SIZE, "%chome", PATH_SEP); - wapp_cpath_dirname(dst, tmp); - result = strcmp(dst, expected) == 0; + output = wapp_cpath_dirname(&arena, &tmp); + result = output != NULL && wapp_str8_equal(output, &expected); + + // CASE 2 + wapp_str8_format(&expected, "%s", "."); + + output = wapp_cpath_dirname(&arena, &wapp_str8_lit("home")); + result = result && output != NULL && wapp_str8_equal(output, &expected); + + // CASE 3 + output = wapp_cpath_dirname(&arena, &wapp_str8_lit("")); + result = result && output != NULL && wapp_str8_equal(output, &expected); + + // CASE 4 + wapp_str8_format(&tmp, "%chome%ctest", PATH_SEP, PATH_SEP); + wapp_str8_format(&expected, "%chome", PATH_SEP); + + output = wapp_cpath_dirname(&arena, &tmp); + result = result && output != NULL && wapp_str8_equal(output, &expected); + + // CASE 5 + wapp_str8_format(&tmp, "%chome%ctest%c", PATH_SEP, PATH_SEP, PATH_SEP); + wapp_str8_format(&expected, "%chome", PATH_SEP); + + output = wapp_cpath_dirname(&arena, &tmp); + result = result && output != NULL && wapp_str8_equal(output, &expected); + + wapp_mem_arena_allocator_destroy(&arena); -TEST_DIRNAME_EXIT: return wapp_tester_result(result); } TestFuncResult test_cpath_dirup(void) { - char dst[MAIN_BUF_SIZE] = {0}; - char expected[MAIN_BUF_SIZE] = {0}; - char tmp[TMP_BUF_SIZE] = {0}; - - snprintf(tmp, 2, "%c", PATH_SEP); - wapp_cpath_dirup(dst, 3, tmp); - bool result = strcmp(dst, tmp) == 0; - if (!result) { - goto TEST_DIRUP_EXIT; + Allocator arena = wapp_mem_arena_allocator_init(MB(8)); + if (wapp_mem_allocator_invalid(&arena)) { + return wapp_tester_result(false); } - memset(dst, 0, strlen(dst)); - memset(tmp, 0, strlen(tmp)); - snprintf(tmp, TMP_BUF_SIZE, "%chome%cabdelrahman%cDocuments", PATH_SEP, PATH_SEP, PATH_SEP); - snprintf(expected, MAIN_BUF_SIZE, "%c", PATH_SEP); - wapp_cpath_dirup(dst, 3, tmp); - result = strcmp(dst, expected) == 0; - if (!result) { - goto TEST_DIRUP_EXIT; - } + bool result; + Str8 *output = NULL; - memset(dst, 0, strlen(dst)); - memset(tmp, 0, strlen(tmp)); - snprintf(tmp, TMP_BUF_SIZE, "home%cabdelrahman%cDocuments", PATH_SEP, PATH_SEP); - wapp_cpath_dirup(dst, 3, tmp); - result = strcmp(dst, ".") == 0; - if (!result) { - goto TEST_DIRUP_EXIT; - } + Str8 expected = wapp_str8_buf(MAIN_BUF_SIZE); + Str8 tmp = wapp_str8_buf(TMP_BUF_SIZE); - memset(dst, 0, strlen(dst)); - memset(tmp, 0, strlen(tmp)); - memset(expected, 0, strlen(expected)); - snprintf(tmp, TMP_BUF_SIZE, "%chome%cabdelrahman%cDocuments", PATH_SEP, PATH_SEP, PATH_SEP); - snprintf(expected, MAIN_BUF_SIZE, "%chome", PATH_SEP); - wapp_cpath_dirup(dst, 2, tmp); - result = strcmp(dst, expected) == 0; - if (!result) { - goto TEST_DIRUP_EXIT; - } + // CASE 1 + wapp_str8_format(&tmp, "%c", PATH_SEP); + wapp_str8_format(&expected, "%c", PATH_SEP); - memset(dst, 0, strlen(dst)); - memset(tmp, 0, strlen(tmp)); - snprintf(tmp, TMP_BUF_SIZE, "home%cabdelrahman%cDocuments", PATH_SEP, PATH_SEP); - wapp_cpath_dirup(dst, 2, tmp); - result = strcmp(dst, "home") == 0; + output = wapp_cpath_dirup(&arena, &tmp, 3); + result = output != NULL && wapp_str8_equal(output, &expected); + + // CASE 2 + wapp_str8_format(&tmp, "%chome%cabdelrahman%cDocuments", PATH_SEP, PATH_SEP, PATH_SEP); + wapp_str8_format(&expected, "%c", PATH_SEP); + + output = wapp_cpath_dirup(&arena, &tmp, 3); + result = result && output != NULL && wapp_str8_equal(output, &expected); + + // CASE 3 + wapp_str8_format(&tmp, "home%cabdelrahman%cDocuments", PATH_SEP, PATH_SEP); + wapp_str8_copy_cstr_capped(&expected, "."); + + output = wapp_cpath_dirup(&arena, &tmp, 3); + result = result && output != NULL && wapp_str8_equal(output, &expected); + + // CASE 4 + wapp_str8_format(&tmp, "%chome%cabdelrahman%cDocuments", PATH_SEP, PATH_SEP, PATH_SEP); + wapp_str8_format(&expected, "%chome", PATH_SEP); + + output = wapp_cpath_dirup(&arena, &tmp, 2); + result = result && output != NULL && wapp_str8_equal(output, &expected); + + // CASE 5 + wapp_str8_format(&tmp, "home%cabdelrahman%cDocuments", PATH_SEP, PATH_SEP); + wapp_str8_copy_cstr_capped(&expected, "home"); + + output = wapp_cpath_dirup(&arena, &tmp, 2); + result = result && output != NULL && wapp_str8_equal(output, &expected); + + wapp_mem_arena_allocator_destroy(&arena); -TEST_DIRUP_EXIT: return wapp_tester_result(result); }