#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; } char* find_root(char* relative) { char* current_dir = calloc(PATH_MAX, sizeof(char)); if (!current_dir) { perror("ERROR: calloc in find_root failed!"); return NULL; } if (!getcwd(current_dir, PATH_MAX)) { perror("ERROR: getcwd in find_root failed!"); free(current_dir); return NULL; } char* search_dir = strdup(current_dir); if (!search_dir) { perror("ERROR: strdup in find_root failed!"); free(current_dir); return NULL; } while (1) { size_t dir_len = strlen(search_dir); size_t merk_path_len = dir_len + strlen("/.merk") + 1; char* merk_path = calloc(merk_path_len, sizeof(char)); if (!merk_path) { perror("ERROR: calloc in find_root failed!"); free(current_dir); free(search_dir); return NULL; } snprintf(merk_path, merk_path_len, "%s/.merk", search_dir); struct stat st; if (stat(merk_path, &st) == 0 && S_ISDIR(st.st_mode)) { free(current_dir); free(merk_path); char* result = strdup(search_dir); free(search_dir); return result; } free(merk_path); if (strcmp(search_dir, "/") == 0) { break; } char temp[PATH_MAX]; snprintf(temp, sizeof(temp), "../%s", relative); strcpy(relative, temp); char* parent = strrchr(search_dir, '/'); if (parent == search_dir) { search_dir[1] = '\0'; } else if (parent) { *parent = '\0'; } else { break; } } free(current_dir); free(search_dir); printf("ERROR: you are in no merk repository!\nCreate a new repository with merk init\n"); return NULL; } void normalize_path(char* path, char* rel) { if (strlen(rel) == 0) return; size_t path_len = strlen(path); size_t rel_len = strlen(rel); int consumers = rel_len / 3; int counter = 0; size_t latest = 0; for (size_t idx = rel_len; idx < path_len; idx++) { if (path[idx] == '/') { counter++; latest = idx; if (counter == consumers) break; } if (path[idx] == '\0') break; } strcpy(path, path+latest+(counter > 0 ? 1 : 0)); } void walk(const char* base, const char* base_rel, const char* rel, PathBuffer* paths) { DIR* dir = opendir(base); if (!dir) { return; } struct dirent* de; while ((de = readdir(dir)) != NULL) { if (is_dot_or_dotdot(de->d_name)) continue; char* child_full = join_path(base, de->d_name); if (!child_full) { perror("ERROR: memory allocation failed in walk!"); closedir(dir); exit(1); } struct stat st; if (lstat(child_full, &st) != 0) { free(child_full); continue; } if (S_ISDIR(st.st_mode)) { char* new_rel; if (rel && rel[0]) { new_rel = join_path(rel, de->d_name); } else { new_rel = strdup(de->d_name); } if (!new_rel) { perror("ERROR: memory allocation failed in walk!"); free(child_full); closedir(dir); exit(1); } walk(child_full, base_rel, new_rel, paths); free(new_rel); } else { char* relative_path; if (rel && rel[0]) { relative_path = join_path(rel, de->d_name); } else { relative_path = strdup(de->d_name); } if (!relative_path) { perror("ERROR: memory allocation failed in walk!"); free(child_full); closedir(dir); exit(1); } normalize_path(relative_path, base_rel); add_path(paths, relative_path); free(relative_path); } free(child_full); } closedir(dir); }