aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordam <dam@gudinoff>2022-09-29 00:14:20 +0000
committerdam <dam@gudinoff>2022-09-29 00:14:20 +0000
commit92ca1b6d71706cdb91abc4690da4215891e03479 (patch)
tree4e2e2de389763582c573428ea9938e6929238f07
parent8d2f93fe0497c322f2243cad123b70543cab9eac (diff)
downloadtask-time-tracker-92ca1b6d71706cdb91abc4690da4215891e03479.tar.zst
task-time-tracker-92ca1b6d71706cdb91abc4690da4215891e03479.zip
During startup, create database and archive files if missing.
-rw-r--r--main.c82
-rw-r--r--readme.md7
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 <string.h>
#include <time.h>
-#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.