refactor: split up the utilities file into smaller modules
This commit is contained in:
parent
abaa6e12fc
commit
ff71a92249
13 changed files with 572 additions and 488 deletions
|
|
@ -30,5 +30,6 @@ ActionList* new_list();
|
||||||
void add_action(ActionList*, Action);
|
void add_action(ActionList*, Action);
|
||||||
void append_list(ActionList*, ActionList*);
|
void append_list(ActionList*, ActionList*);
|
||||||
void free_action_list(ActionList*);
|
void free_action_list(ActionList*);
|
||||||
|
void sort_action_list(ActionList*);
|
||||||
|
|
||||||
#endif // ACTION_LIST_H
|
#endif // ACTION_LIST_H
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char** content;
|
char** content;
|
||||||
|
|
@ -34,6 +35,8 @@ typedef struct {
|
||||||
char* hash;
|
char* hash;
|
||||||
} FileInfo;
|
} FileInfo;
|
||||||
|
|
||||||
|
typedef List FileInfoBuffer;
|
||||||
|
|
||||||
File* new_empty_file();
|
File* new_empty_file();
|
||||||
File* new_file(const char*);
|
File* new_file(const char*);
|
||||||
File* from_string(char*);
|
File* from_string(char*);
|
||||||
|
|
@ -43,5 +46,10 @@ int insert_line(File*, char*, size_t);
|
||||||
int delete_line(File*, size_t);
|
int delete_line(File*, size_t);
|
||||||
int snapshot_file(char*, char*, size_t, char*);
|
int snapshot_file(char*, char*, size_t, char*);
|
||||||
void free_file(File*);
|
void free_file(File*);
|
||||||
|
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*);
|
||||||
|
|
||||||
#endif // FILE_H
|
#endif // FILE_H
|
||||||
|
|
|
||||||
24
include/list.h
Normal file
24
include/list.h
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef LIST_H
|
||||||
|
#define LIST_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define LIST_INIT_CAPACITY 4
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void** items;
|
||||||
|
size_t len;
|
||||||
|
size_t capacity;
|
||||||
|
size_t item_size;
|
||||||
|
} List;
|
||||||
|
|
||||||
|
List* list_new(size_t item_size);
|
||||||
|
int list_push(List*, void*);
|
||||||
|
int list_remove(List*, const void*, int (*compare)(const void*, const void*));
|
||||||
|
void list_free(List*);
|
||||||
|
void* list_binary_search(List*, const void*, int (*compare)(const void*, const void*));
|
||||||
|
|
||||||
|
#endif // LIST_H
|
||||||
32
include/object.h
Normal file
32
include/object.h
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef OBJECT_H
|
||||||
|
#define OBJECT_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#ifndef PATH_MAX
|
||||||
|
#define PATH_MAX MAX_PATH
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#include <limits.h>
|
||||||
|
#ifndef PATH_MAX
|
||||||
|
#define PATH_MAX 4096
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "hash.h"
|
||||||
|
#include "file.h"
|
||||||
|
#include "tree.h"
|
||||||
|
#include "utilities.h"
|
||||||
|
|
||||||
|
char* get_object(char*, size_t*);
|
||||||
|
void* parse_object(char*, ObjectType, size_t*);
|
||||||
|
|
||||||
|
#endif // OBJECT_H
|
||||||
|
|
@ -2,11 +2,19 @@
|
||||||
#define TREE_H
|
#define TREE_H
|
||||||
|
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include "utilities.h"
|
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
|
#include "file.h"
|
||||||
|
#include "myers.h"
|
||||||
|
#include "utilities.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))
|
||||||
|
|
||||||
void snapshot_tree(FileInfoBuffer*, char*);
|
void snapshot_tree(FileInfoBuffer*, char*);
|
||||||
int save_tree_diff(FileInfoBuffer*, char*, char*, size_t, char*, char*);
|
int save_tree_diff(FileInfoBuffer*, char*, char*, size_t, char*, char*);
|
||||||
|
int read_tree(FileInfoBuffer*, char*);
|
||||||
#endif // TREE_H
|
#endif // TREE_H
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include "myers.h"
|
#include "myers.h"
|
||||||
|
#include "action_list.h"
|
||||||
|
|
||||||
#define IS_ALPHA(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
|
#define IS_ALPHA(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
|
||||||
#define IS_DIGIT(c) (c >= '0' && c <= '9')
|
#define IS_DIGIT(c) (c >= '0' && c <= '9')
|
||||||
|
|
@ -18,8 +19,6 @@
|
||||||
#define GREEN_BG "\033[42m"
|
#define GREEN_BG "\033[42m"
|
||||||
#define BLACK_FG "\033[30m"
|
#define BLACK_FG "\033[30m"
|
||||||
|
|
||||||
#define LIST_INIT_CAPACITY 4
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
PT_NOEXIST,
|
PT_NOEXIST,
|
||||||
PT_FILE,
|
PT_FILE,
|
||||||
|
|
@ -28,36 +27,17 @@ typedef enum {
|
||||||
PT_ERROR
|
PT_ERROR
|
||||||
} PathType;
|
} PathType;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
void** items;
|
|
||||||
size_t len;
|
|
||||||
size_t capacity;
|
|
||||||
size_t item_size;
|
|
||||||
} List;
|
|
||||||
|
|
||||||
typedef List StringBuffer;
|
typedef List StringBuffer;
|
||||||
typedef List FileInfoBuffer;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t insertions;
|
uint32_t insertions;
|
||||||
uint32_t deletions;
|
uint32_t deletions;
|
||||||
} Changes;
|
} Changes;
|
||||||
|
|
||||||
List* list_new(size_t);
|
|
||||||
int list_push(List*, void*);
|
|
||||||
int list_remove(List*, const void*, int (*compare)(const void*, const void*));
|
|
||||||
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();
|
StringBuffer* string_buffer_new();
|
||||||
int string_buffer_push(StringBuffer*, char*);
|
int string_buffer_push(StringBuffer*, char*);
|
||||||
void string_buffer_sort(StringBuffer*);
|
void string_buffer_sort(StringBuffer*);
|
||||||
char* string_buffer_search(StringBuffer*, char*);
|
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*);
|
char* find_root(char*);
|
||||||
void walk(char*, char*, char*, FileInfoBuffer*, int, char*);
|
void walk(char*, char*, char*, FileInfoBuffer*, int, char*);
|
||||||
char* get_repo_path(char*, char*);
|
char* get_repo_path(char*, char*);
|
||||||
|
|
@ -70,9 +50,7 @@ char* get_file_content(char*);
|
||||||
char* get_file_content_with_size(char*, size_t*);
|
char* get_file_content_with_size(char*, size_t*);
|
||||||
int create_default_config_file(char*);
|
int create_default_config_file(char*);
|
||||||
int save_diff(ActionList*, char*, char*, size_t, char*, File*, int);
|
int save_diff(ActionList*, char*, char*, size_t, char*, File*, int);
|
||||||
int read_diff(char*, char*, size_t, char*, ActionList*);
|
int read_diff(char*, char*, ActionList*);
|
||||||
int save_file_diff(char*, char*, size_t, char*, Changes*);
|
int save_file_diff(char*, char*, size_t, char*, Changes*);
|
||||||
File* apply_diff(File*, ActionList*);
|
|
||||||
void sort_action_list(ActionList*);
|
|
||||||
|
|
||||||
#endif // UTILITIES_H
|
#endif // UTILITIES_H
|
||||||
|
|
|
||||||
|
|
@ -50,4 +50,29 @@ void free_action_list(ActionList* list) {
|
||||||
|
|
||||||
free(list->actions); // Free the array of actions
|
free(list->actions); // Free the array of actions
|
||||||
free(list); // Free the ActionList itself
|
free(list); // Free the ActionList itself
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int compare_actions(const void* a, const void* b) {
|
||||||
|
const Action* action1 = (const Action*)a;
|
||||||
|
const Action* action2 = (const Action*)b;
|
||||||
|
|
||||||
|
if (action1->type != action2->type) {
|
||||||
|
return (action1->type == DELETE) ? -1 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action1->type == DELETE) {
|
||||||
|
if (action1->line_original < action2->line_original) return 1;
|
||||||
|
if (action1->line_original > action2->line_original) return -1;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
if (action1->line_changed < action2->line_changed) return -1;
|
||||||
|
if (action1->line_changed > action2->line_changed) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sort_action_list(ActionList* actions) {
|
||||||
|
if (!actions || actions->len <= 1) return;
|
||||||
|
|
||||||
|
qsort(actions->actions, actions->len, sizeof(Action), compare_actions);
|
||||||
|
}
|
||||||
|
|
|
||||||
38
src/file.c
38
src/file.c
|
|
@ -291,3 +291,41 @@ void free_file(File* file) {
|
||||||
|
|
||||||
free(file);
|
free(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
104
src/list.c
Normal file
104
src/list.c
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
|
List* list_new(size_t item_size) {
|
||||||
|
List* list = calloc(1, sizeof(List));
|
||||||
|
if (!list) { perror("ERROR: memory allocation in new_list failed!"); return NULL; }
|
||||||
|
|
||||||
|
list->items = calloc(LIST_INIT_CAPACITY, item_size);
|
||||||
|
if (!list->items) { perror("ERROR: memory allocation in new_list failed!"); free(list); return NULL; }
|
||||||
|
|
||||||
|
list->len = 0;
|
||||||
|
list->capacity = LIST_INIT_CAPACITY;
|
||||||
|
list->item_size = item_size;
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
int list_push(List* list, void* item) {
|
||||||
|
if (!list || !item) return 0;
|
||||||
|
|
||||||
|
if (list->len == list->capacity) {
|
||||||
|
size_t new_capacity = list->capacity * 2;
|
||||||
|
void* new_items = realloc(list->items, new_capacity * list->item_size);
|
||||||
|
if (!new_items) { perror("ERROR: memory reallocation failed in list_push!"); return 0; }
|
||||||
|
|
||||||
|
list->items = new_items;
|
||||||
|
list->capacity = new_capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* dest = (char*)list->items + (list->len * list->item_size);
|
||||||
|
memcpy(dest, item, list->item_size);
|
||||||
|
list->len++;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int list_remove(List* list, const void* key, int (*compare)(const void*, const void*)) {
|
||||||
|
if (!list || !key || !compare || list->len == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < list->len; i++) {
|
||||||
|
char* current_item = (char*)list->items + (i * list->item_size);
|
||||||
|
|
||||||
|
if (compare(key, current_item) == 0) {
|
||||||
|
for (size_t j = i; j < list->len - 1; j++) {
|
||||||
|
char* dest = (char*)list->items + (j * list->item_size);
|
||||||
|
char* src = (char*)list->items + ((j + 1) * list->item_size);
|
||||||
|
memcpy(dest, src, list->item_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
list->len--;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void list_free(List* buffer) {
|
||||||
|
if (buffer) {
|
||||||
|
for (size_t i = 0; i < buffer->len; i++) {
|
||||||
|
free(buffer->items[i]);
|
||||||
|
}
|
||||||
|
free(buffer->items);
|
||||||
|
free(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);
|
||||||
|
}
|
||||||
81
src/main.c
81
src/main.c
|
|
@ -6,14 +6,11 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include "action_list.h"
|
|
||||||
#include "file.h"
|
|
||||||
#include "myers.h"
|
|
||||||
#include "tree.h"
|
|
||||||
#include "base_file_buffer.h"
|
#include "base_file_buffer.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "commit.h"
|
#include "commit.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
|
#include "object.h"
|
||||||
|
|
||||||
static void usage(int exitcode) {
|
static void usage(int exitcode) {
|
||||||
printf("usage: merk <command> [<args>]\n\
|
printf("usage: merk <command> [<args>]\n\
|
||||||
|
|
@ -24,7 +21,7 @@ static void usage(int exitcode) {
|
||||||
exit(exitcode);
|
exit(exitcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char** argv) {
|
||||||
if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) {
|
if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) {
|
||||||
usage(0);
|
usage(0);
|
||||||
}
|
}
|
||||||
|
|
@ -247,32 +244,25 @@ int main(int argc, char **argv) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char relative[PATH_MAX] = "";
|
char tmp_path[PATH_MAX] = ".merk/BRANCH";
|
||||||
char* root = find_root(relative);
|
|
||||||
if (!root) {
|
|
||||||
free_config(&config);
|
|
||||||
free(commit_message);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char branch_path[PATH_MAX];
|
char branch_path[PATH_MAX];
|
||||||
snprintf(branch_path, sizeof(branch_path), "%s/.merk/BRANCH", root);
|
realpath(tmp_path, branch_path);
|
||||||
|
|
||||||
char* branch = get_file_content(branch_path);
|
char* branch = get_file_content(branch_path);
|
||||||
if (!branch) {
|
if (!branch) {
|
||||||
free(root);
|
|
||||||
free_config(&config);
|
free_config(&config);
|
||||||
free(commit_message);
|
free(commit_message);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char tmp_path2[PATH_MAX];
|
||||||
char info_path[PATH_MAX];
|
char info_path[PATH_MAX];
|
||||||
snprintf(info_path, sizeof(info_path), "%s/.merk/info/%s", root, branch);
|
snprintf(tmp_path2, sizeof(tmp_path2), ".merk/info/%s", branch);
|
||||||
|
realpath(tmp_path2, info_path);
|
||||||
|
|
||||||
BaseFileBuffer* base_files = base_file_buffer_new();
|
BaseFileBuffer* base_files = base_file_buffer_new();
|
||||||
if (!base_files) {
|
if (!base_files) {
|
||||||
free(branch);
|
free(branch);
|
||||||
free(root);
|
|
||||||
free_config(&config);
|
free_config(&config);
|
||||||
free(commit_message);
|
free(commit_message);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
@ -284,7 +274,16 @@ int main(int argc, char **argv) {
|
||||||
if (!files) {
|
if (!files) {
|
||||||
base_file_buffer_free(base_files);
|
base_file_buffer_free(base_files);
|
||||||
free(branch);
|
free(branch);
|
||||||
free(root);
|
free_config(&config);
|
||||||
|
free(commit_message);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* root = find_root(NULL);
|
||||||
|
if (!root) {
|
||||||
|
list_free(files);
|
||||||
|
base_file_buffer_free(base_files);
|
||||||
|
free(branch);
|
||||||
free_config(&config);
|
free_config(&config);
|
||||||
free(commit_message);
|
free(commit_message);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
@ -297,7 +296,6 @@ int main(int argc, char **argv) {
|
||||||
list_free(files);
|
list_free(files);
|
||||||
base_file_buffer_free(base_files);
|
base_file_buffer_free(base_files);
|
||||||
free(branch);
|
free(branch);
|
||||||
free(root);
|
|
||||||
free_config(&config);
|
free_config(&config);
|
||||||
free(commit_message);
|
free(commit_message);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
@ -366,8 +364,8 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuffer* file_hashes = string_buffer_new();
|
Changes* changes = calloc(1, sizeof(Changes));
|
||||||
if (!file_hashes) {
|
if (!changes) {
|
||||||
free(commit_message);
|
free(commit_message);
|
||||||
list_free(files);
|
list_free(files);
|
||||||
base_file_buffer_free(base_files);
|
base_file_buffer_free(base_files);
|
||||||
|
|
@ -377,6 +375,9 @@ int main(int argc, char **argv) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
changes->insertions = 0;
|
||||||
|
changes->deletions = 0;
|
||||||
|
|
||||||
for (size_t idx = 0; idx < files->len; idx++) {
|
for (size_t idx = 0; idx < files->len; idx++) {
|
||||||
BaseFileInfo* base_file = base_file_buffer_search(base_files, files->items[idx]);
|
BaseFileInfo* base_file = base_file_buffer_search(base_files, files->items[idx]);
|
||||||
if (!base_file) {
|
if (!base_file) {
|
||||||
|
|
@ -385,7 +386,6 @@ int main(int argc, char **argv) {
|
||||||
// Compress the files content and put it into the object database
|
// Compress the files content and put it into the object database
|
||||||
char file_hash[41];
|
char file_hash[41];
|
||||||
snapshot_file(files->items[idx], root, 0, file_hash);
|
snapshot_file(files->items[idx], root, 0, file_hash);
|
||||||
string_buffer_push(file_hashes, file_hash);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
size_t base_num = base_file->base_num;
|
size_t base_num = base_file->base_num;
|
||||||
|
|
@ -398,17 +398,13 @@ int main(int argc, char **argv) {
|
||||||
char id[2 + snprintf(NULL, 0, "%d", base_num) + strlen(files->items[idx])];
|
char id[2 + snprintf(NULL, 0, "%d", base_num) + strlen(files->items[idx])];
|
||||||
snprintf(id, sizeof(id), "%s %d", files->items[idx], base_num);
|
snprintf(id, sizeof(id), "%s %d", files->items[idx], base_num);
|
||||||
object_hash(BaseFileObject, id, basefile_hash);
|
object_hash(BaseFileObject, id, basefile_hash);
|
||||||
|
save_file_diff(files->items[idx], root, base_num, basefile_hash, changes);
|
||||||
char diff_hash[41];
|
|
||||||
save_file_diff(files->items[idx], root, base_num, basefile_hash, diff_hash);
|
|
||||||
string_buffer_push(file_hashes, diff_hash);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
base_file_buffer_sort(base_files);
|
base_file_buffer_sort(base_files);
|
||||||
write_base_file_list(base_files, info_path);
|
write_base_file_list(base_files, info_path);
|
||||||
FileInfoBuffer* tree = basefilebuffer_to_fileinfobuffer(base_files);
|
FileInfoBuffer* tree = basefilebuffer_to_fileinfobuffer(base_files);
|
||||||
if (!tree) {
|
if (!tree) {
|
||||||
list_free(file_hashes);
|
|
||||||
free(commit_message);
|
free(commit_message);
|
||||||
list_free(files);
|
list_free(files);
|
||||||
base_file_buffer_free(base_files);
|
base_file_buffer_free(base_files);
|
||||||
|
|
@ -417,6 +413,23 @@ int main(int argc, char **argv) {
|
||||||
free_config(&config);
|
free_config(&config);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (size_t idx = 0; idx < tree->len; idx++) {
|
||||||
|
FileInfo* info = (FileInfo*)tree->items + idx;
|
||||||
|
BaseFileInfo* base_info = base_file_buffer_search(base_files, info->name);
|
||||||
|
char hash[41];
|
||||||
|
if (base_info->diff_num == 0) {
|
||||||
|
char id[2 + snprintf(NULL, 0, "%d", base_info->base_num) + strlen(info->name)];
|
||||||
|
snprintf(id, sizeof(id), "%s %d", info->name, base_info->base_num);
|
||||||
|
object_hash(BaseFileObject, id, hash);
|
||||||
|
} else {
|
||||||
|
char id[2 + snprintf(NULL, 0, "%d", base_info->diff_num-1) + strlen(info->name)];
|
||||||
|
snprintf(id, sizeof(id), "%s %d", info->name, base_info->diff_num-1);
|
||||||
|
object_hash(FileDiffObject, id, hash);
|
||||||
|
}
|
||||||
|
info->hash = strdup(hash);
|
||||||
|
}
|
||||||
|
|
||||||
char tree_hash[41];
|
char tree_hash[41];
|
||||||
snapshot_tree(tree, tree_hash);
|
snapshot_tree(tree, tree_hash);
|
||||||
|
|
||||||
|
|
@ -427,7 +440,6 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
if (!log) {
|
if (!log) {
|
||||||
file_info_buffer_free(tree);
|
file_info_buffer_free(tree);
|
||||||
list_free(file_hashes);
|
|
||||||
free(commit_message);
|
free(commit_message);
|
||||||
list_free(files);
|
list_free(files);
|
||||||
base_file_buffer_free(base_files);
|
base_file_buffer_free(base_files);
|
||||||
|
|
@ -484,7 +496,6 @@ int main(int argc, char **argv) {
|
||||||
if (!write_commit_log(log, log_path)) {
|
if (!write_commit_log(log, log_path)) {
|
||||||
commit_log_free(log);
|
commit_log_free(log);
|
||||||
file_info_buffer_free(tree);
|
file_info_buffer_free(tree);
|
||||||
list_free(file_hashes);
|
|
||||||
free(commit_message);
|
free(commit_message);
|
||||||
list_free(files);
|
list_free(files);
|
||||||
base_file_buffer_free(base_files);
|
base_file_buffer_free(base_files);
|
||||||
|
|
@ -497,14 +508,18 @@ int main(int argc, char **argv) {
|
||||||
char ref_path[PATH_MAX];
|
char ref_path[PATH_MAX];
|
||||||
snprintf(ref_path, sizeof(ref_path), "%s/.merk/refs/branches/%s", root, branch);
|
snprintf(ref_path, sizeof(ref_path), "%s/.merk/refs/branches/%s", root, branch);
|
||||||
|
|
||||||
printf("this is the ref path: %s\n", ref_path);
|
|
||||||
|
|
||||||
int ref = open(ref_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
int ref = open(ref_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||||
if (ref < 0) return -1;
|
if (ref < 0) return -1;
|
||||||
write(ref, commit_hash, 40);
|
write(ref, commit_hash, 40);
|
||||||
close(ref);
|
close(ref);
|
||||||
|
|
||||||
// Cleanup
|
if (changes->insertions == 0 && changes->deletions == 0) {
|
||||||
|
printf("(\x1b[33;1m%.7s\x1b[0m on \x1b[39;1;4m%s\x1b[0m) %s\n", commit_hash, branch, commit_message);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("(\x1b[33;1m%.7s\x1b[0m on \x1b[39;1;4m%s\x1b[0m \x1b[32;1m%d+\x1b[0m \x1b[31;1m%d-\x1b[0m) %s\n", commit_hash, branch, changes->insertions, changes->deletions, commit_message);
|
||||||
|
}
|
||||||
|
|
||||||
list_free(files);
|
list_free(files);
|
||||||
base_file_buffer_free(base_files);
|
base_file_buffer_free(base_files);
|
||||||
free(branch);
|
free(branch);
|
||||||
|
|
@ -541,7 +556,7 @@ int main(int argc, char **argv) {
|
||||||
time_t timestamp = atol(commit->committer.timestamp);
|
time_t timestamp = atol(commit->committer.timestamp);
|
||||||
strftime(human_readable_time, sizeof(human_readable_time), "%Y-%m-%d %H:%M:%S %z", localtime(×tamp));
|
strftime(human_readable_time, sizeof(human_readable_time), "%Y-%m-%d %H:%M:%S %z", localtime(×tamp));
|
||||||
|
|
||||||
printf("\x1b[33;1m%.7s\x1b[0m: %s\n%s <\x1b[38;5;240m\x1b]8;;mailto:%s\x1b\\%s\x1b]8;;\x1b\\\x1b[0m> \x1b[36m%s\x1b[0m\n\n",
|
printf("\x1b[33;1m%.7s\x1b[0m: %s\n%s <\x1b[38;5;240m\x1b]8;;mailto:%s\x1b\\%s\x1b]8;;\x1b\\\x1b[0m> (\x1b[36m%s\x1b[0m)\n\n",
|
||||||
commit->hash,
|
commit->hash,
|
||||||
commit->message,
|
commit->message,
|
||||||
commit->committer.name,
|
commit->committer.name,
|
||||||
|
|
|
||||||
117
src/object.c
Normal file
117
src/object.c
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
#include "object.h"
|
||||||
|
|
||||||
|
char* get_object(char* hash, size_t* size_out) {
|
||||||
|
char dir_path[PATH_MAX];
|
||||||
|
char repo_path[PATH_MAX];
|
||||||
|
char file_path[PATH_MAX];
|
||||||
|
snprintf(dir_path, sizeof(dir_path), ".merk/objects/%.2s", hash);
|
||||||
|
snprintf(repo_path, sizeof(repo_path), "%s/%s", dir_path, hash+2);
|
||||||
|
realpath(repo_path, file_path);
|
||||||
|
|
||||||
|
size_t compressed_size;
|
||||||
|
unsigned char* compressed_data = (unsigned char*)get_file_content_with_size(file_path, &compressed_size);
|
||||||
|
if (!compressed_data || compressed_size == 0) {
|
||||||
|
free(compressed_data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t idx = 0;
|
||||||
|
while (idx < compressed_size && IS_DIGIT(compressed_data[idx])) {
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx == 0) {
|
||||||
|
perror("ERROR: no length found at start of object!");
|
||||||
|
free(compressed_data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* size_str = calloc(idx + 1, sizeof(char));
|
||||||
|
if (!size_str) {
|
||||||
|
free(compressed_data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(size_str, compressed_data, idx);
|
||||||
|
size_str[idx] = '\0';
|
||||||
|
|
||||||
|
char* end;
|
||||||
|
long original_size = strtol(size_str, &end, 10);
|
||||||
|
if (end == size_str || *end != '\0') {
|
||||||
|
perror("ERROR: invalid length in get_object!");
|
||||||
|
free(size_str);
|
||||||
|
free(compressed_data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
free(size_str);
|
||||||
|
|
||||||
|
if (idx < compressed_size && compressed_data[idx] == ' ') {
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* decompressed = malloc(original_size + 1);
|
||||||
|
if (!decompressed) {
|
||||||
|
free(compressed_data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
uLongf decompressed_size = original_size;
|
||||||
|
|
||||||
|
if (uncompress((Bytef*)decompressed, &decompressed_size, compressed_data + idx, compressed_size - idx) != Z_OK) {
|
||||||
|
perror("ERROR: decompression failed in get_object!");
|
||||||
|
free(decompressed);
|
||||||
|
free(compressed_data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(compressed_data);
|
||||||
|
|
||||||
|
decompressed[decompressed_size] = '\0';
|
||||||
|
if (size_out) {
|
||||||
|
*size_out = decompressed_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return decompressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* parse_object(char* hash, ObjectType type, size_t* size_out) {
|
||||||
|
size_t line_count;
|
||||||
|
char* content = get_object(hash, &line_count);
|
||||||
|
if (!content) return NULL;
|
||||||
|
if (line_count == 0) {
|
||||||
|
free(content);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case BaseFileObject: {
|
||||||
|
File* file = from_string(content);
|
||||||
|
if (!file) {
|
||||||
|
free(content);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
free(content);
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
case TreeObject: {
|
||||||
|
FileInfoBuffer* buffer = file_info_buffer_new();
|
||||||
|
if (!buffer) {
|
||||||
|
free(content);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read_tree(buffer, hash) < 0) {
|
||||||
|
file_info_buffer_free(buffer);
|
||||||
|
free(content);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(content);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
case FileDiffObject: {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
default: free(content); return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
101
src/tree.c
101
src/tree.c
|
|
@ -416,3 +416,104 @@ int save_tree_diff(FileInfoBuffer* current_tree, char* root, char* branch_name,
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int read_tree(FileInfoBuffer* tree_out, char* hash) {
|
||||||
|
if (!tree_out || !hash) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char repo_location[PATH_MAX];
|
||||||
|
snprintf(repo_location, sizeof(repo_location), ".merk/objects/%.2s/%s", hash, hash+2);
|
||||||
|
|
||||||
|
char tree_location[PATH_MAX];
|
||||||
|
realpath(repo_location, tree_location);
|
||||||
|
|
||||||
|
size_t compressed_size;
|
||||||
|
unsigned char* compressed_data = (unsigned char*)get_file_content_with_size(tree_location, &compressed_size);
|
||||||
|
if (!compressed_data) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t idx = 0;
|
||||||
|
while (idx < compressed_size && IS_DIGIT(compressed_data[idx])) {
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx == 0) {
|
||||||
|
perror("ERROR: no length found in tree file!");
|
||||||
|
free(compressed_data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* size_str = calloc(idx + 1, sizeof(char));
|
||||||
|
if (!size_str) {
|
||||||
|
free(compressed_data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(size_str, compressed_data, idx);
|
||||||
|
size_str[idx] = '\0';
|
||||||
|
|
||||||
|
char* end;
|
||||||
|
long size = strtol(size_str, &end, 10);
|
||||||
|
if (end == size_str || *end != '\0' || size <= 0) {
|
||||||
|
perror("ERROR: invalid length in tree file");
|
||||||
|
free(size_str);
|
||||||
|
free(compressed_data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t offset = strlen(size_str) + 1;
|
||||||
|
free(size_str);
|
||||||
|
|
||||||
|
char* tree_content = calloc(size + 1, sizeof(char));
|
||||||
|
if (!tree_content) {
|
||||||
|
free(compressed_data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uLongf dest_len = (uLongf)size;
|
||||||
|
int result = uncompress((unsigned char*)tree_content, &dest_len, compressed_data + offset, compressed_size - offset);
|
||||||
|
free(compressed_data);
|
||||||
|
|
||||||
|
if (result != Z_OK) {
|
||||||
|
perror("ERROR: decompression of tree failed!");
|
||||||
|
free(tree_content);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tree_content[dest_len] = '\0';
|
||||||
|
|
||||||
|
char* line = strtok(tree_content, "\n");
|
||||||
|
while (line) {
|
||||||
|
FileInfo file_info;
|
||||||
|
char mode_str[8];
|
||||||
|
if (sscanf(line, "%7s %ms %ms", mode_str, &file_info.name, &file_info.hash) != 3) {
|
||||||
|
fprintf(stderr, "ERROR: failed to parse file info in tree file! Line: %s\n", line);
|
||||||
|
free(tree_content);
|
||||||
|
file_info_buffer_free(tree_out);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* endptr;
|
||||||
|
file_info.mode = (mode_t)strtol(mode_str, &endptr, 8);
|
||||||
|
if (endptr == mode_str || *endptr != '\0') {
|
||||||
|
fprintf(stderr, "ERROR: failed to parse mode as octal! Mode string: %s\n", mode_str);
|
||||||
|
free(tree_content);
|
||||||
|
file_info_buffer_free(tree_out);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!list_push(tree_out, &file_info)) {
|
||||||
|
fprintf(stderr, "ERROR: Failed to push FileInfo to tree_out!\n");
|
||||||
|
free(tree_content);
|
||||||
|
file_info_buffer_free(tree_out);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
line = strtok(NULL, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
free(tree_content);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
|
||||||
489
src/utilities.c
489
src/utilities.c
|
|
@ -1,108 +1,5 @@
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
List* list_new(size_t item_size) {
|
|
||||||
List* list = calloc(1, sizeof(List));
|
|
||||||
if (!list) { perror("ERROR: memory allocation in new_list failed!"); return NULL; }
|
|
||||||
|
|
||||||
list->items = calloc(LIST_INIT_CAPACITY, item_size);
|
|
||||||
if (!list->items) { perror("ERROR: memory allocation in new_list failed!"); free(list); return NULL; }
|
|
||||||
|
|
||||||
list->len = 0;
|
|
||||||
list->capacity = LIST_INIT_CAPACITY;
|
|
||||||
list->item_size = item_size;
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
int list_push(List* list, void* item) {
|
|
||||||
if (!list || !item) return 0;
|
|
||||||
|
|
||||||
if (list->len == list->capacity) {
|
|
||||||
size_t new_capacity = list->capacity * 2;
|
|
||||||
void* new_items = realloc(list->items, new_capacity * list->item_size);
|
|
||||||
if (!new_items) { perror("ERROR: memory reallocation failed in list_push!"); return 0; }
|
|
||||||
|
|
||||||
list->items = new_items;
|
|
||||||
list->capacity = new_capacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* dest = (char*)list->items + (list->len * list->item_size);
|
|
||||||
memcpy(dest, item, list->item_size);
|
|
||||||
list->len++;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int list_remove(List* list, const void* key, int (*compare)(const void*, const void*)) {
|
|
||||||
if (!list || !key || !compare || list->len == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < list->len; i++) {
|
|
||||||
char* current_item = (char*)list->items + (i * list->item_size);
|
|
||||||
|
|
||||||
if (compare(key, current_item) == 0) {
|
|
||||||
for (size_t j = i; j < list->len - 1; j++) {
|
|
||||||
char* dest = (char*)list->items + (j * list->item_size);
|
|
||||||
char* src = (char*)list->items + ((j + 1) * list->item_size);
|
|
||||||
memcpy(dest, src, list->item_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
list->len--;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void list_free(List* buffer) {
|
|
||||||
if (buffer) {
|
|
||||||
for (size_t i = 0; i < buffer->len; i++) {
|
|
||||||
free(buffer->items[i]);
|
|
||||||
}
|
|
||||||
free(buffer->items);
|
|
||||||
free(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() {
|
StringBuffer* string_buffer_new() {
|
||||||
return list_new(sizeof(char*));
|
return list_new(sizeof(char*));
|
||||||
}
|
}
|
||||||
|
|
@ -135,44 +32,6 @@ char* string_buffer_search(StringBuffer* buffer, char* path) {
|
||||||
return (char*)list_binary_search(buffer, path, compare_strings);
|
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) {
|
static int is_dot_or_dotdot(const char* s) {
|
||||||
return (s[0] == '.' && (s[1] == '\0' || (s[1] == '.' && s[2] == '\0')));
|
return (s[0] == '.' && (s[1] == '\0' || (s[1] == '.' && s[2] == '\0')));
|
||||||
}
|
}
|
||||||
|
|
@ -697,319 +556,119 @@ int save_diff(ActionList* diff, char* path, char* root, size_t diff_id, char* ba
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int read_diff(char* path, char* root, size_t diff_id, char* basefile_hash, ActionList* diff_out) {
|
int read_diff(char* content, char* basefile_hash, ActionList* diff_out) {
|
||||||
size_t compressed_size;
|
if (!content || !basefile_hash || !diff_out) {
|
||||||
unsigned char* compressed_data = (unsigned char*)get_file_content_with_size(path, &compressed_size);
|
return 0;
|
||||||
|
|
||||||
if (!compressed_data || compressed_size == 0) {
|
|
||||||
free(compressed_data);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t idx = 0;
|
size_t idx = 0;
|
||||||
while (idx < compressed_size && IS_DIGIT(compressed_data[idx])) {
|
strncpy(basefile_hash, content, 40);
|
||||||
idx++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (idx == 0) {
|
|
||||||
perror("ERROR: no length found at start of base file list!");
|
|
||||||
free(compressed_data);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* size_str = calloc(idx + 1, sizeof(char));
|
|
||||||
if (!size_str) {
|
|
||||||
free(compressed_data);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(size_str, compressed_data, idx);
|
|
||||||
size_str[idx] = '\0';
|
|
||||||
|
|
||||||
char* end;
|
|
||||||
long original_size = strtol(size_str, &end, 10);
|
|
||||||
if (end == size_str || *end != '\0') {
|
|
||||||
perror("ERROR: invalid length in read_diff!");
|
|
||||||
free(size_str);
|
|
||||||
free(compressed_data);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
free(size_str);
|
|
||||||
|
|
||||||
if (idx < compressed_size && compressed_data[idx] == ' ') {
|
|
||||||
idx++;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* diff_list = calloc(original_size + 1, sizeof(char));
|
|
||||||
if (!diff_list) {
|
|
||||||
free(compressed_data);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uLongf dest_len = (uLongf)original_size;
|
|
||||||
|
|
||||||
int result = uncompress((unsigned char*)diff_list, &dest_len, compressed_data + idx, compressed_size - idx);
|
|
||||||
free(compressed_data);
|
|
||||||
|
|
||||||
if (result != Z_OK) {
|
|
||||||
perror("ERROR: decompression of the diff failed!");
|
|
||||||
free(diff_list);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
diff_list[dest_len] = '\0';
|
|
||||||
|
|
||||||
printf("Decompressed diff content: %s\n", diff_list);
|
|
||||||
|
|
||||||
idx = 0;
|
|
||||||
strncpy(basefile_hash, diff_list, 40);
|
|
||||||
basefile_hash[40] = '\0';
|
basefile_hash[40] = '\0';
|
||||||
idx += 41;
|
idx += 41;
|
||||||
|
|
||||||
while (idx < dest_len && IS_DIGIT(diff_list[idx])) {
|
while (content[idx] && IS_DIGIT(content[idx])) {
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (idx == 41) {
|
if (idx == 41) {
|
||||||
perror("ERROR: no length found at start of diff!");
|
perror("ERROR: no length found at start of diff!");
|
||||||
free(diff_list);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* number_of_actions = calloc(idx + 1, sizeof(char));
|
char* number_of_actions = calloc(idx - 41 + 1, sizeof(char));
|
||||||
if (!number_of_actions) {
|
if (!number_of_actions) {
|
||||||
free(diff_list);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(number_of_actions, diff_list + 41, idx-41);
|
memcpy(number_of_actions, content + 41, idx - 41);
|
||||||
number_of_actions[idx] = '\0';
|
number_of_actions[idx - 41] = '\0';
|
||||||
|
|
||||||
|
char* end;
|
||||||
long actions = strtol(number_of_actions, &end, 10);
|
long actions = strtol(number_of_actions, &end, 10);
|
||||||
if (end == number_of_actions || *end != '\0') {
|
|
||||||
perror("ERROR: invalid length in read_diff!");
|
|
||||||
free(number_of_actions);
|
|
||||||
free(diff_list);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(number_of_actions);
|
free(number_of_actions);
|
||||||
|
|
||||||
if (actions <= 0) {
|
if (end == number_of_actions || *end != '\0' || actions <= 0) {
|
||||||
free(diff_list);
|
perror("ERROR: invalid number of actions in read_diff!");
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t action_idx = 0;
|
size_t action_idx = 0;
|
||||||
while (idx < dest_len && action_idx < (size_t)actions) {
|
while (content[idx] && action_idx < (size_t)actions) {
|
||||||
idx++;
|
idx++;
|
||||||
|
|
||||||
if (diff_list[idx] == '0') {
|
Action action = {0};
|
||||||
|
|
||||||
|
if (content[idx] == '0') {
|
||||||
idx++;
|
idx++;
|
||||||
if (diff_list[idx] == ' ') idx++;
|
if (content[idx] != ' ') {
|
||||||
else {
|
|
||||||
perror("ERROR: expected space after opbit in read_diff!");
|
perror("ERROR: expected space after opbit in read_diff!");
|
||||||
free(diff_list);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
size_t start_idx = idx;
|
|
||||||
|
|
||||||
while (idx < dest_len && IS_DIGIT(diff_list[idx])) {
|
|
||||||
idx++;
|
|
||||||
}
|
|
||||||
if (idx == dest_len) {
|
|
||||||
perror("ERROR: unexpected end of diff in read_diff!");
|
|
||||||
free(diff_list);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
char* line_original_str = calloc(idx + 1, sizeof(char));
|
|
||||||
if (!line_original_str) {
|
|
||||||
free(diff_list);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
memcpy(line_original_str, diff_list + start_idx, idx - start_idx);
|
|
||||||
line_original_str[idx - start_idx] = '\0';
|
|
||||||
char* end2;
|
|
||||||
long line_original = strtol(line_original_str, &end2, 10);
|
|
||||||
if (end2 == line_original_str || *end2 != '\0') {
|
|
||||||
perror("ERROR: invalid line number in read_diff!");
|
|
||||||
free(line_original_str);
|
|
||||||
free(diff_list);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
free(line_original_str);
|
|
||||||
|
|
||||||
if (diff_list[idx] == ' ') idx++;
|
|
||||||
else {
|
|
||||||
perror("ERROR: expected space after line original in read_diff!");
|
|
||||||
free(diff_list);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
start_idx = idx;
|
|
||||||
while (idx < dest_len && IS_DIGIT(diff_list[idx])) {
|
|
||||||
idx++;
|
|
||||||
}
|
|
||||||
if (idx == dest_len) {
|
|
||||||
perror("ERROR: unexpected end of diff in read_diff!");
|
|
||||||
free(diff_list);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
char* line_changed_str = calloc(idx + 1, sizeof(char));
|
|
||||||
if (!line_changed_str) {
|
|
||||||
free(diff_list);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
memcpy(line_changed_str, diff_list + start_idx, idx - start_idx);
|
|
||||||
line_changed_str[idx - start_idx] = '\0';
|
|
||||||
long line_changed = strtol(line_changed_str, &end2, 10);
|
|
||||||
if (end2 == line_changed_str || *end2 != '\0') {
|
|
||||||
perror("ERROR: invalid line number in read_diff!");
|
|
||||||
free(line_changed_str);
|
|
||||||
free(diff_list);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
free(line_changed_str);
|
|
||||||
|
|
||||||
Action action = {.type=DELETE, .line_original=line_original, .line_changed=line_changed, .content=NULL};
|
|
||||||
add_action(diff_out, action);
|
|
||||||
action_idx++;
|
|
||||||
}
|
|
||||||
else if (diff_list[idx] == '1') {
|
|
||||||
idx++;
|
idx++;
|
||||||
if (diff_list[idx] == ' ') idx++;
|
|
||||||
else {
|
char* endptr;
|
||||||
|
action.line_original = strtol(content + idx, &endptr, 10);
|
||||||
|
if (endptr == content + idx || *endptr != ' ') {
|
||||||
|
perror("ERROR: failed to parse line_original in read_diff!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
idx = endptr - content + 1;
|
||||||
|
|
||||||
|
action.line_changed = strtol(content + idx, &endptr, 10);
|
||||||
|
if (endptr == content + idx || (*endptr != ' ' && *endptr != '\0')) {
|
||||||
|
perror("ERROR: failed to parse line_changed in read_diff!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
idx = endptr - content;
|
||||||
|
} else if (content[idx] == '1') {
|
||||||
|
idx++;
|
||||||
|
if (content[idx] != ' ') {
|
||||||
perror("ERROR: expected space after opbit in read_diff!");
|
perror("ERROR: expected space after opbit in read_diff!");
|
||||||
free(diff_list);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
size_t start_idx = idx;
|
idx++;
|
||||||
|
|
||||||
while (idx < dest_len && IS_DIGIT(diff_list[idx])) {
|
char* endptr;
|
||||||
idx++;
|
action.line_original = strtol(content + idx, &endptr, 10);
|
||||||
}
|
if (endptr == content + idx || *endptr != ' ') {
|
||||||
if (idx == dest_len) {
|
perror("ERROR: failed to parse line_original in read_diff!");
|
||||||
perror("ERROR: unexpected end of diff in read_diff!");
|
|
||||||
free(diff_list);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
char* line_original_str = calloc(idx + 1, sizeof(char));
|
|
||||||
if (!line_original_str) {
|
|
||||||
free(diff_list);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
memcpy(line_original_str, diff_list + start_idx, idx - start_idx);
|
|
||||||
line_original_str[idx - start_idx] = '\0';
|
|
||||||
char* end2;
|
|
||||||
long line_original = strtol(line_original_str, &end2, 10);
|
|
||||||
if (end2 == line_original_str || *end2 != '\0') {
|
|
||||||
perror("ERROR: invalid line number in read_diff!");
|
|
||||||
free(line_original_str);
|
|
||||||
free(diff_list);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
free(line_original_str);
|
|
||||||
|
|
||||||
if (diff_list[idx] == ' ') idx++;
|
|
||||||
else {
|
|
||||||
perror("ERROR: expected space after line original in read_diff!");
|
|
||||||
free(diff_list);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
start_idx = idx;
|
|
||||||
while (idx < dest_len && IS_DIGIT(diff_list[idx])) {
|
|
||||||
idx++;
|
|
||||||
}
|
|
||||||
if (idx == dest_len) {
|
|
||||||
perror("ERROR: unexpected end of diff in read_diff!");
|
|
||||||
free(diff_list);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
char* line_changed_str = calloc(idx + 1, sizeof(char));
|
|
||||||
if (!line_changed_str) {
|
|
||||||
free(diff_list);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
memcpy(line_changed_str, diff_list + start_idx, idx - start_idx);
|
|
||||||
line_changed_str[idx - start_idx] = '\0';
|
|
||||||
long line_changed = strtol(line_changed_str, &end2, 10);
|
|
||||||
if (end2 == line_changed_str || *end2 != '\0') {
|
|
||||||
perror("ERROR: invalid line number in read_diff!");
|
|
||||||
free(line_changed_str);
|
|
||||||
free(diff_list);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
free(line_changed_str);
|
|
||||||
|
|
||||||
if (diff_list[idx] == ' ') idx++;
|
|
||||||
else {
|
|
||||||
perror("ERROR: expected space after line changed in read_diff!");
|
|
||||||
free(diff_list);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
idx = endptr - content + 1;
|
||||||
|
|
||||||
start_idx = idx;
|
action.line_changed = strtol(content + idx, &endptr, 10);
|
||||||
while (idx < dest_len && IS_DIGIT(diff_list[idx])) {
|
if (endptr == content + idx || *endptr != ' ') {
|
||||||
idx++;
|
perror("ERROR: failed to parse line_changed in read_diff!");
|
||||||
}
|
|
||||||
if (idx == dest_len) {
|
|
||||||
perror("ERROR: unexpected end of diff in read_diff!");
|
|
||||||
free(diff_list);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
char* content_len_str = calloc(idx + 1, sizeof(char));
|
|
||||||
if (!content_len_str) {
|
|
||||||
free(diff_list);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
memcpy(content_len_str, diff_list + start_idx, idx - start_idx);
|
|
||||||
content_len_str[idx - start_idx] = '\0';
|
|
||||||
long content_len = strtol(content_len_str, &end2, 10);
|
|
||||||
if (end2 == content_len_str || *end2 != '\0') {
|
|
||||||
perror("ERROR: invalid line number in read_diff!");
|
|
||||||
free(content_len_str);
|
|
||||||
free(diff_list);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
free(content_len_str);
|
|
||||||
|
|
||||||
if (diff_list[idx] == ' ') idx++;
|
|
||||||
else {
|
|
||||||
perror("ERROR: expected space after line original in read_diff!");
|
|
||||||
free(diff_list);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
idx = endptr - content + 1;
|
||||||
|
|
||||||
if (idx + content_len > dest_len) {
|
size_t content_length = strtol(content + idx, &endptr, 10);
|
||||||
perror("ERROR: content length exceeds diff length in read_diff!");
|
if (endptr == content + idx || *endptr != ' ') {
|
||||||
free(diff_list);
|
perror("ERROR: failed to parse content length in read_diff!");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
idx = endptr - content + 1;
|
||||||
|
|
||||||
char* content = calloc(content_len + 1, sizeof(char));
|
action.content = strndup(content + idx, content_length);
|
||||||
if (!content) {
|
if (!action.content) {
|
||||||
free(diff_list);
|
perror("ERROR: failed to allocate memory for action content in read_diff!");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
memcpy(content, diff_list + idx, content_len);
|
idx += content_length;
|
||||||
content[content_len] = '\0';
|
} else {
|
||||||
|
perror("ERROR: unknown action type in read_diff!");
|
||||||
idx += content_len;
|
|
||||||
|
|
||||||
Action action = {.type=INSERT, .line_original=line_original, .line_changed=line_changed, .content=content};
|
|
||||||
add_action(diff_out, action);
|
|
||||||
action_idx++;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
perror("ERROR: invalid opbit in read_diff!");
|
|
||||||
free(diff_list);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
add_action(diff_out, action);
|
||||||
|
|
||||||
|
action_idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int save_file_diff(char* path, char* root, size_t diff_id, char* basefile_hash, Changes* changes) {
|
int save_file_diff(char* path, char* root, size_t diff_id, char* basefile_hash, Changes* changes) {
|
||||||
char basefile_location[2+strlen(root)+strlen("/.merk/objects/")+strlen(basefile_hash)];
|
char basefile_location[2+strlen(root)+strlen("/.merk/objects/")+strlen(basefile_hash)];
|
||||||
snprintf(basefile_location, sizeof(basefile_location), "%s/.merk/objects/%.2s/%s", root, basefile_hash, basefile_hash+2);
|
snprintf(basefile_location, sizeof(basefile_location), "%s/.merk/objects/%.2s/%s", root, basefile_hash, basefile_hash+2);
|
||||||
|
|
@ -1135,30 +794,4 @@ File* apply_diff(File* basefile, ActionList* diff) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return copy;
|
return copy;
|
||||||
}
|
|
||||||
|
|
||||||
int compare_actions(const void* a, const void* b) {
|
|
||||||
const Action* action1 = (const Action*)a;
|
|
||||||
const Action* action2 = (const Action*)b;
|
|
||||||
|
|
||||||
if (action1->type != action2->type) {
|
|
||||||
return (action1->type == DELETE) ? -1 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action1->type == DELETE) {
|
|
||||||
if (action1->line_original < action2->line_original) return 1;
|
|
||||||
if (action1->line_original > action2->line_original) return -1;
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
if (action1->line_changed < action2->line_changed) return -1;
|
|
||||||
if (action1->line_changed > action2->line_changed) return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void sort_action_list(ActionList* actions) {
|
|
||||||
if (!actions || actions->len <= 1) return;
|
|
||||||
|
|
||||||
qsort(actions->actions, actions->len, sizeof(Action), compare_actions);
|
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue