From aa851fad3a3e4fd2a67327229f12512458351780 Mon Sep 17 00:00:00 2001 From: Zvonimir Rudinski Date: Thu, 21 Dec 2023 18:06:50 +0100 Subject: [PATCH] add todo serialization --- .gitignore | 1 + Makefile | 2 +- engine/todo.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++ engine/todo.h | 25 +++++++++++++++++++++++ main.c | 45 ++++++++++++++++++++++++++++++++--------- todo.c | 23 --------------------- todo.h | 15 -------------- 7 files changed, 119 insertions(+), 48 deletions(-) create mode 100644 engine/todo.c create mode 100644 engine/todo.h delete mode 100644 todo.c delete mode 100644 todo.h diff --git a/.gitignore b/.gitignore index ffad158..43ef343 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ todd *.o +*.todd diff --git a/Makefile b/Makefile index a9346e3..0aa8afe 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ .DEFAULT_GOAL := purge todo.o: - cc -c todo.c -o todo.o + cc -c engine/todo.c -o todo.o main.o: cc -c main.c -o main.o diff --git a/engine/todo.c b/engine/todo.c new file mode 100644 index 0000000..3d488a4 --- /dev/null +++ b/engine/todo.c @@ -0,0 +1,56 @@ +#include "todo.h" +#include +#include +#include + +// Memory management +void todo_free_item(TodoItem *item) { + free(item->title); +} + +// Item operations +TodoItem todo_create_item(char *title) { + TodoItem item; + item.title_length = strlen(title); + item.title = malloc(item.title_length); + strcpy(item.title, title); + item.completed = false; + + return item; +} + +void todo_mark_item(TodoItem *item, bool_t completed) { + item->completed = completed; +} + +void todo_print_item(TodoItem *item) { + printf("%s - ", item->title); + if (item->completed) { + printf("Completed\n"); + } else { + printf("Not Completed\n"); + } +} + +// Serialization +char *todo_item_serialize(TodoItem *item, int *buffer_size_out) { + // Layout of the serialized item: + // title_length - 1 byte + // title - title_length bytes + // completed - 1 byte + unsigned char title_length = item->title_length; unsigned char completed_length = sizeof(item->completed); + int buffer_size = sizeof(unsigned char) + title_length + completed_length; + + char *buffer = malloc(buffer_size); + + // copy title length + memcpy(buffer, &title_length, sizeof(unsigned char)); + // copy title + memcpy(buffer + sizeof(unsigned char), item->title, title_length); + // copy completed + memcpy(buffer + sizeof(unsigned char) + title_length, &item->completed, completed_length); + + *buffer_size_out = buffer_size; + + return buffer; +} diff --git a/engine/todo.h b/engine/todo.h new file mode 100644 index 0000000..4cd1e6f --- /dev/null +++ b/engine/todo.h @@ -0,0 +1,25 @@ +#ifndef TODO_H +#define TODO_H +#define TODO_MAX_TITLE_LENGTH 255 + +#define true 1 +#define false 0 +typedef unsigned char bool_t; + +typedef struct { + unsigned char title_length; + char *title; + bool_t completed; +} TodoItem; + +// Memory management +void todo_free_item(TodoItem *item); + +// Item operations +TodoItem todo_create_item(char *title); +void todo_mark_item(TodoItem *item, bool_t completed); +void todo_print_item(TodoItem *item); + +// Serialization +char *todo_item_serialize(TodoItem *item, int *buffer_size_out); +#endif diff --git a/main.c b/main.c index c70ff68..3b42714 100644 --- a/main.c +++ b/main.c @@ -1,33 +1,39 @@ #include #include -#include "todo.h" +#include +#include "engine/todo.h" + +#define MAX_TODOS 10 +#define SAVE_FILE "todos.todd" enum Command { ADD = 'a', MARK = 'm', PRINT = 'p', REMOVE = 'r', - QUIT = 'q' + QUIT = 'q', + + SERIALIZE = 's' }; TodoItem todos[MAX_TODOS]; int todos_count = 0; -void add_todo() { - char title[MAX_TODO_TITLE_LENGTH]; +void add_command_handler() { + char title[TODO_MAX_TITLE_LENGTH]; printf("Enter todo title: "); - fgets(title, MAX_TODO_TITLE_LENGTH - 1, stdin); + fgets(title, TODO_MAX_TITLE_LENGTH - 1, stdin); // remove the newline character from the buffer title[strlen(title) - 1] = '\0'; - TodoItem item = create_todo(title); + TodoItem item = todo_create_item(title); todos[todos_count] = item; todos_count++; } void print_all_todos() { for (int i = 0; i < todos_count; i++) { - print_todo(&todos[i]); + todo_print_item(&todos[i]); } } @@ -41,6 +47,9 @@ void remove_todo_at_index(int index) { int main(int argc, char **argv) { char cmd; int op_index = -1; + int bs; + FILE *file; + do { printf("Enter command: "); cmd = getc(stdin); @@ -52,7 +61,7 @@ int main(int argc, char **argv) { printf("No more space for new todos\n"); break; } - add_todo(); + add_command_handler(); break; case MARK: do { @@ -60,7 +69,7 @@ int main(int argc, char **argv) { op_index = getc(stdin) - '0'; getc(stdin); // remove the newline character from the buffer } while (op_index < 0 || op_index >= todos_count); - mark_todo(&todos[op_index], !todos[op_index].completed); + todo_mark_item(&todos[op_index], !todos[op_index].completed); break; case PRINT: print_all_todos(); @@ -72,6 +81,20 @@ int main(int argc, char **argv) { 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 QUIT: break; default: @@ -80,4 +103,8 @@ int main(int argc, char **argv) { } } while (cmd != QUIT); + + for (int i = 0; i < todos_count; i++) { + todo_free_item(&todos[i]); + } } diff --git a/todo.c b/todo.c deleted file mode 100644 index 7c05c24..0000000 --- a/todo.c +++ /dev/null @@ -1,23 +0,0 @@ -#include "todo.h" -#include -#include - -TodoItem create_todo(const char *title) { - TodoItem item; - strncpy(item.title, title, MAX_TODO_TITLE_LENGTH); - item.completed = false; - return item; -} - -void mark_todo(TodoItem *item, bool completed) { - (*item).completed = completed; -} - -void print_todo(TodoItem *item) { - printf("%s - ", item->title); - if (item->completed) { - printf("Completed\n"); - } else { - printf("Not Completed\n"); - } -} diff --git a/todo.h b/todo.h deleted file mode 100644 index 057d48b..0000000 --- a/todo.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef TODO_H -#define TODO_H -#include -#define MAX_TODO_TITLE_LENGTH 32 -#define MAX_TODOS 10 - -typedef struct { - char title[MAX_TODO_TITLE_LENGTH]; - bool completed; -} TodoItem; - -TodoItem create_todo(const char *title); -void mark_todo(TodoItem *item, bool completed); -void print_todo(TodoItem *item); -#endif