From 3f35a0052651752f268a17ad04f1493bbebd693d Mon Sep 17 00:00:00 2001 From: FantasyPvP <80643031+FantasyPvP@users.noreply.github.com> Date: Thu, 5 Dec 2024 01:42:50 +0000 Subject: [PATCH] logging works ( but it's buggy :sob: ) --- final/debug.txt | 0 final/diff.txt | 270 ++++++++++++++++++++++++++++++++++++++++++++++++ final/dynstr.c | 15 ++- final/dynstr.h | 4 +- final/editor.c | 221 +++++++++++++++++++++++++++++++++------ final/editor.h | 11 +- final/log.c | 10 +- final/log.h | 2 +- final/log.txt | 27 +++++ final/main.c | 5 +- final/state.c | 150 +++++++++++++++++++++++++++ final/state.h | 115 +++++++++++++++++++++ 12 files changed, 786 insertions(+), 44 deletions(-) create mode 100644 final/debug.txt create mode 100644 final/diff.txt create mode 100644 final/log.txt create mode 100644 final/state.c create mode 100644 final/state.h diff --git a/final/debug.txt b/final/debug.txt new file mode 100644 index 0000000..e69de29 diff --git a/final/diff.txt b/final/diff.txt new file mode 100644 index 0000000..50940c0 --- /dev/null +++ b/final/diff.txt @@ -0,0 +1,270 @@ +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +REMOVED +REMOVED +REMOVED +REMOVED +REMOVED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +ADDED +ADDED +ADDED +ADDED +ADDED +ADDED +ADDED +ADDED +ADDED +ADDED +REMOVED +REMOVED +REMOVED +REMOVED +REMOVED +REMOVED +REMOVED +REMOVED +REMOVED +REMOVED +REMOVED +REMOVED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED +UNMODIFIED diff --git a/final/dynstr.c b/final/dynstr.c index ad1c61f..4022ab7 100644 --- a/final/dynstr.c +++ b/final/dynstr.c @@ -96,7 +96,6 @@ String_t str_from_file(FILE* file) { return string; } - int str_to_file(String_t* self, FILE* file) { char* data = to_chars(self); @@ -108,16 +107,24 @@ int str_to_file(String_t* self, FILE* file) { return 0; } - String_t str_clone(String_t* self) { String_t clone; clone.size = self->size; clone.capacity = self->capacity; - clone.data = (char*)malloc(clone.capacity); + clone.data = (char*)calloc(clone.capacity, sizeof(char)); memcpy(clone.data, self->data, clone.capacity); return clone; } +String_t* str_clone_all(String_t* strings, int len) { + String_t* clones = (String_t*)calloc(len, sizeof(String_t)); + + for (int i = 0; i < len; i++) { + clones[i] = str_clone(&strings[i]); + } + return clones; +} + char str_pop(String_t* self) { if (self->size == 0) { return '\0'; @@ -244,4 +251,4 @@ String_t str_slice(String_t* s, int start, int end) { s2.data[i] = s->data[start + i]; } return s2; -} +} \ No newline at end of file diff --git a/final/dynstr.h b/final/dynstr.h index 4439426..7cd8a49 100644 --- a/final/dynstr.h +++ b/final/dynstr.h @@ -70,7 +70,9 @@ String_t str_new(); * This allocates new memory that must be freed * @param self Pointer to the String_t to clone */ -String_t str_clone(); +String_t str_clone(String_t* self); + +String_t* str_clone_all(String_t* strings, int len); /** * Creates a new string containing a slice of an existing string. diff --git a/final/editor.c b/final/editor.c index 24d9fee..49fc5e6 100644 --- a/final/editor.c +++ b/final/editor.c @@ -1,6 +1,8 @@ #include #include #include "dynstr.h" +#include "log.h" +#include "state.h" #include #define min(x, y) ((x) < (y) ? (x) : (y)) @@ -15,9 +17,13 @@ typedef struct { uint32_t x_offset; bool unsaved_changes; bool editmode; - String_t* buffer; - String_t* original; String_t filename; + String_t* buffer; + + // variables needed for the changelog functionality + int original_len; // length of the original buffer + String_t* original; // original buffer + StateArray diff; // changelog } Editor; void add_toolbar(Editor* self) { @@ -46,6 +52,23 @@ void add_toolbar(Editor* self) { attroff(COLOR_PAIR(1)); } +void refresh_cursor(Editor* self) { + + int max_x,max_y; + getmaxyx(stdscr, max_y, max_x); + + // Clamp cursor position to screen bounds + int cursor_y = min( + max(self->buffer_line - self->y_offset, 0), + max_y - 1 + ); + int cursor_x = min( + max(self->buffer_col - self->x_offset + 5, 5), + max_x - 1 + ); + + move(cursor_y, cursor_x); +} void refresh_buffer(Editor* self) { move(0, 0); @@ -99,41 +122,42 @@ void refresh_buffer(Editor* self) { } add_toolbar(self); + refresh_cursor(self); + } - // Ensure cursor position is valid - int cursor_y = self->buffer_line - self->y_offset; - int cursor_x = self->buffer_col - self->x_offset + 5; - - // Clamp cursor position to screen bounds - cursor_y = min(max(cursor_y, 0), max_y - 1); - cursor_x = min(max(cursor_x, 5), max_x - 1); - - move(cursor_y, cursor_x); -} -void move_cursor_on_screen(Editor* editor, int x, int y) { +void move_cursor_on_screen(Editor* self, int x, int y) { + bool offset_changed = false; int max_x, max_y; + getmaxyx(stdscr, max_y, max_x); max_y--; // Reserve bottom line for toolbar max_x -= 5; // Account for line number margin - // Adjust x_offset if cursor would be off screen - if (x + 5 >= max_x + editor->x_offset) { - editor->x_offset = x - max_x + 6; + // Adjust x_offset if cursor would be off screen + if (x + 5 >= max_x + self->x_offset) { + self->x_offset = x - max_x + 6; + offset_changed = true; } - if (x < editor->x_offset) { - editor->x_offset = x; + if (x < self->x_offset) { + self->x_offset = x; + offset_changed = true; } // Adjust y_offset if cursor would be off screen - if (y >= max_y + editor->y_offset) { - editor->y_offset = y - max_y + 1; + if (y >= max_y + self->y_offset) { + self->y_offset = y - max_y + 1; + offset_changed = true; } - if (y < editor->y_offset) { - editor->y_offset = y; + if (y < self->y_offset) { + self->y_offset = y; + offset_changed = true; + } + if (offset_changed) { + refresh_buffer(self); + } else { + refresh_cursor(self); } - - refresh_buffer(editor); } void switch_mode(Editor* self) { @@ -144,7 +168,7 @@ void switch_mode(Editor* self) { void newline(Editor* self) { move(self->buffer_line, 0); char line_no[6]; - snprintf(line_no, 6, "%-6d", self->buffer_line + 1); + snprintf(line_no, 6, "%-5d", self->buffer_line + 1); // add the line number attron(COLOR_PAIR(1)); @@ -166,9 +190,13 @@ Editor editor_from(String_t input_string, String_t filename) { int linenum = 0; e.buffer = str_lines(&input_string, &linenum); + e.original = str_clone_all(e.buffer, linenum); e.lines = (uint32_t)linenum; + e.original_len = linenum; e.capacity = e.lines; + e.diff = arr_init(e.lines); + str_dealloc(&input_string); refresh_buffer(&e); @@ -179,22 +207,129 @@ Editor new_editor(String_t filename) { return editor_from(str_new(), filename); } +int print_diff(Editor* self) { + + char buffer[512]; + String_t log_string = str_new(); + int original_offset; + int modified_offset; + + for (size_t i = 0; i < self->diff.size; i++) { + LineState state = self->diff.data[i]; + switch (state) { + // case UNMODIFIED: + // original_offset = arr_original_offset(&self->diff, i); + // snprintf( + // buffer, + // 512, + // "UNMODIFIED %s \n", + // to_chars(&self->buffer[original_offset + i]) + // ); + // str_push_str(&log_string, buffer); + // break; + + case MODIFIED: + original_offset = arr_original_offset(&self->diff, i); + modified_offset = arr_modified_offset(&self->diff, i); + snprintf( + buffer, + 512, + "MODIFIED %-6d | %s\n -> %-6d | %s \n", + original_offset + i + 1, + to_chars(&self->original[original_offset + i]), + modified_offset + i + 1, + to_chars(&self->buffer[modified_offset + i]) + ); + str_push_str(&log_string, buffer); + break; + + case REMOVED: + original_offset = arr_original_offset(&self->diff, i); + snprintf( + buffer, + 512, + "REMOVED %-6d | %s \n", + original_offset + i + 1, + to_chars(&self->original[original_offset + i]) + ); + str_push_str(&log_string, buffer); + break; + + case ADDED: + modified_offset = arr_modified_offset(&self->diff, i); + snprintf( + buffer, + 512, + "ADDED %-6d | %s \n", + modified_offset + i + 1, + to_chars(&self->buffer[modified_offset + i]) + ); + str_push_str(&log_string, buffer); + break; + + default: + break; + } + } + + if (write_log(&log_string) == -1) { + fprintf(stderr, "Error writing log\n"); + return -1; + } + str_dealloc(&log_string); +} + int save_file(Editor* self) { + String_t log_string = str_new(); + char log_message[64]; char* name = to_chars(&self->filename); + FILE* file = fopen(name, "w"); + + if (file == NULL) { + fprintf(stderr, "Error: Could not open file %s\n", name); + return -1; + } // writes the content line by line to the file - FILE* file = fopen(name, "w"); for (size_t i = 0; i < self->lines; i++) { if (str_to_file(&self->buffer[i], file) == -1) { - free(name); fprintf(stderr, "Error writing to file\n"); return -1; } } + arr_print(&self->diff); + print_diff(self); + free(name); fclose(file); + + for (size_t i = 0; i < self->original_len; i++) { + str_dealloc(&self->original[i]); + } + free(self->original); + self->original = str_clone_all(self->buffer, self->lines); + + snprintf(log_message, 64, "Edited file [%s]\n", to_chars(&self->filename)); + str_push_str(&log_string, log_message); + + self->original_len = self->lines; + + snprintf(log_message, 64, "Old Length: [%d] New Length: [%d]\n", self->original_len, self->lines); + str_push_str(&log_string, log_message); + + // log messages + if (write_log(&log_string) == -1) { + fprintf(stderr, "Error writing log\n"); + return -1; + } + + printf("wrote log"); + str_dealloc(&log_string); + + arr_dealloc(&self->diff); + self->diff = arr_init(self->lines); return 0; } @@ -235,7 +370,6 @@ void delchar(Editor* self) { self->unsaved_changes = true; if (self->buffer_col == str_len(&self->buffer[self->buffer_line])) { - if (self->buffer_line +1 == self->lines) { return; } @@ -245,7 +379,13 @@ void delchar(Editor* self) { String_t old_next_line = self->buffer[self->buffer_line + 1]; // assign the new line - self->buffer[self->buffer_line] = str_merge(&self->buffer[self->buffer_line], &self->buffer[self->buffer_line + 1]); + self->buffer[self->buffer_line] = str_merge(&old_curr_line, &old_next_line); + + if (arr_get(&self->diff, self->buffer_line + 1) == ADDED) { + arr_remove(&self->diff, self->buffer_line + 1); + } else { + arr_set(&self->diff, self->buffer_line + 1, REMOVED); + } // deallocate the memory for the old lines str_dealloc(&old_curr_line); @@ -261,6 +401,8 @@ void delchar(Editor* self) { refresh_buffer(self); } else { // removes the character from the current line + arr_set(&self->diff, self->buffer_line, MODIFIED); + str_remove(&self->buffer[self->buffer_line], self->buffer_col); delch(); } @@ -278,6 +420,9 @@ void pressed_enter(Editor* self) { } self->buffer = (String_t*)realloc(self->buffer, sizeof(String_t) * (self->capacity)); + // logs the change of adding a new line + arr_insert(&self->diff, self->buffer_line + 1, ADDED); + if (self->buffer_line == self->lines -1) { // if at end of file add an empty line self->buffer[self->lines - 1] = str_new(); @@ -314,6 +459,12 @@ void addchar(Editor* self, char c) { if (self->buffer_line == self->lines) { // if we are at the end of the file then we need to add a new line + if (arr_get(&self->diff, self->buffer_line) == REMOVED) { + arr_set(&self->diff, self->buffer_line, MODIFIED); + } else { + arr_insert(&self->diff, self->buffer_line, ADDED); + } + newline(self); // reallocate self->buffer to be 1 larger @@ -327,6 +478,10 @@ void addchar(Editor* self, char c) { // allocate the memory space for the new line and add it to the buffer self->buffer[self->buffer_line] = str_new(); + } else { + if (arr_get(&self->diff, self->buffer_line) == UNMODIFIED) { + arr_set(&self->diff, self->buffer_line, MODIFIED); + } } insch(c); @@ -339,6 +494,12 @@ void shutdown_editor(Editor* self) { for (size_t i = 0; i < self->capacity; i++) { str_dealloc(&self->buffer[i]); } - str_dealloc(&self->filename); free(self->buffer); + + for (size_t i = 0; i < self->original_len; i++) { + str_dealloc(&self->original[i]); + } + free(self->original); + + str_dealloc(&self->filename); } diff --git a/final/editor.h b/final/editor.h index 24f1b6b..5dc3c90 100644 --- a/final/editor.h +++ b/final/editor.h @@ -1,4 +1,5 @@ #include "dynstr.h" +#include "state.h" #include /** @@ -6,7 +7,7 @@ * cursor position, and various editor settings. */ typedef struct { - uint32_t lines; + uint32_t lines; uint32_t capacity; uint32_t buffer_line; uint32_t buffer_col; @@ -14,9 +15,13 @@ typedef struct { uint32_t x_offset; bool unsaved_changes; bool editmode; - String_t* buffer; - String_t* original; String_t filename; + String_t* buffer; + + // variables needed for the changelog functionality + int original_len; // length of the original buffer + String_t* original; // original buffer + StateArray diff; // changelog } Editor; /** diff --git a/final/log.c b/final/log.c index 7f15bfa..04bdfb1 100644 --- a/final/log.c +++ b/final/log.c @@ -1,14 +1,18 @@ #include "dynstr.h" -int write_log(String_t* string, int lines) { +int write_log(String_t* string) { FILE* file = fopen("log.txt", "a"); + int numlines; + String_t* lines = str_lines(string, &numlines); - for (int i = 0; i < lines; i++) { - str_to_file(&string[i], file); + for (int i = 0; i < numlines; i++) { + str_to_file(&lines[i], file); } + fclose(file); + return 0; } diff --git a/final/log.h b/final/log.h index a5ff0a3..0263570 100644 --- a/final/log.h +++ b/final/log.h @@ -8,5 +8,5 @@ * @return 0 on success, -1 on error * @note This function frees the string passed to it! */ -int write_log(String_t* string, int lines); +int write_log(String_t* string); diff --git a/final/log.txt b/final/log.txt new file mode 100644 index 0000000..cca5046 --- /dev/null +++ b/final/log.txt @@ -0,0 +1,27 @@ +REMOVED 16 | +REMOVED 17 | +REMOVED 18 | modifie +REMOVED 19 | +REMOVED 20 | +ADDED 35 | } AND modified a line. +ADDED 36 | +ADDED 37 | +ADDED 38 | added some lines +ADDED 39 | +ADDED 40 | +ADDED 41 | +ADDED 42 | +ADDED 43 | +ADDED 44 | +REMOVED 40 | } AND modified a line. +REMOVED 41 | +REMOVED 42 | +REMOVED 43 | added some lines +REMOVED 44 | +REMOVED 45 | +REMOVED 46 | +REMOVED 47 | +REMOVED 48 | +REMOVED 49 | +REMOVED 50 | +REMOVED 51 | diff --git a/final/main.c b/final/main.c index aba9f04..647dda0 100644 --- a/final/main.c +++ b/final/main.c @@ -211,7 +211,7 @@ int main(int argc, char* argv[]) { if (argc == 3) { switch (cmd) { case CMD_OPEN: - sprintf(log_fmt_string, "Edited File [%s]", argv[2]); + sprintf(log_fmt_string, "Opened File [%s]", argv[2]); open_editor(argv[2]); break; case CMD_RM: @@ -263,7 +263,8 @@ int main(int argc, char* argv[]) { // log output of command if (log_fmt_string[0] != '\0') { String_t str = str_from_chars(log_fmt_string); - write_log(&str, 1); + write_log(&str); + str_dealloc(&str); } return 0; diff --git a/final/state.c b/final/state.c new file mode 100644 index 0000000..118d893 --- /dev/null +++ b/final/state.c @@ -0,0 +1,150 @@ +/// dynamic array class +/// written by: Harry Irving + +#include +#include +#include +#include +#include + +typedef enum LineState { + UNMODIFIED, + MODIFIED, + ADDED, + REMOVED, +} LineState; + +typedef struct { + uint32_t size; // Current number of elements + uint32_t capacity; // Total capacity allocated + LineState* data; // Array of LineState values +} StateArray; + +StateArray arr_init(int capacity) { + StateArray arr; + arr.size = capacity; + arr.capacity = capacity; + arr.data = (LineState*)calloc(capacity, sizeof(LineState)); + // Initialize all elements to UNMODIFIED + for (int i = 0; i < capacity; i++) { + arr.data[i] = UNMODIFIED; + } + return arr; +} + +void arr_print(StateArray* self) { + FILE* log_file = fopen("diff.txt", "w"); + if (log_file == NULL) { + fprintf(stderr, "Error: Could not open log file\n"); + } + + for (int i = 0; i < self->size; i++) { + switch (self->data[i]) { + case UNMODIFIED: + fwrite("UNMODIFIED\n", sizeof(char), strlen("UNMODIFIED\n"), log_file); + break; + case MODIFIED: + fwrite("MODIFIED\n", sizeof(char), strlen("MODIFIED\n"), log_file); + break; + case ADDED: + fwrite("ADDED\n", sizeof(char), strlen("ADDED\n"), log_file); + break; + case REMOVED: + fwrite("REMOVED\n", sizeof(char), strlen("REMOVED\n"), log_file); + break; + } + } + + fclose(log_file); +} + +int arr_added_or_removed_before(StateArray* self, int index) { + int count = 0; + for (int i = 0; i < index; i++) { + if (self->data[i] == ADDED || self->data[i] == REMOVED) { + if (self->data[i] == REMOVED) { + index++; + } + count++; + } + } + return count; +} + +void arr_set(StateArray* self, int index, LineState state) { + int offset = arr_added_or_removed_before(self, index); + self->data[index] = state; +} + +LineState arr_remove(StateArray* self, int index) { + int offset = arr_added_or_removed_before(self, index); + + if (index >= self->size) { + return -1; + } + + LineState removed = self->data[index]; + + // Shift remaining elements left + for (int i = index; i < self->size - 1; i++) { + self->data[i] = self->data[i + 1]; + } + self->size--; + + return removed; +} + +int arr_insert(StateArray* self, int index, LineState state) { + int offset = arr_added_or_removed_before(self, index); + + if (index > self->size) { + return -1; + } + self->size++; + + // Grow array if needed + if (self->size > self->capacity) { + self->capacity = (self->size) * sizeof(LineState); + self->data = (LineState*)realloc(self->data, self->capacity * sizeof(LineState)); + } + + // Shift elements right to make room + for (int i = self->size - 1; i > index; i--) { + self->data[i] = self->data[i - 1]; + } + self->data[index] = state; + return 0; +} + +LineState arr_get(StateArray* self, int index) { + int offset = arr_added_or_removed_before(self, index); + return self->data[index]; +} + +int arr_original_offset(StateArray* self, int index) { + int offset = 0; + for (int i = 0; i < index; i++) { + if (self->data[i] == ADDED) { + offset--; + } + } + return offset; +} + +int arr_modified_offset(StateArray* self, int index) { + int offset = 0; + for (int i = 0; i < index; i++) { + if (self->data[i] == REMOVED) { + offset--; + } + } + return offset; +} + +int arr_dealloc(StateArray* self) { + free(self->data); + self->data = NULL; + self->size = 0; + self->capacity = 0; + return 0; +} \ No newline at end of file diff --git a/final/state.h b/final/state.h new file mode 100644 index 0000000..8a1b645 --- /dev/null +++ b/final/state.h @@ -0,0 +1,115 @@ +#ifndef STATEARR_H +#define STATEARR_H + +#include + +typedef enum LineState { + UNMODIFIED, + MODIFIED, + ADDED, + REMOVED, +} LineState; + +/** + * Dynamic array structure for storing LineState values + */ +typedef struct { + uint32_t size; // Current number of elements + uint32_t capacity; // Total capacity allocated + LineState* data; // Array of LineState values +} StateArray; + +void arr_print(StateArray* self); + +/** + * Creates a new StateArray with the specified initial capacity + * + * All elements will have a default value of UNMODIFIED + * + * @param capacity Initial capacity in number of elements + * @return A new StateArray structure with allocated memory + */ +StateArray arr_init(int capacity); + +/** + * Sets a LineState value at the specified index + * Does not perform bounds checking + * + * @param self Pointer to the StateArray to modify + * @param index Position to set the value + * @param state The LineState value to set + */ +void arr_set(StateArray* self, int index, LineState state); + +/** + * Removes a LineState value at the specified index + * Shifts remaining elements left to fill the gap + * + * @param self Pointer to the StateArray to modify + * @param index Position of value to remove + * @return The LineState value that was removed + */ +LineState arr_remove(StateArray* self, int index); + +/** + * Inserts a LineState value at the specified index + * Shifts existing elements right to make room + * Automatically reallocates if more capacity is needed + * + * @param self Pointer to the StateArray to modify + * @param index Position to insert the value + * @param state The LineState value to insert + * @return 0 on success, -1 if index is out of bounds + */ +int arr_insert(StateArray* self, int index, LineState state); + +/** + * Gets the LineState value at the specified index + * Does not perform bounds checking + * + * @param self Pointer to the StateArray to read from + * @param index Position to get the value from + * @return The LineState value at the specified index + */ +LineState arr_get(StateArray* self, int index); + +/** + * Deallocates memory used by the StateArray + * Must be called when the array is no longer needed + * + * @param self Pointer to the StateArray to deallocate + * @return 0 on success + */ +int arr_dealloc(StateArray* self); + +/** + * Calculates the offset needed to map from state array index to original buffer index + * by counting ADDED lines before the given index + * + * @param self Pointer to the StateArray + * @param index The index in the state array + * @return The negative offset (number of ADDED lines before index) + */ +int arr_original_offset(StateArray* self, int index); + +/** + * Calculates the offset needed to map from state array index to modified buffer index + * by counting REMOVED lines before the given index + * + * @param self Pointer to the StateArray + * @param index The index in the state array + * @return The negative offset (number of REMOVED lines before index) + */ +int arr_modified_offset(StateArray* self, int index); + +/** + * Counts the number of lines that have been either added or removed + * Does not count lines that have been modified + * + * @param self Pointer to the StateArray to analyze + * @param index The index to count up to. + * @return The count of lines marked as either ADDED or REMOVED + */ +int arr_added_or_removed_before(StateArray* self, int index); + +#endif