From 92ca1b6d71706cdb91abc4690da4215891e03479 Mon Sep 17 00:00:00 2001 From: dam Date: Thu, 29 Sep 2022 00:14:20 +0000 Subject: During startup, create database and archive files if missing. --- main.c | 82 +++++++++++++++++++++++++++++++++++++-------------------------- readme.md | 7 +++--- 2 files changed, 52 insertions(+), 37 deletions(-) diff --git a/main.c b/main.c index c32df1c..e138686 100644 --- a/main.c +++ b/main.c @@ -15,9 +15,10 @@ #include #include -#define MAX_TASK_NAME 58 // Maximum task name length, including null-terminator. -#define FIRST_DAY_OF_WEEK 1 // (0-6, Sunday = 0) -#define WEEK_DAYS 7 // Just to avoid magic numbers. +#define VERSION "1.0" // Use only 3 chars (to fit layouts). +#define MAX_TASK_NAME 58 // Maximum task name length (includes NUL). +#define FIRST_DAY_OF_WEEK 1 // (0-6, Sunday = 0). +#define WEEK_DAYS 7 // Just to avoid magic numbers. #define LOG_FILE_NAME "log.txt" #define DB_BIN_PATH_NAME "./database.bin" @@ -55,6 +56,17 @@ database_t *db; char *string_buffer; int size_x, size_y, pos_x, pos_y; +// Checks if file is exists and is accessible. +// Returns true when the file exists and is accessible. +bool is_file_accessible(const char *path_name) { + assert(path_name != NULL); + FILE *file = fopen(path_name, "r+"); + bool is_file_accessible = file != NULL; + if (is_file_accessible) { + fclose(file); + } + return is_file_accessible; +} // Given an UTF8 encoded string, truncate it to length without breaking any UTF8 character. // The string should have capacity for at least length number of items. @@ -329,7 +341,7 @@ bool store_database(const database_t *db, const char *path_name) { assert(path_name != NULL); // Open file. - FILE *file = fopen(path_name, "w"); + FILE *file = fopen(path_name, "wb"); if (file == NULL) { fprintf(stderr, "Failed to open file '%s' while storing database: %s.\n", path_name, strerror(errno)); return false; @@ -351,7 +363,7 @@ bool load_database(database_t *db, const char *path_name) { assert(path_name != NULL); // Open file. - FILE *file = fopen(path_name, "r"); + FILE *file = fopen(path_name, "rb"); if (file == NULL) { fprintf(stderr, "Failed to open file '%s' while loading database: %s.\n", path_name, strerror(errno)); return false; @@ -700,7 +712,7 @@ void initialize_tui() { layouts[L_NORMAL] = (layout_st) { .archive_title = " Archive ", .columns = { - { .header = " Task Time Tracker v1 ", .width = -1, .alignment = 'L' }, + { .header = " Task Time Tracker v" VERSION " ", .width = -1, .alignment = 'L' }, { .header = " Sun ", .width = 7, .alignment = 'C' }, { .header = " Mon ", .width = 7, .alignment = 'C' }, { .header = " Tue ", .width = 7, .alignment = 'C' }, @@ -716,7 +728,7 @@ void initialize_tui() { layouts[L_COMPACT] = (layout_st) { .archive_title = " Archive ", .columns = { - { .header = " TTT v1 ", .width = -1, .alignment = 'L' }, + { .header = " TTT v" VERSION " ", .width = -1, .alignment = 'L' }, { .header = " S ", .width = 5, .alignment = 'C' }, { .header = " M ", .width = 5, .alignment = 'C' }, { .header = " T ", .width = 5, .alignment = 'C' }, @@ -967,9 +979,17 @@ void free_memory() { int main(int argc, char *argv[]) { + db = &database; reset_database(&database); reset_database(&archive); - db = &database; + + if (is_file_accessible(DB_BIN_PATH_NAME) == false) { + store_database(&database, DB_BIN_PATH_NAME); + } + + if (is_file_accessible(AR_CSV_PATH_NAME) == false) { + export_to_csv(&archive, AR_CSV_PATH_NAME); + } if (argc > 1) { @@ -980,7 +1000,7 @@ int main(int argc, char *argv[]) { action = "--version"; do_action = strncmp(argv[idx], action, strlen(action)+1) == 0; if (do_action) { - fprintf(stdout, "Task Time Tracker v1.0\n"); + fprintf(stdout, "Task Time Tracker " VERSION "\n"); return EXIT_SUCCESS; } @@ -1021,6 +1041,7 @@ int main(int argc, char *argv[]) { load_database(&database, DB_BIN_PATH_NAME); import_from_csv(&database, argv[idx+1]); store_database(&database, DB_BIN_PATH_NAME); + reset_database(&database); return EXIT_SUCCESS; } @@ -1032,6 +1053,7 @@ int main(int argc, char *argv[]) { } load_database(&database, DB_BIN_PATH_NAME); export_to_csv(&database, argv[idx+1]); + reset_database(&database); return EXIT_SUCCESS; } } @@ -1042,9 +1064,7 @@ int main(int argc, char *argv[]) { initialize_tui(); - if (load_database(&database, DB_BIN_PATH_NAME) == false) { - store_database(&database, DB_BIN_PATH_NAME); - } + load_database(&database, DB_BIN_PATH_NAME); ungetch(KEY_RESIZE); for (int key; (key = getch()) != 'q'; ) { @@ -1151,14 +1171,12 @@ int main(int argc, char *argv[]) { case KEY_BACKSPACE: if (db == &database) { - if (load_database(&archive, AR_CSV_PATH_NAME) == false) { - store_database(&archive, AR_CSV_PATH_NAME); - } + reset_database(&archive); + import_from_csv(&archive, AR_CSV_PATH_NAME); db = &archive; - db->active_task = -1; // TODO This should not be necessary. } else { - store_database(&archive, AR_CSV_PATH_NAME); + export_to_csv(&archive, AR_CSV_PATH_NAME); reset_database(&archive); db = &database; } @@ -1166,26 +1184,22 @@ int main(int argc, char *argv[]) { case 'a': case 'A': - if (selected_task == NULL || selected_task == active_task) { + if (db != &database || selected_task == NULL || selected_task == active_task) { break; } - - // TODO - // Would be nice to mark several tasks to be archived then really do it, - // instead of loading adding and storing every single time. - // If the archive was in CSV, we could simply append to it. Let's do this! - if (db == &database) { - if (load_database(&archive, AR_CSV_PATH_NAME) == false) { - store_database(&archive, AR_CSV_PATH_NAME); - } - } - database_t *target = (db == &database ? &archive : &database); - add_task(target, selected_task); + append_to_csv(selected_task, AR_CSV_PATH_NAME); delete_task(db, selected_task); - if (db == &database) { - store_database(&archive, AR_CSV_PATH_NAME); - reset_database(&archive); + // TODO Maybe save stuff? Shoulw we? + break; + + case 'u': + case 'U': + if (db != &archive || selected_task == NULL) { + break; } + add_task(&database, selected_task); + delete_task(db, selected_task); + // TODO Maybe save stuff? Shoulw we? break; case KEY_LEFT: @@ -1247,7 +1261,7 @@ int main(int argc, char *argv[]) { update_timers(&database); store_database(&database, DB_BIN_PATH_NAME); if (db == &archive) { - store_database(&archive, AR_CSV_PATH_NAME); + export_to_csv(&archive, AR_CSV_PATH_NAME); } free_memory(); endwin(); diff --git a/readme.md b/readme.md index 6e6242e..5c5565d 100644 --- a/readme.md +++ b/readme.md @@ -34,9 +34,10 @@ Task Time Tracker - [x] using the archive header, we can remove the top-left-corner diamond on the archive. - [x] Allow to cancel a rename_task operation: you can do it by leaving it blank. - [x] Make sure we are not using `strcat` and `strcpy`... or that we are using them wisely (famous last words). -- [ ] Make archive be stored in CSV format: takes less space and allows to quickly archive by appending to end of file; -- [ ] Implement `append_to_csv(task_t *task, char *path_name)` and use it in archive function; -- [ ] MAYBE... IS THIS REALLY NEEDED? add helper func: get_selected_screen_row(db*, out int selected_row); It seems to be used in KEY_F(1) and KEY_F(2) cases of input management. +- [x] Make archive be stored in CSV format: takes less space and allows to quickly archive by appending to end of file; +- [x] Implement `append_to_csv(task_t *task, char *path_name)` and use it in archive function; +- [x] At startup, check for required files and create them if not present. +- [ ] Convert `get_available_rows` into a function, or variable set when resize happens - MAYBE. - [ ] Improve total_times: - Create function to recalculate them. Shouldn't take so long, right? - Decide when this will run. -- cgit v1.2.3