aboutsummaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
authordam <dam@gudinoff>2022-10-01 01:17:17 +0000
committerdam <dam@gudinoff>2022-10-01 01:17:17 +0000
commit31923fe0598464bb9745ca8fc2d7f78463e896f8 (patch)
treef081e5be55a0de23537f9485b4739d9917229a4f /main.c
parent4261d2ecc8bea77679ed3cfd67ee45bc302ed753 (diff)
downloadtask-time-tracker-31923fe0598464bb9745ca8fc2d7f78463e896f8.tar.zst
task-time-tracker-31923fe0598464bb9745ca8fc2d7f78463e896f8.zip
Store app data on ~/.task_time_tracker/ folder.
Diffstat (limited to 'main.c')
-rw-r--r--main.c185
1 files changed, 105 insertions, 80 deletions
diff --git a/main.c b/main.c
index e0a2279..d239bef 100644
--- a/main.c
+++ b/main.c
@@ -24,8 +24,8 @@
#define LOG_FILE_NAME "log.txt"
#define APP_FOLDER_NAME ".task_time_tracker"
-#define DB_BIN_PATH_NAME APP_FOLDER_NAME "/database.bin"
-#define AR_CSV_PATH_NAME APP_FOLDER_NAME "/archive.csv"
+#define DB_FILE_NAME "database.bin"
+#define AR_FILE_NAME "archive.csv"
typedef struct {
int64_t times[NUM_WEEK_DAYS];
@@ -45,24 +45,30 @@ typedef struct {
#define DB_FILE_SIGN_STR "TTT:B:01"
const char DB_FILE_SIGN[] = DB_FILE_SIGN_STR;
const size_t DB_FILE_SIGN_LENGTH = sizeof(DB_FILE_SIGN_STR)-1;
-const size_t SIZEOF_TASK_T = sizeof(task_st);
-const size_t SIZEOF_DATABASE_T = sizeof(database_st);
+const size_t SIZEOF_TASK_ST = sizeof(task_st);
+const size_t SIZEOF_DATABASE_ST = sizeof(database_st);
const int64_t SECONDS_IN_MINUTE = (int64_t)60;
const int64_t SECONDS_IN_HOUR = (int64_t)60*SECONDS_IN_MINUTE;
const int64_t SECONDS_IN_DAY = (int64_t)24*SECONDS_IN_HOUR;
const int64_t SECONDS_IN_YEAR = (int64_t)365*SECONDS_IN_DAY;
-database_st database = { .tasks = NULL };
+database_st database = { .tasks = NULL };
database_st archive = { .tasks = NULL };
database_st *db = NULL;
+// char *app_folder = NULL;
+// char *db_file_path = NULL;
+// char *ar_file_path = NULL;
char *string_buffer = NULL;
int size_x, size_y, pos_x, pos_y;
+char *app_folder = NULL;
+char *db_file_path = NULL;
+char *ar_file_path = NULL;
// 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(const char *path) {
+ assert(path != NULL);
+ FILE *file = fopen(path, "r+");
bool is_file_accessible = file != NULL;
if (is_file_accessible) {
fclose(file);
@@ -234,7 +240,7 @@ bool create_task(database_st *db, task_st **task) {
current_capacity > PTRDIFF_MAX >> 1 ? PTRDIFF_MAX :
current_capacity << 1;
- task_st *new_tasks = realloc(db->tasks, new_capacity * SIZEOF_TASK_T);
+ task_st *new_tasks = realloc(db->tasks, new_capacity * SIZEOF_TASK_ST);
if (new_tasks == NULL) {
fprintf(stderr, "Failed to expand database.\n");
return false;
@@ -246,7 +252,7 @@ bool create_task(database_st *db, task_st **task) {
// Prepare new task.
*task = &db->tasks[db->count];
- memset(*task, 0, SIZEOF_TASK_T);
+ memset(*task, 0, SIZEOF_TASK_ST);
db->count++;
@@ -269,7 +275,7 @@ bool add_task(database_st *db, task_st *task) {
return false;
}
- memcpy(new_task, task, SIZEOF_TASK_T);
+ memcpy(new_task, task, SIZEOF_TASK_ST);
// Add task timer values to total timers.
for (int idx = 0; idx < NUM_WEEK_DAYS; idx++) {
@@ -295,7 +301,7 @@ bool delete_task(database_st *db, task_st *task) {
// Move tasks after the index position to their new positions.
ptrdiff_t index = task - db->tasks;
- memmove(task, task + 1, (db->count - index - 1) * SIZEOF_TASK_T);
+ memmove(task, task + 1, (db->count - index - 1) * SIZEOF_TASK_ST);
db->count--;
// Adjust selected task.
@@ -315,7 +321,7 @@ bool delete_task(database_st *db, task_st *task) {
size_t current_capacity = db->capacity;
if (db->count <= (current_capacity >> 2)) {
size_t new_capacity = current_capacity >> 1;
- task_st *new_tasks = realloc(db->tasks, new_capacity * SIZEOF_TASK_T);
+ task_st *new_tasks = realloc(db->tasks, new_capacity * SIZEOF_TASK_ST);
if (new_tasks == NULL && new_capacity > 0) {
fprintf(stderr, "Failed to shrink database.\n");
return false;
@@ -330,28 +336,28 @@ bool delete_task(database_st *db, task_st *task) {
// Resets database to the initial state and deallocates all memory taken by tasks.
void reset_database(database_st *db) {
free(db->tasks);
- memset(db, 0, SIZEOF_DATABASE_T);
+ memset(db, 0, SIZEOF_DATABASE_ST);
db->active_task = -1;
db->selected_task = -1;
}
// Stores data from database into binary file.
// Returns success.
-bool store_database(const database_st *db, const char *path_name) {
+bool store_database(const database_st *db, const char *path) {
assert(db != NULL);
- assert(path_name != NULL);
+ assert(path != NULL);
// Open file.
- FILE *file = fopen(path_name, "wb");
+ FILE *file = fopen(path, "wb");
if (file == NULL) {
- fprintf(stderr, "Failed to open file '%s' while storing database: %s.\n", path_name, strerror(errno));
+ fprintf(stderr, "Failed to open file '%s' while storing database: %s.\n", path, strerror(errno));
return false;
}
fwrite(DB_FILE_SIGN, sizeof(char), DB_FILE_SIGN_LENGTH, file);
- fwrite(db, SIZEOF_DATABASE_T, 1, file);
- fwrite(db->tasks, SIZEOF_TASK_T, db->count, file);
+ fwrite(db, SIZEOF_DATABASE_ST, 1, file);
+ fwrite(db->tasks, SIZEOF_TASK_ST, db->count, file);
fclose(file);
return true;
@@ -359,15 +365,15 @@ bool store_database(const database_st *db, const char *path_name) {
// Loads data from binary file into database.
// Returns success.
-bool load_database(database_st *db, const char *path_name) {
+bool load_database(database_st *db, const char *path) {
assert(db != NULL);
- assert(path_name != NULL);
+ assert(path != NULL);
// Open file.
- FILE *file = fopen(path_name, "rb");
+ FILE *file = fopen(path, "rb");
if (file == NULL) {
- fprintf(stderr, "Failed to open file '%s' while loading database: %s.\n", path_name, strerror(errno));
+ fprintf(stderr, "Failed to open file '%s' while loading database: %s.\n", path, strerror(errno));
return false;
}
@@ -380,13 +386,13 @@ bool load_database(database_st *db, const char *path_name) {
}
// Read database structure.
- fread(db, SIZEOF_DATABASE_T, 1, file);
+ fread(db, SIZEOF_DATABASE_ST, 1, file);
// Restore database capacity.
- db->tasks = calloc(db->capacity, SIZEOF_TASK_T);
+ db->tasks = calloc(db->capacity, SIZEOF_TASK_ST);
// Read database entries.
- fread(db->tasks, SIZEOF_TASK_T, db->count, file);
+ fread(db->tasks, SIZEOF_TASK_ST, db->count, file);
// Make sure we are reading all the file.
assert(fgetc(file) == EOF);
@@ -397,14 +403,14 @@ bool load_database(database_st *db, const char *path_name) {
// Exports data into CSV file.
// Returns success.
-bool export_to_csv(const database_st *db, const char *path_name) {
+bool export_to_csv(const database_st *db, const char *path) {
assert(db != NULL);
- assert(path_name != NULL);
+ assert(path != NULL);
- FILE *file = fopen(path_name, "w");
+ FILE *file = fopen(path, "w");
if (file == NULL) {
- fprintf(stderr, "Failed to open file '%s' while exporting to CSV: %s.\n", path_name, strerror(errno));
+ fprintf(stderr, "Failed to open file '%s' while exporting to CSV: %s.\n", path, strerror(errno));
return false;
}
@@ -442,13 +448,13 @@ bool export_to_csv(const database_st *db, const char *path_name) {
// Imports CSV file into database.
// Returns success.
-bool import_from_csv(database_st *db, const char *path_name) {
+bool import_from_csv(database_st *db, const char *path) {
assert(db != NULL);
- assert(path_name != NULL);
+ assert(path != NULL);
- FILE *file = fopen(path_name, "r");
+ FILE *file = fopen(path, "r");
if (file == NULL) {
- fprintf(stderr, "Failed to open file '%s' while importing from CSV: %s.\n", path_name, strerror(errno));
+ fprintf(stderr, "Failed to open file '%s' while importing from CSV: %s.\n", path, strerror(errno));
return false;
}
@@ -508,13 +514,13 @@ bool import_from_csv(database_st *db, const char *path_name) {
return true;
}
-bool append_to_csv(task_st *task, const char *path_name) {
+bool append_to_csv(task_st *task, const char *path) {
assert(task != NULL);
- assert(path_name != NULL);
+ assert(path != NULL);
- FILE *file = fopen(path_name, "a+");
+ FILE *file = fopen(path, "a+");
if (file == NULL) {
- fprintf(stderr, "Failed to open file '%s' while appending to CSV: %s.\n", path_name, strerror(errno));
+ fprintf(stderr, "Failed to open file '%s' while appending to CSV: %s.\n", path, strerror(errno));
return false;
}
@@ -627,15 +633,15 @@ void update_total_timers(database_st *db) {
typedef struct {
- char *header;
- int width;
- char alignment;
- int alignment_offset;
+ char *header;
+ int width;
+ char alignment;
+ int alignment_offset;
} column_st;
typedef struct {
- column_st columns[NUM_COLUMNS];
- char *archive_title;
+ column_st columns[NUM_COLUMNS];
+ char *archive_title;
} layout_st;
layout_st layouts[2];
@@ -899,39 +905,58 @@ void draw_tui(database_st *db, layout_st *layout) {
mvaddstr(y, x, string_buffer);
}
-char *app_folder = NULL;
-
void free_memory() {
reset_database(&database);
reset_database(&archive);
- free(string_buffer);
- string_buffer = NULL;
-
- free(app_folder);
- app_folder = NULL;
+ free(string_buffer); string_buffer = NULL;
+ free(app_folder); app_folder = NULL;
+ free(db_file_path); db_file_path = NULL;
+ free(ar_file_path); ar_file_path = NULL;
}
-bool initialize_app_folder(const char *path) {
- size_t path_length = strlen(path);
- size_t app_folder_name_length = strlen(APP_FOLDER_NAME);
- app_folder = malloc(path_length + app_folder_name_length + 2 + 1); // Add 2 for the '/'s and 1 for the NUL.
- memcpy(app_folder, path, path_length);
- app_folder[path_length] = '/';
- memcpy(app_folder + path_length + 1, APP_FOLDER_NAME, app_folder_name_length);
- app_folder[path_length + 1 + app_folder_name_length] = '/';
-
- mkdir(app_folder, 0740);
- if (errno != 0 && errno != EEXIST) {
- fprintf(stderr, "Failed to create app folder '%s': %s.\n", app_folder, strerror(errno));
- return false;
+bool initialize_app_folder() {
+ char* home_path = getenv("HOME");
+
+#if defined(_WIN64)
+ home_path = getenv("USERPROFILE");
+#endif
+
+ if (home_path != NULL)
+ {
+ app_folder = malloc(strlen(home_path) + 1 + strlen(APP_FOLDER_NAME) + 1); // Add space for folder separator and NUL.
+ // TODO Check malloc result.
+ sprintf(app_folder, "%s/%s", home_path, APP_FOLDER_NAME);
+
+ // Create app folder.
+ mkdir(app_folder, 0740);
+ if (errno != 0 && errno != EEXIST) {
+ fprintf(stderr, "Failed to create app folder '%s': %s.\n", app_folder, strerror(errno));
+ return false;
+ }
}
+ else {
+ app_folder = malloc(3);
+ // TODO Check malloc result.
+ sprintf(app_folder, "./");
+ }
+
+ // Set database file path.
+ db_file_path = malloc(strlen(app_folder) + 1 + strlen(DB_FILE_NAME) + 1); // Add space for folder separator and NUL.
+ // TODO Check malloc result.
+ sprintf(db_file_path, "%s/%s", app_folder, DB_FILE_NAME);
+
+ // Set archive file path.
+ ar_file_path = malloc(strlen(app_folder) + 1 + strlen(AR_FILE_NAME) + 1); // Add space for folder separator and NUL.
+ // TODO Check malloc result.
+ sprintf(ar_file_path, "%s/%s", app_folder, AR_FILE_NAME);
+
return true;
}
int main(int argc, char *argv[]) {
- if (initialize_app_folder(getenv("HOME")) == false) {
+ if (initialize_app_folder() == false) {
return EXIT_FAILURE;
}
@@ -939,12 +964,12 @@ int main(int argc, char *argv[]) {
reset_database(&database);
reset_database(&archive);
- if (is_file_accessible(DB_BIN_PATH_NAME) == false) {
- store_database(&database, DB_BIN_PATH_NAME);
+ if (is_file_accessible(db_file_path) == false) {
+ store_database(&database, db_file_path);
}
- if (is_file_accessible(AR_CSV_PATH_NAME) == false) {
- export_to_csv(&archive, AR_CSV_PATH_NAME);
+ if (is_file_accessible(ar_file_path) == false) {
+ export_to_csv(&archive, ar_file_path);
}
if (argc > 1) {
@@ -974,9 +999,9 @@ int main(int argc, char *argv[]) {
if (argc < idx+1) {
fprintf(stdout, "Missing CSV file path to import.\n");
}
- load_database(&database, DB_BIN_PATH_NAME);
+ load_database(&database, db_file_path);
import_from_csv(&database, argv[idx+1]);
- store_database(&database, DB_BIN_PATH_NAME);
+ store_database(&database, db_file_path);
free_memory();
return EXIT_SUCCESS;
}
@@ -987,7 +1012,7 @@ int main(int argc, char *argv[]) {
if (argc < idx+1) {
fprintf(stdout, "Missing CSV file path to export.\n");
}
- load_database(&database, DB_BIN_PATH_NAME);
+ load_database(&database, db_file_path);
export_to_csv(&database, argv[idx+1]);
free_memory();
return EXIT_SUCCESS;
@@ -1000,7 +1025,7 @@ int main(int argc, char *argv[]) {
initialize_tui();
- load_database(&database, DB_BIN_PATH_NAME);
+ load_database(&database, db_file_path);
ungetch(KEY_RESIZE);
for (int key; (key = getch()) != 'q'; ) {
@@ -1101,18 +1126,18 @@ int main(int argc, char *argv[]) {
db->active_task = next_task - db->tasks;
}
db->modified_on = time(NULL);
- store_database(db, DB_BIN_PATH_NAME);
+ store_database(db, db_file_path);
break;
}
case KEY_BACKSPACE:
if (db == &database) {
reset_database(&archive); // TODO Not needed because we never leave things hanging.
- import_from_csv(&archive, AR_CSV_PATH_NAME);
+ import_from_csv(&archive, ar_file_path);
db = &archive;
}
else {
- export_to_csv(&archive, AR_CSV_PATH_NAME);
+ export_to_csv(&archive, ar_file_path);
reset_database(&archive);
db = &database;
}
@@ -1123,7 +1148,7 @@ int main(int argc, char *argv[]) {
if (db != &database || selected_task == NULL || selected_task == active_task) {
break;
}
- append_to_csv(selected_task, AR_CSV_PATH_NAME);
+ append_to_csv(selected_task, ar_file_path);
delete_task(db, selected_task);
// TODO Maybe save stuff? Shoulw we?
break;
@@ -1195,9 +1220,9 @@ int main(int argc, char *argv[]) {
}
update_timers(&database);
- store_database(&database, DB_BIN_PATH_NAME);
+ store_database(&database, db_file_path);
if (db == &archive) {
- export_to_csv(&archive, AR_CSV_PATH_NAME);
+ export_to_csv(&archive, ar_file_path);
}
free_memory();
endwin();