add todo serialization

This commit is contained in:
Zvonimir Rudinski
2023-12-21 18:06:50 +01:00
parent a89a330ede
commit aa851fad3a
7 changed files with 119 additions and 48 deletions

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
todd
*.o
*.todd

View File

@@ -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

56
engine/todo.c Normal file
View File

@@ -0,0 +1,56 @@
#include "todo.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
// 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;
}

25
engine/todo.h Normal file
View File

@@ -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

45
main.c
View File

@@ -1,33 +1,39 @@
#include <stdio.h>
#include <string.h>
#include "todo.h"
#include <stdlib.h>
#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]);
}
}

23
todo.c
View File

@@ -1,23 +0,0 @@
#include "todo.h"
#include <string.h>
#include <stdio.h>
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");
}
}

15
todo.h
View File

@@ -1,15 +0,0 @@
#ifndef TODO_H
#define TODO_H
#include <stdbool.h>
#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