add todo serialization
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
todd
|
todd
|
||||||
*.o
|
*.o
|
||||||
|
*.todd
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -1,7 +1,7 @@
|
|||||||
.DEFAULT_GOAL := purge
|
.DEFAULT_GOAL := purge
|
||||||
|
|
||||||
todo.o:
|
todo.o:
|
||||||
cc -c todo.c -o todo.o
|
cc -c engine/todo.c -o todo.o
|
||||||
|
|
||||||
main.o:
|
main.o:
|
||||||
cc -c main.c -o main.o
|
cc -c main.c -o main.o
|
||||||
|
|||||||
56
engine/todo.c
Normal file
56
engine/todo.c
Normal 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
25
engine/todo.h
Normal 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
45
main.c
@@ -1,33 +1,39 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.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 {
|
enum Command {
|
||||||
ADD = 'a',
|
ADD = 'a',
|
||||||
MARK = 'm',
|
MARK = 'm',
|
||||||
PRINT = 'p',
|
PRINT = 'p',
|
||||||
REMOVE = 'r',
|
REMOVE = 'r',
|
||||||
QUIT = 'q'
|
QUIT = 'q',
|
||||||
|
|
||||||
|
SERIALIZE = 's'
|
||||||
};
|
};
|
||||||
|
|
||||||
TodoItem todos[MAX_TODOS];
|
TodoItem todos[MAX_TODOS];
|
||||||
int todos_count = 0;
|
int todos_count = 0;
|
||||||
|
|
||||||
void add_todo() {
|
void add_command_handler() {
|
||||||
char title[MAX_TODO_TITLE_LENGTH];
|
char title[TODO_MAX_TITLE_LENGTH];
|
||||||
printf("Enter todo title: ");
|
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
|
// remove the newline character from the buffer
|
||||||
title[strlen(title) - 1] = '\0';
|
title[strlen(title) - 1] = '\0';
|
||||||
|
|
||||||
TodoItem item = create_todo(title);
|
TodoItem item = todo_create_item(title);
|
||||||
todos[todos_count] = item;
|
todos[todos_count] = item;
|
||||||
todos_count++;
|
todos_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_all_todos() {
|
void print_all_todos() {
|
||||||
for (int i = 0; i < todos_count; i++) {
|
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) {
|
int main(int argc, char **argv) {
|
||||||
char cmd;
|
char cmd;
|
||||||
int op_index = -1;
|
int op_index = -1;
|
||||||
|
int bs;
|
||||||
|
FILE *file;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
printf("Enter command: ");
|
printf("Enter command: ");
|
||||||
cmd = getc(stdin);
|
cmd = getc(stdin);
|
||||||
@@ -52,7 +61,7 @@ int main(int argc, char **argv) {
|
|||||||
printf("No more space for new todos\n");
|
printf("No more space for new todos\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
add_todo();
|
add_command_handler();
|
||||||
break;
|
break;
|
||||||
case MARK:
|
case MARK:
|
||||||
do {
|
do {
|
||||||
@@ -60,7 +69,7 @@ int main(int argc, char **argv) {
|
|||||||
op_index = getc(stdin) - '0';
|
op_index = getc(stdin) - '0';
|
||||||
getc(stdin); // remove the newline character from the buffer
|
getc(stdin); // remove the newline character from the buffer
|
||||||
} while (op_index < 0 || op_index >= todos_count);
|
} 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;
|
break;
|
||||||
case PRINT:
|
case PRINT:
|
||||||
print_all_todos();
|
print_all_todos();
|
||||||
@@ -72,6 +81,20 @@ int main(int argc, char **argv) {
|
|||||||
getc(stdin); // remove the newline character from the buffer
|
getc(stdin); // remove the newline character from the buffer
|
||||||
} while (op_index < 0 || op_index >= todos_count);
|
} while (op_index < 0 || op_index >= todos_count);
|
||||||
remove_todo_at_index(op_index);
|
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:
|
case QUIT:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -80,4 +103,8 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} while (cmd != QUIT);
|
} while (cmd != QUIT);
|
||||||
|
|
||||||
|
for (int i = 0; i < todos_count; i++) {
|
||||||
|
todo_free_item(&todos[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
23
todo.c
23
todo.c
@@ -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
15
todo.h
@@ -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
|
|
||||||
Reference in New Issue
Block a user