diff --git a/include/utilities.h b/include/utilities.h index ebbd114..55fa6d6 100644 --- a/include/utilities.h +++ b/include/utilities.h @@ -1,18 +1,19 @@ #ifndef UTILITIES_H #define UTILITIES_H -#include -#include -#include #include #include -#include #include #include #include "file.h" #include "action_list.h" +#define IS_ALPHA(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) +#define IS_DIGIT(c) (c >= '0' && c <= '9') +#define IS_ALNUM(c) (IS_ALPHA(c) || IS_DIGIT(c)) +#define IS_PUNCT(c) ((c >= 33 && c <= 47) || (c >= 58 && c <= 64) || (c >= 91 && c <= 96) || (c >= 123 && c <= 126)) + #define RESET "\033[0m" #define RED_BG "\033[41m" #define GREEN_BG "\033[42m" @@ -35,21 +36,31 @@ typedef struct { size_t item_size; } List; -typedef List PathBuffer; +typedef List StringBuffer; +typedef List FileInfoBuffer; List* list_new(size_t); int list_push(List*, void*); -PathType get_path_type(const char*); -PathBuffer* path_buffer_new(); -void path_buffer_push(PathBuffer*, char*); -void path_buffer_sort(PathBuffer*); -void path_buffer_free(PathBuffer*); +void list_free(List*); +void* binary_search(const void*, const void*, size_t, size_t, int (*compare)(const void*, const void*)); +void* list_binary_search(List*, const void*, int (*compare)(const void*, const void*)); +StringBuffer* string_buffer_new(); +int string_buffer_push(StringBuffer*, char*); +void string_buffer_sort(StringBuffer*); +char* string_buffer_search(StringBuffer*, char*); +FileInfoBuffer* file_info_buffer_new(); +int file_info_buffer_push(FileInfoBuffer*, FileInfo); +void file_info_buffer_free(FileInfoBuffer*); +void file_info_buffer_sort(FileInfoBuffer*); +FileInfo* file_info_buffer_search(FileInfoBuffer*, const char*); char* find_root(char*); -void walk(char*, char*, char*, PathBuffer*, int, char*); +void walk(char*, char*, char*, FileInfoBuffer*, int, char*); char* get_repo_path(char*, char*); int is_in_repo(char*, char*); void visualize_diff(File*, File*, ActionList*); -void cut_path(char* base, char* path); -void combine_path(char* base, char* path); +int cut_path(char*, char*); +void combine_path(char*, char*); +PathType get_path_type(const char*); +char* get_file_content(char*); #endif // UTILITIES_H diff --git a/src/utilities.c b/src/utilities.c index 30187ca..7d84201 100644 --- a/src/utilities.c +++ b/src/utilities.c @@ -32,45 +32,7 @@ int list_push(List* list, void* item) { return 1; } -PathType get_path_type(const char* path) { - struct stat st; - int rc = stat(path, &st); - if (rc != 0) { - return (errno == ENOENT) ? PT_NOEXIST : PT_ERROR; - } - if (S_ISREG(st.st_mode)) return PT_FILE; - if (S_ISDIR(st.st_mode)) return PT_DIR; - return PT_OTHER; -} - -PathBuffer* path_buffer_new() { - return list_new(sizeof(char*)); -} - -void path_buffer_push(PathBuffer* buffer, char* path) { - char* path_copy = strdup(path); - if (!path_copy) { - perror("ERROR: strdup failed in add_path"); - return; - } - list_push(buffer, &path_copy); -} - -int compare_paths(const void* a, const void* b) { - const char* s1 = *(const char**)a; - const char* s2 = *(const char**)b; - return strcmp(s1,s2); -} - -void path_buffer_sort(PathBuffer* buffer) { - if (!buffer || buffer->len <= 1) { - return; - } - - qsort(buffer->items, buffer->len, sizeof(char*), compare_paths); -} - -void path_buffer_free(PathBuffer* buffer) { +void list_free(List* buffer) { if (buffer) { for (size_t i = 0; i < buffer->len; i++) { free(buffer->items[i]); @@ -80,6 +42,114 @@ void path_buffer_free(PathBuffer* buffer) { } } +void* binary_search(const void* key, const void* base, size_t num_elements, size_t element_size, int (*compare)(const void*, const void*)) { + if (!key || !base || !compare || num_elements == 0) { + return NULL; + } + + size_t left = 0; + size_t right = num_elements - 1; + + while (left <= right) { + size_t mid = left + (right - left) / 2; + + const char* mid_element = (const char*)base + (mid * element_size); + + int cmp = compare(key, mid_element); + + if (cmp == 0) { + return (void*)mid_element; + } + else if (cmp < 0) { + if (mid == 0) break; + right = mid - 1; + } + else { + left = mid + 1; + } + } + + return NULL; +} + +void* list_binary_search(List* list, const void* key, int (*compare)(const void*, const void*)) { + if (!list || !key || !compare) { + return NULL; + } + + return binary_search(key, list->items, list->len, list->item_size, compare); +} + +StringBuffer* string_buffer_new() { + return list_new(sizeof(char*)); +} + +int string_buffer_push(StringBuffer* buffer, char* path) { + char* path_copy = strdup(path); + if (!path_copy) { + perror("ERROR: strdup failed in string_buffer_push!"); + return 0; + } + return list_push(buffer, &path_copy); +} + +int compare_strings(const void* a, const void* b) { + const char* s1 = *(const char**)a; + const char* s2 = *(const char**)b; + return strcmp(s1,s2); +} + +void string_buffer_sort(StringBuffer* buffer) { + if (!buffer || buffer->len <= 1) { + return; + } + + qsort(buffer->items, buffer->len, sizeof(char*), compare_strings); +} + +char* string_buffer_search(StringBuffer* buffer, char* path) { + if (!buffer || !path) return NULL; + return (char*)list_binary_search(buffer, path, compare_strings); +} + +FileInfoBuffer* file_info_buffer_new() { + return list_new(sizeof(FileInfo)); +} + +int file_info_buffer_push(FileInfoBuffer* buffer, FileInfo info) { + return list_push(buffer, &info); +} + +void file_info_buffer_free(List* buffer) { + if (buffer) { + free(buffer->items); + free(buffer); + } +} + +int compare_file_info(const void* a, const void* b) { + const FileInfo* info1 = (const FileInfo*)a; + const FileInfo* info2 = (const FileInfo*)b; + + return strcmp(info1->name, info2->name); +} + +void file_info_buffer_sort(FileInfoBuffer* buffer) { + if (!buffer || buffer->len <= 1) { + return; + } + + qsort(buffer->items, buffer->len, sizeof(FileInfo), compare_file_info); +} + +FileInfo* file_info_buffer_search(FileInfoBuffer* buffer, const char* filename) { + if (!buffer || !filename) return NULL; + + FileInfo search_key = {.mode = 0, .name = (char*)filename}; + + return (FileInfo*)list_binary_search(buffer, &search_key, compare_file_info); +} + static int is_dot_or_dotdot(const char* s) { return (s[0] == '.' && (s[1] == '\0' || (s[1] == '.' && s[2] == '\0'))); } @@ -196,7 +266,7 @@ char* find_root(char* relative) { return NULL; } -void walk(char* base, char* base_rel, char* rel, PathBuffer* paths, int full_repo_path, char* repo_root_path) { +void walk(char* base, char* base_rel, char* rel, FileInfoBuffer* file_infos, int full_repo_path, char* repo_root_path) { DIR* dir = opendir(base); if (!dir) { return; @@ -235,7 +305,7 @@ void walk(char* base, char* base_rel, char* rel, PathBuffer* paths, int full_rep exit(1); } - walk(child_full, base_rel, new_rel, paths, full_repo_path, repo_root_path); + walk(child_full, base_rel, new_rel, file_infos, full_repo_path, repo_root_path); free(new_rel); } else { char* relative_path; @@ -254,12 +324,14 @@ void walk(char* base, char* base_rel, char* rel, PathBuffer* paths, int full_rep if (!full_repo_path) { normalize_path(relative_path, base_rel); - path_buffer_push(paths, relative_path); + FileInfo info = (FileInfo){.mode=st.st_mode, .name=strdup(relative_path)}; + file_info_buffer_push(file_infos, info); free(relative_path); } else { char* repo_path = get_repo_path(repo_root_path, relative_path); - path_buffer_push(paths, repo_path); + FileInfo info = (FileInfo){.mode=st.st_mode, .name=strdup(repo_path)}; + file_info_buffer_push(file_infos, info); free(relative_path); free(repo_path); } @@ -278,6 +350,18 @@ char* get_repo_path(char* repo_root_path, char* path) { return real_path; } +int is_in_repo(char* repo_root_path, char* path) { + size_t root_len = strlen(repo_root_path); + char* path_base = strdup(path); + + path_base[root_len] = '\0'; + + int cmp = strcmp(path_base, repo_root_path); + free(path_base); + + return cmp; +} + void visualize_diff(File* old_version, File* new_version, ActionList* actions) { int* deleted_lines = calloc(old_version->lines, sizeof(int)); int* inserted_lines = calloc(new_version->lines, sizeof(int)); @@ -333,9 +417,9 @@ void visualize_diff(File* old_version, File* new_version, ActionList* actions) { // In this function we assume that base is a prefix of path // Thus we just need the length of the base to jump ahead in the path -void cut_path(char* base, char* path) { +int cut_path(char* base, char* path) { size_t base_len = strlen(base); - if (strlen(path) < base_len) perror("ERROR: the provided path is smaller than the base path!"); + if (strlen(path) < base_len) return 0; int add = strlen(path) != base_len ? 1 : 0; strcpy(path, path+base_len+add); @@ -345,6 +429,8 @@ void cut_path(char* base, char* path) { snprintf(tmp, sizeof(tmp), "%s/", path); strcpy(path, tmp); } + + return 1; } // In this function we assume that the end of the base and the beginning of the @@ -365,4 +451,34 @@ void combine_path(char* base, char* path) { strcpy(path, tmp); } +PathType get_path_type(const char* path) { + struct stat st; + int rc = stat(path, &st); + if (rc != 0) { + return (errno == ENOENT) ? PT_NOEXIST : PT_ERROR; + } + if (S_ISREG(st.st_mode)) return PT_FILE; + if (S_ISDIR(st.st_mode)) return PT_DIR; + return PT_OTHER; +} +char* get_file_content(char* path) { + if (!path) return NULL; + + FILE* file = fopen(path, "rb"); + if (!file) { perror("ERROR: could not open file in get_file_content!"); return NULL; } + if (fseek(file, 0, SEEK_END) != 0) { fclose(file); return NULL; } + long file_size = ftell(file); + if (file_size < 0) { perror("ERROR: file size is negative in get_file_content!"); fclose(file); return NULL; } + if (fseek(file, 0, SEEK_SET) != 0) { fclose(file); return NULL; } + size_t n = (size_t)file_size; + char* buf = (char*)calloc(n + 1, 1); + if (!buf) { fclose(file); return NULL; } + + size_t got = fread(buf, 1, n, file); + fclose(file); + + buf[got] = '\0'; + + return buf; +}