// vim:fileencoding=utf-8:foldmethod=marker #include "cpath.h" #include "../allocators/arena/mem_arena_allocator.h" #include "../../common/aliases/aliases.h" #include "../../common/misc/misc_utils.h" #include "../../base/dbl_list/dbl_list.h" #include "../../base/mem/allocator/mem_allocator.h" #include "../../base/strings/str8/str8.h" #include #include #include u32 wapp_cpath_join_path(WpStr8 *dst, const WpStr8List *parts) { if (!dst || !parts) { return CPATH_JOIN_INVALID_ARGS; } if (parts->node_count == 0) { return CPATH_JOIN_EMPTY_PARTS; } WpStr8 separator = wpStr8Buf(4); wpStr8PushBack(&separator, WAPP_PATH_SEP); u64 required_capacity = parts->node_count * separator.size + wpStr8ListTotalSize(parts); if (dst->capacity < required_capacity) { return CPATH_JOIN_INSUFFICIENT_DST_CAPACITY; } // Handle first node WpStr8 *first_node = wapp_dbl_list_get(WpStr8, parts, 0); wpStr8CopyStr8Capped(dst, first_node); // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of // MSVC Spectre mitigation warnings WpStr8 *node = first_node; u64 node_index = 1; b8 running = node_index < parts->node_count; while (running) { node = wapp_dbl_list_get(WpStr8, parts, node_index); if (node->size == 0) { goto CPATH_JOIN_LOOP_END; } if (dst->size > 0) { char dst_last = wpStr8Get(dst, dst->size - 1); char node_start = wpStr8Get(node, 0); b8 add_path_sep = dst_last != WAPP_PATH_SEP && node_start != WAPP_PATH_SEP; if (add_path_sep) { wpStr8ConcatCapped(dst, &separator); } } wpStr8ConcatCapped(dst, node); CPATH_JOIN_LOOP_END: ++node_index; running = node_index < parts->node_count; } return CPATH_JOIN_SUCCESS; } WpStr8 *dirup(const WpAllocator *allocator, WpStr8RO *path, u64 levels) { WpStr8 *output = NULL; if (!allocator || !path) { goto RETURN_DIRUP; } b8 absolute = wpStr8Get(path, 0) == WAPP_PATH_SEP; WpStr8 separator = wpStr8Buf(4); wpStr8PushBack(&separator, WAPP_PATH_SEP); if (path->size == 0) { output = wpStr8AllocBuf(allocator, 16); if (!output) { goto RETURN_DIRUP; } wpStr8PushBack(output, absolute ? WAPP_PATH_SEP : '.'); goto RETURN_DIRUP; } if (levels < 1) { output = wpStr8AllocStr8(allocator, path); goto RETURN_DIRUP; } WpAllocator tmp_arena = wapp_mem_arena_allocator_init(MiB(8)); if (wpMemAllocatorInvalid(&tmp_arena)) { goto RETURN_DIRUP; } WpStr8List *parts = wpStr8Split(&tmp_arena, path, &separator); if (!parts) { goto RETURN_DIRUP; } if (levels >= parts->node_count) { output = wpStr8AllocBuf(allocator, 16); if (!output) { goto LIST_CLEANUP_DIRUP; } wpStr8PushBack(output, absolute ? WAPP_PATH_SEP : '.'); } else { for (u64 i = 0; i < levels; ++i) { wapp_dbl_list_pop_back(WpStr8, parts); } u64 alignment = sizeof(void *) * 2; u64 alloc_size = wpStr8ListTotalSize(parts) + parts->node_count * separator.size; u64 modulo = alloc_size & (alignment - 1); alloc_size += alignment - modulo; output = wpStr8AllocBuf(allocator, alloc_size); if (output) { if (absolute) { wpStr8PushBack(output, WAPP_PATH_SEP); } WpStr8 *joined = wpStr8Join(&tmp_arena, parts, &separator); if (joined) { wpStr8ConcatCapped(output, joined); } } } LIST_CLEANUP_DIRUP: wapp_mem_arena_allocator_destroy(&tmp_arena); RETURN_DIRUP: return output; }