From 1a45b1e2192a7334724cc56d90afbc5cf08ebf26 Mon Sep 17 00:00:00 2001 From: Zvonimir Rudinski Date: Thu, 21 Dec 2023 18:26:44 +0100 Subject: [PATCH] steal a linked list implementation --- Makefile | 7 +++- README.md | 3 ++ engine/llist.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++ engine/llist.h | 21 +++++++++++ main.c | 97 +++++++++++++++++++++++++++---------------------- 5 files changed, 182 insertions(+), 45 deletions(-) create mode 100644 engine/llist.c create mode 100644 engine/llist.h diff --git a/Makefile b/Makefile index 0aa8afe..dd793c7 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,8 @@ .DEFAULT_GOAL := purge +llist.o: + cc -c engine/llist.c -o llist.o + todo.o: cc -c engine/todo.c -o todo.o @@ -10,5 +13,5 @@ purge: rm -f *.o make all -all: todo.o main.o - cc todo.o main.o -o todd +all: todo.o main.o llist.o + cc todo.o main.o llist.o -o todd diff --git a/README.md b/README.md index eda43f0..acabaec 100644 --- a/README.md +++ b/README.md @@ -10,3 +10,6 @@ Just run: `./build.sh` and run `./todd` after that. - [ ] Save todos to disk - [ ] Smarter way to organize todos (instead of global array) - [ ] Add a TUI + +# Attributions +- https://gist.github.com/meylingtaing/11018042 diff --git a/engine/llist.c b/engine/llist.c new file mode 100644 index 0000000..c8472f3 --- /dev/null +++ b/engine/llist.c @@ -0,0 +1,99 @@ +/* llist.c + * Generic Linked List implementation + */ + +#include +#include +#include "llist.h" + +llist *llist_create(TodoItem *new_item) +{ + TodoItemNode *new_node; + + llist *new_list = (llist *)malloc(sizeof (llist)); + *new_list = (TodoItemNode *)malloc(sizeof (TodoItemNode)); + + new_node = *new_list; + new_node->item = new_item; + new_node->next = NULL; + return new_list; +} + +void llist_free(llist *list) +{ + TodoItemNode *curr = *list; + TodoItemNode *next; + + while (curr != NULL) { + next = curr->next; + free(curr); + curr = next; + } + + free(list); +} + +void llist_push(llist *list, TodoItem *item) +{ + TodoItemNode *head; + TodoItemNode *new_node; + if (list == NULL || *list == NULL) { + fprintf(stderr, "llist_add_inorder: list is null\n"); + } + + head = *list; + + // Head is empty node + if (head->item == NULL) + head->item = item; + + // Head is not empty, add new node to front + else { + new_node = malloc(sizeof (TodoItemNode)); + new_node->item = item; + new_node->next = head; + *list = new_node; + } +} + +TodoItem *llist_pop(llist *list) +{ + TodoItem *popped_item; + TodoItemNode *head = *list; + + if (list == NULL || head->item == NULL) + return NULL; + + popped_item = head->item; + *list = head->next; + + free(head); + + return popped_item; +} + +void llist_print(llist *list, void (*print)(TodoItem *)) +{ + TodoItemNode *curr = *list; + while (curr != NULL) { + print(curr->item); + printf(" "); + curr = curr->next; + } + putchar('\n'); +} + +unsigned int llist_length(llist *list) { + if (list == NULL) { + return 0; + } + + TodoItemNode *curr = *list; + unsigned int length = 0; + while (curr != NULL) { + length++; + curr = curr->next; + } + + return length; +} diff --git a/engine/llist.h b/engine/llist.h new file mode 100644 index 0000000..3c1dd99 --- /dev/null +++ b/engine/llist.h @@ -0,0 +1,21 @@ +#ifndef LLIST_H +#define LLIST_H +#include "todo.h" +/* llist.h + * Generic Linked List + */ + +typedef struct Node { + TodoItem *item; + struct Node *next; +} TodoItemNode; + +typedef TodoItemNode *llist; + +llist *llist_create(TodoItem *item); +void llist_free(llist *list); +void llist_push(llist *list, TodoItem *item); +TodoItem *llist_pop(llist *list); +void llist_print(llist *list, void (*print)(TodoItem *item)); +unsigned int llist_length(llist *list); +#endif diff --git a/main.c b/main.c index 3b42714..1545d5f 100644 --- a/main.c +++ b/main.c @@ -2,6 +2,7 @@ #include #include #include "engine/todo.h" +#include "engine/llist.h" #define MAX_TODOS 10 #define SAVE_FILE "todos.todd" @@ -13,11 +14,11 @@ enum Command { REMOVE = 'r', QUIT = 'q', - SERIALIZE = 's' + WRITE_TO_FILE = 'w', + LOAD_FROM_FILE = 'l', }; -TodoItem todos[MAX_TODOS]; -int todos_count = 0; +llist *todos; void add_command_handler() { char title[TODO_MAX_TITLE_LENGTH]; @@ -27,28 +28,55 @@ void add_command_handler() { title[strlen(title) - 1] = '\0'; TodoItem item = todo_create_item(title); - todos[todos_count] = item; - todos_count++; + if (llist_length(todos) == 0) { + todos = llist_create(&item); + } else { + llist_push(todos, &item); + } } -void print_all_todos() { - for (int i = 0; i < todos_count; i++) { - todo_print_item(&todos[i]); - } +void mark_command_handler() { + int op_index = -1; + do { + printf("Enter todo index: "); + op_index = getc(stdin) - '0'; + getc(stdin); // remove the newline character from the buffer + } while (op_index < 0 || op_index >= llist_length(todos)); + + todo_mark_item(todos[op_index]->item, !todos[op_index]->item->completed); +} + +void print_command_handler() { + llist_print(todos, todo_print_item); } void remove_todo_at_index(int index) { - for (int i = index; i < todos_count - 1; i++) { - todos[i] = todos[i + 1]; + // TODO!: Implement this + /* for (int i = index; i < todos_count - 1; i++) { */ + /* todos[i] = todos[i + 1]; */ + /* } */ + /* todos_count--; */ +} + +void write_to_file_handler() { + FILE *file = fopen(SAVE_FILE, "wb"); + int todos_count = llist_length(todos); + int bs = 0; + // write a magic value "TODD" to the file + fwrite("TODD", sizeof(char), 4, file); + // write the number of todos to the file + fwrite(&todos_count, sizeof(int), 1, file); + // write each todo to the file + for (int i = 0; i < todos_count; i++) { + char *buffer = todo_item_serialize(todos[i]->item, &bs); + fwrite(buffer, sizeof(char), bs, file); + free(buffer); } - todos_count--; + fclose(file); } int main(int argc, char **argv) { char cmd; - int op_index = -1; - int bs; - FILE *file; do { printf("Enter command: "); @@ -57,43 +85,22 @@ int main(int argc, char **argv) { switch (cmd) { case ADD: - if (todos_count + 1 > MAX_TODOS) { + if (llist_length(todos) + 1 > MAX_TODOS) { printf("No more space for new todos\n"); break; } add_command_handler(); break; case MARK: - do { - printf("Enter todo index: "); - op_index = getc(stdin) - '0'; - getc(stdin); // remove the newline character from the buffer - } while (op_index < 0 || op_index >= todos_count); - todo_mark_item(&todos[op_index], !todos[op_index].completed); + mark_command_handler(); break; case PRINT: - print_all_todos(); + print_command_handler(); break; case REMOVE: - do { - printf("Enter todo index: "); - op_index = getc(stdin) - '0'; - getc(stdin); // remove the newline character from the buffer - } while (op_index < 0 || op_index >= todos_count); - remove_todo_at_index(op_index); - case SERIALIZE: - file = fopen(SAVE_FILE, "wb"); - // write a magic value "TODD" to the file - fwrite("TODD", sizeof(char), 4, file); - // write the number of todos to the file - fwrite(&todos_count, sizeof(int), 1, file); - // write each todo to the file - for (int i = 0; i < todos_count; i++) { - char *buffer = todo_item_serialize(&todos[i], &bs); - fwrite(buffer, sizeof(char), bs, file); - free(buffer); - } - fclose(file); + break; + case WRITE_TO_FILE: + write_to_file_handler(); break; case QUIT: break; @@ -104,7 +111,11 @@ int main(int argc, char **argv) { } while (cmd != QUIT); + // free all the todos + int todos_count = llist_length(todos); + for (int i = 0; i < todos_count; i++) { - todo_free_item(&todos[i]); + todo_free_item(todos[i]->item); + llist_pop(todos); } }