aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordam <dam@gudinoff>2022-10-27 00:34:28 +0000
committerdam <dam@gudinoff>2022-10-27 00:34:28 +0000
commiteb5a3b3535057a62728460cce562aa64312e0519 (patch)
tree29271ecf356f12d57b55d35cfa0d645d6c235bb5
parentf62a1e1b2c9358997da9f12edffaf2120f56f3ed (diff)
downloadtask-time-tracker-eb5a3b3535057a62728460cce562aa64312e0519.tar.zst
task-time-tracker-eb5a3b3535057a62728460cce562aa64312e0519.zip
Prototype code for store_database_partial.
-rw-r--r--main.c64
-rw-r--r--readme.md21
2 files changed, 65 insertions, 20 deletions
diff --git a/main.c b/main.c
index 0c0e767..daac495 100644
--- a/main.c
+++ b/main.c
@@ -82,6 +82,10 @@ char *string_buffer = NULL;
size_t string_buffer_size = 0;
int size_x, size_y, pos_x, pos_y;
+void inline static clear_string_buffer() {
+ memset(string_buffer, 0, string_buffer_size);
+}
+
// Checks if file is exists and is accessible.
// Returns true when the file exists and is accessible.
@@ -527,6 +531,33 @@ bool store_database(const database_st *db, const char *path) {
return true;
}
+// Writes only the database core structure and the provided task if not null.
+// Returns success.
+bool store_database_partial(const database_st *db, const task_st *task, const char *path) {
+ assert(db != NULL);
+ assert(path != NULL);
+
+ // Open file.
+ FILE *file = fopen(path, "r+b");
+ if (file == NULL) {
+ fprintf(stderr, "Failed to open file '%s' while partially storing database: %s.\n", path, strerror(errno));
+ return false;
+ }
+
+ fseek(file, DB_FILE_SIGN_LENGTH, SEEK_SET);
+ fwrite(db, SIZEOF_DATABASE_ST, 1, file);
+
+ if (task != NULL) {
+ assert(task >= db->tasks && task < &db->tasks[db->count]);
+ ptrdiff_t offset = task - db->tasks;
+ fseek(file, offset * SIZEOF_TASK_ST, SEEK_CUR);
+ fwrite(task, SIZEOF_TASK_ST, 1, file);
+ }
+
+ fclose(file);
+ return true;
+}
+
// Loads data from binary file into database.
// Returns success.
bool load_database(database_st *db, const char *path) {
@@ -751,7 +782,7 @@ typedef struct {
layout_st layouts[NUM_LAYOUTS];
int layout_tasks_rows;
-bool is_valid_window = false;
+bool is_terminal_too_small = true;
void initialize_tui() {
@@ -1151,7 +1182,7 @@ int main(int argc, char *argv[]) {
static layout_st *layout = &layouts[L_COMPACT];
task_st *active_task = get_active_task(db);
task_st *selected_task = get_selected_task(db);
- int selected_task_row = is_valid_window ? (db->selected_task % layout_tasks_rows) + NUM_HEADER_ROWS : 0;
+ int selected_task_row = is_terminal_too_small ? 0 : (db->selected_task % layout_tasks_rows) + NUM_HEADER_ROWS;
int selected_task_theme = selected_task == active_task ? THEME_E : THEME_D;
timeout(INPUT_AWAIT_INF);
@@ -1168,7 +1199,7 @@ int main(int argc, char *argv[]) {
case KEY_RESIZE: {
clear();
getmaxyx(stdscr, size_y, size_x);
- is_valid_window = size_x >= 60 && size_y >= 3;
+ is_terminal_too_small = size_x < 60 || size_y < 3;
size_t new_size = 2047 | MAX_TASK_NAME | (size_x + 1);
if (string_buffer_size < new_size) {
string_buffer_size = new_size;
@@ -1193,10 +1224,13 @@ int main(int argc, char *argv[]) {
struct tm *now_local = localtime(&now_utc);
strftime(new_task->name, MAX_TASK_NAME, "%Y-%m-%d %H:%M:%S", now_local);
- // Select new task.
+ // Select new task. TODO Maybe do this on the database?
selected_task = new_task;
db->selected_task = selected_task - db->tasks;
-
+
+ // TODO
+ store_database_partial(db, selected_task, db_file_path);
+
// Force rename action.
flushinp();
ungetch(KEY_F(2));
@@ -1216,6 +1250,8 @@ int main(int argc, char *argv[]) {
// Get new task name.
echo();
curs_set(1);
+ clear_string_buffer();
+// memset(string_buffer, 0, string_buffer_size); TODO
mvgetnstr(selected_task_row, 1, string_buffer, MAX_TASK_NAME-1);
noecho();
curs_set(0);
@@ -1233,7 +1269,7 @@ int main(int argc, char *argv[]) {
break;
}
- case '0': {
+ case KEY_BACKSPACE: {
if (selected_task == NULL) {
break;
}
@@ -1361,6 +1397,7 @@ int main(int argc, char *argv[]) {
// Adust time.
set_task_time(db, selected_task, day, time);
+ store_database_partial(db, selected_task, db_file_path);
break;
}
@@ -1592,20 +1629,25 @@ int main(int argc, char *argv[]) {
}
}
- if (is_valid_window) {
- draw_tui(db, layout);
- }
- else {
- const char *INVALID_WINDOW_MESSAGE = "Please expand window.";
+ if (is_terminal_too_small) {
+ const char *INVALID_WINDOW_MESSAGE = "Terminal is too small: minimum 60x3.";
const int INVALID_WINDOW_MESSAGE_LENGTH = strlen(INVALID_WINDOW_MESSAGE);
mvaddstr(size_y / 2, (size_x - INVALID_WINDOW_MESSAGE_LENGTH) / 2, INVALID_WINDOW_MESSAGE);
}
+ else {
+ draw_tui(db, layout);
+ }
timeout(INPUT_TIMEOUT_MS);
}
update_times(&database);
store_database(&database, db_file_path);
+// task_st *active_task = get_active_task(&database);
+// if (active_task != NULL) {
+// update_times(&database);
+// store_database_partial(&database, active_task, db_file_path);
+// }
if (db == &archive) {
export_to_csv(&archive, ar_file_path);
}
diff --git a/readme.md b/readme.md
index 4fef661..770fe3e 100644
--- a/readme.md
+++ b/readme.md
@@ -5,6 +5,7 @@ Task Time Tracker
- [ncurses colors](https://tldp.org/HOWTO/NCURSES-Programming-HOWTO/color.html#COLORBASICS)
- [pprintf](https://cplusplus.com/reference/cstdio/printf/)
- [intmax_t](https://wiki.sei.cmu.edu/confluence/plugins/servlet/mobile?contentId=87152366#content/view/87152366)
+- [hexed.it](https://hexed.it/)
# to-do list
- [x] Include check on number of char bits;
@@ -51,18 +52,20 @@ Task Time Tracker
- [x] Add/remove time using keys: `F3`;
- [x] Add/remove time for any day of week;
- [x] Total times may saturate, but before that the user will see the infinite symbol. Solution: Provide user with possibility to refresh totals.
-- [ ] Improve the way we save the changes made to the database:
+- [x] Decide on a INVALID_WINDOW_MESSAGE.
+- [x] Use backspace to clear all timers for current task.
+- [ ] Save more often using the `store_database_partial` and only save all when quitting:
- When operating on the archive, will we keep the saves synchronous?
- Maybe add a cooldown timer and save changes after it times out?
- Maybe add a partial-save when (de)activating a task (just save the task and the database core?
- - partial_store_task(db, task)
- - partial_store_database(db)
- - on (de)activate_task : partial_store_database partial_store_database
- - on rename, changetimes : partial_store_task
- - on new_task : partial_store_database partial_store_task
- - on refresh : partial_store_database
- - on exit if active : partial_store_database partial_store_task
- - on move, delete, archive: FULL store_database
+ - on (de)activate_task : partial w/task
+ - on rename, changetimes : partial w/task
+ - on new_task : partial w/task
+ - on refresh : partial
+ - on exit : full
+ - on move, delete, archive: full
+- [ ] Check if string_buffer needs to be cleared. We may be leaking info on the string_buffer.
+- [ ] Maybe replace all `sprintf` by `snprintf`;
- [ ] REVISE ALL CODE ptrdiff_t/size_t (signed/unsigned)!
- [ ] Go over all `TODO` items;
- [ ] Cleanup `draw_tui`: