-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpath_utils.c
150 lines (128 loc) · 4.42 KB
/
path_utils.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#include "path_utils.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
bool is_subdirectory(const char *path_a, const char *path_b) {
return strncmp(path_a, path_b, strlen(path_a)) == 0;
}
bool is_path_valid(const char *path) {
size_t len = strlen(path);
if (len == 0 || len > MAX_PATH_LENGTH)
return false;
if (path[0] != '/' || path[len - 1] != '/')
return false;
const char *name_start =
path + 1; // Start of current path component, just after '/'.
while (name_start < path + len) {
char *name_end = strchr(name_start,
'/'); // End of current path component, at '/'.
if (!name_end || name_end == name_start ||
name_end > name_start + MAX_FOLDER_NAME_LENGTH)
return false;
for (const char *p = name_start; p != name_end; ++p)
if (*p < 'a' || *p > 'z')
return false;
name_start = name_end + 1;
}
return true;
}
const char *split_path(const char *path, char *component) {
const char *subpath = strchr(path + 1,
'/'); // Pointer to second '/' character.
if (!subpath) // Path is "/".
return NULL;
if (component) {
int len = subpath - (path + 1);
assert(len >= 1 && len <= MAX_FOLDER_NAME_LENGTH);
strncpy(component, path + 1, len);
component[len] = '\0';
}
return subpath;
}
char *make_path_to_parent(const char *path, char *component) {
size_t len = strlen(path);
if (len == 1) // Path is "/".
return NULL;
const char *p = path + len - 2; // Point before final '/' character.
// Move p to last-but-one '/' character.
while (*p != '/')
p--;
size_t subpath_len = p - path + 1; // Include '/' at p.
char *result = malloc(
subpath_len + 1); // Include terminating null character.
strncpy(result, path, subpath_len);
result[subpath_len] = '\0';
if (component) {
size_t component_len = len - subpath_len - 1; // Skip final '/' as well.
assert(component_len >= 1 && component_len <= MAX_FOLDER_NAME_LENGTH);
strncpy(component, p + 1, component_len);
component[component_len] = '\0';
}
return result;
}
// A wrapper for using strcmp in qsort.
// The arguments here are actually pointers to (const char*).
static int compare_string_pointers(const void *p1, const void *p2) {
return strcmp(*(const char **) p1, *(const char **) p2);
}
const char **make_map_contents_array(HashMap *map) {
size_t n_keys = hmap_size(map);
const char **result = calloc(n_keys + 1, sizeof(char *));
HashMapIterator it = hmap_iterator(map);
const char **key = result;
void *value = NULL;
while (hmap_next(map, &it, key, &value))
key++;
*key = NULL; // Set last array element to NULL.
qsort(result, n_keys, sizeof(char *), compare_string_pointers);
return result;
}
char *make_map_contents_string(HashMap *map) {
const char **keys = make_map_contents_array(map);
unsigned int result_size = 0; // Including ending null character.
for (const char **key = keys; *key; ++key)
result_size += strlen(*key) + 1;
// Return empty string if map is empty.
if (!result_size) {
// Note we can't just return "", as it can't be free'd.
char *result = malloc(1);
*result = '\0';
free(keys);
return result;
}
char *result = malloc(result_size);
char *position = result;
for (const char **key = keys; *key; ++key) {
size_t keylen = strlen(*key);
assert(position + keylen <= result + result_size);
strcpy(position, *key); // NOLINT: array size already checked.
position += keylen;
*position = ',';
position++;
}
position--;
*position = '\0';
free(keys);
return result;
}
char *longest_common_path(const char *path_a, const char *path_b) {
int it = 0;
while (path_a[it] && path_b[it] && path_a[it] == path_b[it])
it++;
while (path_a[it - 1] != '/')
it--;
char *result = malloc(it + 1);
result = strncpy(result, path_a, it);
result[it] = '\0';
return result;
}
const char *remove_prefix(const char *prefix, const char *path) {
if (strlen(prefix) == strlen(path))
return "/";
while (*prefix == *path) {
prefix++;
path++;
}
path--; // Include '/' at the beginning.
return path;
}