merk/src/tree.c

122 lines
2.9 KiB
C

#include "tree.h"
PathBuffer* new_path_buffer() {
PathBuffer* buffer = calloc(1, sizeof(PathBuffer));
if (!buffer) {
perror("ERROR: Failed to allocate PathBuffer");
exit(1);
}
buffer->capacity = 10;
buffer->len = 0;
buffer->paths = calloc(buffer->capacity, sizeof(char*));
if (!buffer->paths) {
perror("ERROR: Failed to allocate paths array");
free(buffer);
exit(1);
}
return buffer;
}
void add_path(PathBuffer* buffer, char* path) {
if (buffer->len >= buffer->capacity) {
buffer->capacity *= 2;
char** new_paths = realloc(buffer->paths, buffer->capacity * sizeof(char*));
if (!new_paths) {
perror("ERROR: PathBuffer realloc failed!");
exit(1);
}
buffer->paths = new_paths;
}
char* path_copy = strdup(path);
if (!path_copy) {
perror("ERROR: strdup failed in add_path!");
exit(1);
}
buffer->paths[buffer->len++] = path_copy;
}
void free_path_buffer(PathBuffer* buffer) {
if (buffer) {
for (size_t i = 0; i < buffer->len; i++) {
free(buffer->paths[i]);
}
free(buffer->paths);
free(buffer);
}
}
static int is_dot_or_dotdot(const char* s) {
return (s[0] == '.' && (s[1] == '\0' || (s[1] == '.' && s[2] == '\0')));
}
static char* join_path(const char* a, const char* b) {
size_t la = strlen(a);
size_t lb = strlen(b);
int need_sep = (la > 0 && a[la - 1] != '/');
char* s = calloc(la + (need_sep ? 1 : 0) + lb + 1, sizeof(char));
if (!s) {
perror("ERROR: calloc failed in join_path!");
exit(1);
}
memcpy(s, a, la);
size_t p = la;
if (need_sep) s[p++] = '/';
memcpy(s + p, b, lb + 1);
return s;
}
void walk(const char* base, const char* rel, PathBuffer* paths) {
char* dir_full = rel[0] ? join_path(base, rel) : strdup(base);
if (!dir_full) {
perror("ERROR: memory allocation failed in walk!");
exit(1);
}
DIR* dir = opendir(dir_full);
if (!dir) {
free(dir_full);
return;
}
struct dirent* de;
while ((de = readdir(dir)) != NULL) {
if (is_dot_or_dotdot(de->d_name)) continue;
char* child_rel = rel[0] ? join_path(rel, de->d_name) : strdup(de->d_name);
if (!child_rel) {
perror("ERROR: memory allocation failed in walk!");
closedir(dir);
free(dir_full);
exit(1);
}
char* child_full = join_path(base, child_rel);
struct stat st;
if (lstat(child_full, &st) != 0) {
free(child_full);
free(child_rel);
continue;
}
if (S_ISDIR(st.st_mode)) {
walk(base, child_rel, paths);
} else {
add_path(paths, child_rel);
}
free(child_rel);
free(child_full);
}
closedir(dir);
free(dir_full);
}