#ifndef UTILITIES_H #define UTILITIES_H #include #include #include #include #include #include #include #include #include "file.h" #include "action_list.h" #define RESET "\033[0m" #define RED_BG "\033[41m" #define GREEN_BG "\033[42m" #define BLACK_FG "\033[30m" typedef enum { PT_NOEXIST, PT_FILE, PT_DIR, PT_OTHER, PT_ERROR } PathType; 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; } 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)); if (!deleted_lines || !inserted_lines) { free(deleted_lines); free(inserted_lines); return; } for (uint64_t i = 0; i < actions->len; i++) { if (actions->actions[i].type == DELETE) { deleted_lines[actions->actions[i].line_original] = 1; } else if (actions->actions[i].type == INSERT) { inserted_lines[actions->actions[i].line_changed] = 1; } } uint64_t old_idx = 0, new_idx = 0; while (old_idx < old_version->lines || new_idx < new_version->lines) { // DELETE if (old_idx < old_version->lines && deleted_lines[old_idx]) { printf("%s%s%4ld | %s%s\n", RED_BG, BLACK_FG, old_idx+1, old_version->content[old_idx], RESET); old_idx++; } // INSERT else if (new_idx < new_version->lines && inserted_lines[new_idx]) { printf("%s%s %4ld | %s%s\n", GREEN_BG, BLACK_FG, new_idx+1, new_version->content[new_idx], RESET); new_idx++; } // STAYS else if (old_idx < old_version->lines && new_idx < new_version->lines) { printf("%4ld %4ld | %s\n", old_idx+1, new_idx+1, old_version->content[old_idx]); old_idx++; new_idx++; } // DELETE else if (old_idx < old_version->lines) { printf("%s%s%4ld | %s%s\n", RED_BG, BLACK_FG, old_idx+1, old_version->content[old_idx], RESET); old_idx++; } // INSERT else if (new_idx < new_version->lines) { printf("%s%s %4ld | %s%s\n", GREEN_BG, BLACK_FG, new_idx+1, new_version->content[new_idx], RESET); new_idx++; } } free(deleted_lines); free(inserted_lines); } // 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) { size_t base_len = strlen(base); if (strlen(path) < base_len) perror("ERROR: the provided path is smaller than the base path!"); int add = strlen(path) != base_len ? 1 : 0; printf("base: %li\n", base_len); strcpy(path, path+base_len+add); if (add) { char tmp[PATH_MAX]; snprintf(tmp, sizeof(tmp), "%s/", path); strcpy(path, tmp); } } // In this function we assume that the end of the base and the beginning of the // path are the same so we can concat them together at that part // The path gets mutated in place void combine_path(char* base, char* path) { size_t base_len = 0; for (size_t idx = strlen(base); idx > 0; idx--) { if (base[idx] == '/') { base_len = idx; break; } } char tmp[PATH_MAX]; snprintf(tmp, sizeof(tmp), "%*s/%s", base_len, base, path); strcpy(path, tmp); } #endif // UTILITIES_H