134 lines
3.3 KiB
C
134 lines
3.3 KiB
C
#include "cpath.h"
|
|
#include "aliases.h"
|
|
#include "mem_allocator.h"
|
|
#include "mem_arena_allocator.h"
|
|
#include "misc_utils.h"
|
|
#include "str8.h"
|
|
#include <stdarg.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
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;
|
|
}
|