#include "cpath.h" #include "aliases.h" #include "mem_allocator.h" #include "mem_arena_allocator.h" #include "misc_utils.h" #include "str8.h" #include #include #include #include u32 wapp_cpath_join_path(Str8 *dst, const Str8List *parts) { if (!dst || !parts) { return CPATH_JOIN_INVALID_ARGS; } if (parts->node_count == 0) { return CPATH_JOIN_EMPTY_PARTS; } Str8 separator = wapp_str8_buf(4); wapp_str8_push_back(&separator, PATH_SEP); u64 required_capacity = parts->node_count * separator.size + parts->total_size; if (dst->capacity < required_capacity) { return CPATH_JOIN_INSUFFICIENT_DST_CAPACITY; } // Handle first node const Str8Node *first_node = wapp_str8_list_get(parts, 0); wapp_str8_copy_str8_capped(dst, first_node->string); // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of // MSVC Spectre mitigation warnings const Str8Node *node = first_node; u64 node_index = 1; bool running = true; while (running && node->next) { node = node->next; if (node->string->size == 0) { continue; } if (dst->size > 0) { char dst_last = wapp_str8_get(dst, dst->size - 1); char node_start = wapp_str8_get(node->string, 0); bool add_path_sep = dst_last != PATH_SEP && node_start != PATH_SEP; if (add_path_sep) { wapp_str8_concat_capped(dst, &separator); } } wapp_str8_concat_capped(dst, node->string); ++node_index; running = node_index < parts->node_count; } return CPATH_JOIN_SUCCESS; } 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) { output = wapp_str8_alloc_str8(allocator, path); goto RETURN_DIRUP; } Allocator tmp_arena = wapp_mem_arena_allocator_init(MB(8)); if (wapp_mem_allocator_invalid(&tmp_arena)) { goto RETURN_DIRUP; } Str8List *parts = wapp_str8_split(&tmp_arena, path, &separator); if (!parts) { goto RETURN_DIRUP; } 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); } } } LIST_CLEANUP_DIRUP: wapp_mem_arena_allocator_destroy(&tmp_arena); RETURN_DIRUP: return output; }