aboutsummaryrefslogtreecommitdiff
path: root/filesystem/src/path.c
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2024-06-15 11:42:48 -0700
committer3gg <3gg@shellblade.net>2024-06-15 11:42:48 -0700
commit04e3ded4c28c0b559620609daaae7b939d776b61 (patch)
tree55efea02bee351ac01ef764a04105ee9cee69259 /filesystem/src/path.c
parent993424547df0d253d546dbe7adee9b2448294b08 (diff)
Add path.
Diffstat (limited to 'filesystem/src/path.c')
-rw-r--r--filesystem/src/path.c104
1 files changed, 104 insertions, 0 deletions
diff --git a/filesystem/src/path.c b/filesystem/src/path.c
new file mode 100644
index 0000000..2ce5a04
--- /dev/null
+++ b/filesystem/src/path.c
@@ -0,0 +1,104 @@
1#include <path.h>
2
3#include <cassert.h>
4#include <stdlib.h>
5#include <string.h>
6
7static const path Empty = (path){0, 0};
8
9path path_new(const char* str) {
10 assert(str);
11 const size_t size = strlen(str);
12 if (size > 0) {
13 char* data = calloc(size + 1, sizeof(char)); // +1 for null
14 memcpy(data, str, size);
15 data[size] = 0;
16 return (path){data, size};
17 }
18 return Empty;
19}
20
21void path_del(path* path) {
22 if (path) {
23 free(path->data);
24 path->data = 0;
25 path->size = 0;
26 }
27}
28
29path path_parent_dir(path p) {
30 assert(p.data);
31
32 if (p.size == 0) {
33 return Empty;
34 }
35 size_t i = p.size - 1;
36 // If the path ends with '/', skip the characters.
37 while ((i > 0) && (p.data[i] == '/')) {
38 i--;
39 }
40 // Search backwards for the parent dir.
41 for (; i > 0; --i) {
42 if (p.data[i] == '/') {
43 return (path){p.data, i + 1};
44 }
45 }
46 return Empty; // No parent.
47}
48
49path path_concat(path left, path right) {
50 assert(left.data);
51 assert(right.data);
52
53 // +1 for separator.
54 const size_t out_size = left.size + right.size + 1;
55 // +1 for null.
56 char* out = calloc(out_size + 1, sizeof(char));
57 ASSERT(out);
58
59 memcpy(out, left.data, left.size);
60 out[left.size] = '/';
61 memcpy(out + left.size + 1, right.data, right.size);
62 out[out_size] = 0;
63
64 return (path){out, out_size};
65}
66
67bool path_make_relative(
68 const char* filepath, const char* path, char* relative,
69 size_t relative_length) {
70 assert(filepath);
71 assert(path);
72 assert(relative);
73
74 const size_t filepath_len = strlen(filepath);
75 const size_t path_len = strlen(path);
76 assert(filepath_len < relative_length);
77 assert(path_len < relative_length);
78
79 // Handle empty filepath.
80 if (filepath_len == 0) {
81 memcpy(relative, path, path_len);
82 return true;
83 }
84
85 // Search for the last / in the file path to get its parent directory.
86 assert(filepath_len > 0);
87 size_t tm_dir_len = 0;
88 for (tm_dir_len = strlen(filepath) - 1; tm_dir_len > 0; --tm_dir_len) {
89 if (filepath[tm_dir_len] == '/') {
90 break;
91 }
92 }
93 tm_dir_len++; // Preserve the backslash.
94
95 // Copy the file path where the parent dir ends.
96 // Make sure there is enough space in the output.
97 if ((tm_dir_len + path_len + 1) >= relative_length) {
98 return false;
99 }
100 memcpy(relative, filepath, tm_dir_len);
101 memcpy(&relative[tm_dir_len], path, path_len);
102
103 return true;
104}