diff options
| author | dam <dam@gudinoff> | 2022-09-03 16:53:43 +0000 |
|---|---|---|
| committer | dam <dam@gudinoff> | 2022-09-03 16:53:43 +0000 |
| commit | cd2247bf832a1f210192afa3dc68cd226ae3aa02 (patch) | |
| tree | c89ceac11b5c1f916049e85546173d2124b2ffff | |
| parent | d8920087a81ef9490037028863d998e9b53989d4 (diff) | |
| download | task-time-tracker-cd2247bf832a1f210192afa3dc68cd226ae3aa02.tar.zst task-time-tracker-cd2247bf832a1f210192afa3dc68cd226ae3aa02.zip | |
Keep track of time for active task.
| -rw-r--r-- | main.c | 213 |
1 files changed, 139 insertions, 74 deletions
@@ -27,12 +27,12 @@ #define DB_MAX_CAP ((PTRDIFF_MAX >> 1) + 1) typedef struct /*__attribute__((__packed__))*/ { - uint32_t time[7]; + uint32_t times[7]; char name[MAX_TASK_NAME]; } task_t; typedef struct /*__attribute__((__packed__))*/ { - uint64_t modified_on; + time_t modified_on; size_t count; size_t capacity; task_t *tasks; @@ -83,13 +83,13 @@ char *replace_char(char *string, char find, char replace) { void print_task(const task_t *task) { printf("name: '%s'\n", task->name); - printf("t[0]: '%" PRIu32 "'\n", task->time[0]); - printf("t[1]: '%" PRIu32 "'\n", task->time[1]); - printf("t[2]: '%" PRIu32 "'\n", task->time[2]); - printf("t[3]: '%" PRIu32 "'\n", task->time[3]); - printf("t[4]: '%" PRIu32 "'\n", task->time[4]); - printf("t[5]: '%" PRIu32 "'\n", task->time[5]); - printf("t[6]: '%" PRIu32 "'\n", task->time[6]); + printf("t[0]: '%" PRIu32 "'\n", task->times[0]); + printf("t[1]: '%" PRIu32 "'\n", task->times[1]); + printf("t[2]: '%" PRIu32 "'\n", task->times[2]); + printf("t[3]: '%" PRIu32 "'\n", task->times[3]); + printf("t[4]: '%" PRIu32 "'\n", task->times[4]); + printf("t[5]: '%" PRIu32 "'\n", task->times[5]); + printf("t[6]: '%" PRIu32 "'\n", task->times[6]); } // Macro used to calculate index of task on a database. @@ -272,13 +272,13 @@ bool export_to_csv(const database_t *db, const char *path_name) { replace_char(name, ',', ' '); fprintf(file, "%s,%" PRIu32 ",%" PRIu32 ",%" PRIu32 ",%" PRIu32 ",%" PRIu32 ",%" PRIu32 ",%" PRIu32 "\n", name, - task->time[0], - task->time[1], - task->time[2], - task->time[3], - task->time[4], - task->time[5], - task->time[6] + task->times[0], + task->times[1], + task->times[2], + task->times[3], + task->times[4], + task->times[5], + task->times[6] ); } @@ -335,13 +335,13 @@ bool import_from_csv(database_t *db, const char *path_name) { // Parse task times. if(sscanf(name_delimiter+1, "%" SCNu32 ",%" SCNu32 ",%" SCNu32 ",%" SCNu32 ",%" SCNu32 ",%" SCNu32 ",%" SCNu32, - &task->time[0], - &task->time[1], - &task->time[2], - &task->time[3], - &task->time[4], - &task->time[5], - &task->time[6] + &task->times[0], + &task->times[1], + &task->times[2], + &task->times[3], + &task->times[4], + &task->times[5], + &task->times[6] ) != 7) { replace_char(line_buffer, '\n', ' '); fprintf(stderr, "Discarding invalid line '%s' and continuing.\n", line_buffer); @@ -362,8 +362,8 @@ bool import_from_csv(database_t *db, const char *path_name) { enum TEST { T_NONE = 0x00, - T_UTC = 0x01, - T_DAY = 0x02, + T_TIME = 0x01, + T_XXXX = 0x02, T_SBIN = 0x04, T_LBIN = 0x08, T_ECSV = 0x10, @@ -377,21 +377,12 @@ void prototype(int level) { const char *done = "# -- done -- -- -- /\n"; /////////////////////////////////////////////////////////////////////////// - // Get current UTC time. - if (level & T_UTC) { - fprintf(stderr, "# current UTC time --------------------------- \\\n"); - time_t x = time(NULL); - printf("%s", ctime(&x)); - fprintf(stderr, done); - } - - /////////////////////////////////////////////////////////////////////////// - // Get current day of the week. - if (level & T_DAY) { - fprintf(stderr, "# current day of the week --------------------- \\\n"); - time_t now_ut = time(NULL); - uint8_t week_day = localtime(&now_ut)->tm_wday; - fprintf(stderr, "%d\n", week_day); + // Get current time and day of week (UTC). + if (level & T_TIME) { + fprintf(stderr, "# UTC time and day of week -------------------- \\\n"); + time_t now_utc = time(NULL); // Get current UTC time. + uint8_t week_day = localtime(&now_utc)->tm_wday; // Get current day of the week. + fprintf(stderr, "day of week: %d\ntime: %s", week_day, ctime(&now_utc)); fprintf(stderr, done); } @@ -401,15 +392,15 @@ void prototype(int level) { task_t tmp[] = { { .name = "ALPHA-TASK", - .time = { 0, 0, 0, 0, 0, 0, 0 }, + .times = { 0, 0, 0, 0, 0, 0, 0 }, }, { .name = "BETA-TASK", - .time = { 1, 1, 1, 1, 1, 1, 1 }, + .times = { 1, 1, 1, 1, 1, 1, 1 }, }, { .name = "DELTA-TASK", - .time = { 2, 2, 2, 2, 2, 2, 2 }, + .times = { 2, 2, 2, 2, 2, 2, 2 }, } }; @@ -485,11 +476,57 @@ void prototype(int level) { size = sizeof(task_t); fprintf(stderr, "sizeof(%s) = %zu bytes (%zu bits : %6.3f W64b)\n", name, size, size*8, ((double)size)*8.0/64.0); + name = "time_t"; + size = sizeof(time_t); + fprintf(stderr, "sizeof(%s) = %zu bytes (%zu bits : %6.3f W64b)\n", name, size, size*8, ((double)size)*8.0/64.0); + + fprintf(stderr, done); } } + + +void update_timers(database_t *db) { + + // Get current UTC time. + time_t stop_time = time(NULL); + + // Get last modified on UTC time. + time_t start_time = db->modified_on; + +// time_t diff = (double)stop_time - start_time; +// fprintf(stderr, "> diff: %zu seconds | %6.2f minutes | %6.2f hours\n", (time_t)diff, diff / 60.0, diff / (60.0*60.0)); + + if (db->active_task < 0) { + return; + } + + task_t *active_task = db->tasks + db->active_task; + uint8_t start_week_day; + while (start_time < stop_time) { + + start_week_day = localtime(&start_time)->tm_wday; + + // Get next week of day. + time_t next_day = (start_time / 86400) * 86400 + 86400; + time_t next_start = next_day < stop_time ? next_day : stop_time; + + active_task->times[start_week_day] += next_start - start_time; + + +// fprintf(stderr, "Added '%zu' on %s\n", next_start - start_time, DAYS_OF_WEEK[start_week_day]); + + start_time = next_start; + } + + db->modified_on = stop_time; +// fprintf(stderr, "> done\n"); +} + + + char *line_buffer; int size_x, size_y, pos_x, pos_y; uint8_t selected_layout = 0; @@ -515,14 +552,14 @@ void initialize_layouts() { layout->table_size = 8; layout->table_headers_size = TABLE_HEADERS_SIZE; // TODO Headers must be dynamic according to FIRST_DAY_OF_WEEK - layout->table_headers[0] = " Task "; - layout->table_headers[1] = " Mon "; - layout->table_headers[2] = " Tue "; - layout->table_headers[3] = " Wed "; - layout->table_headers[4] = " Thu "; - layout->table_headers[5] = " Fri "; - layout->table_headers[6] = " Sat "; - layout->table_headers[7] = " Sun "; + layout->table_headers[0] = " Task Time Tracker v1 "; + layout->table_headers[1] = " Sun "; + layout->table_headers[2] = " Mon "; + layout->table_headers[3] = " Tue "; + layout->table_headers[4] = " Wed "; + layout->table_headers[5] = " Thu "; + layout->table_headers[6] = " Fri "; + layout->table_headers[7] = " Sat "; layout->table_headers[8] = " Total "; // layout->table_headers = { " Task ", " Mon ", " Tue ", " Wed ", " Thu ", " Fri ", " Sat ", " Sun ", " Total " }; @@ -531,13 +568,13 @@ void initialize_layouts() { layout->table_size = 6; layout->table_headers_size = TABLE_HEADERS_SIZE; // TODO Headers must be dynamic according to FIRST_DAY_OF_WEEK - layout->table_headers[0] = " Task "; - layout->table_headers[1] = " M "; - layout->table_headers[2] = " T "; - layout->table_headers[3] = " W "; - layout->table_headers[4] = " T "; - layout->table_headers[5] = " F "; - layout->table_headers[6] = " S "; + layout->table_headers[0] = " TTT "; + layout->table_headers[1] = " S "; + layout->table_headers[2] = " M "; + layout->table_headers[3] = " T "; + layout->table_headers[4] = " W "; + layout->table_headers[5] = " T "; + layout->table_headers[6] = " F "; layout->table_headers[7] = " S "; layout->table_headers[8] = " # "; // layout->table_headers = { " T ", " M ", " T ", " W ", " T ", " F ", " S ", " S ", " # " }; @@ -584,10 +621,30 @@ void draw_header() { start_columns+(table_size*7), }; + time_t now = time(NULL); + uint8_t today = localtime(&now)->tm_wday + 1; + + start_color(); + init_pair(1, COLOR_BLUE, COLOR_BLACK); + init_pair(2, COLOR_BLACK, COLOR_CYAN); + init_pair(3, COLOR_WHITE, COLOR_BLUE); + int color_pair = 1; + + + mvaddstr(0, columns[0]+2, table_headers[0]); - for (int idx = 1; idx < 9; idx++) { + for (int idx = 1; idx < 9; idx++) { // TODO When does the week start? mvaddch(0, columns[idx], ACS_TTEE); + + if (idx == today) { + attron(COLOR_PAIR(color_pair)); + } + mvaddstr(0, columns[idx]+2, table_headers[idx]); + + if (idx == today) { + attroff(COLOR_PAIR(color_pair)); + } } } @@ -646,10 +703,9 @@ void draw_table() { if (task == active_task && task == selected_task) { color_pair = 3; } - if (color_pair > 0) { - attron(COLOR_PAIR(color_pair)); + if (color_pair == 1 || color_pair == 3) { + attron(A_BOLD); } - attron(COLOR_PAIR(color_pair)); // Clear line_buffer and add string termination. @@ -662,7 +718,7 @@ void draw_table() { size_t copy_length = task_name_length < max_column_length ? task_name_length : max_column_length; memcpy(line_buffer+2, task->name, copy_length); - uint32_t *time = task->time; + uint32_t *time = task->times; sprintf(line_buffer + columns[1], "%8d", time[0]); sprintf(line_buffer + columns[2], "%8d", time[1]); sprintf(line_buffer + columns[3], "%8d", time[2]); @@ -678,14 +734,13 @@ void draw_table() { totals[idx] += time[idx]; } totals[DAYS_ON_WEEK] += total; - sprintf(line_buffer + columns[8], "%10" PRIu64, total); + sprintf(line_buffer + columns[8], "%10" PRIu64, total); // BUG This causes "corrupted size vs. prev_size because it is writing beyond line_buffer size. addstr(line_buffer); // Disable highlight color on selected entry. - if (color_pair > 0) { - attroff(COLOR_PAIR(color_pair)); - } + attroff(COLOR_PAIR(color_pair)); + attroff(A_BOLD); // Print columns separators. pos_y = getcury(stdscr); @@ -750,7 +805,6 @@ void draw_footer() { addch(ACS_LRCORNER); - // TODO This code is now repeated accross the header, table and footer. Clean this up. layout_t *layout = &layouts[selected_layout]; int table_size = layout->table_size; @@ -782,7 +836,7 @@ int main(int argc, char *argv[]) { // Make sure architecture uses 8bits per char. assert(CHAR_BIT == 8); - + // TODO Parse commands using: https://stackoverflow.com/questions/9642732/parsing-command-line-arguments-in-c if (argc > 1) { @@ -806,6 +860,13 @@ int main(int argc, char *argv[]) { return EXIT_SUCCESS; } + action = "--t_time"; + do_action = strncmp(argv[idx], action, strlen(action)) == 0; + if (do_action) { + prototype(T_TIME); + return EXIT_SUCCESS; + } + action = "--t_sos"; do_action = strncmp(argv[idx], action, strlen(action)) == 0; if (do_action) { @@ -869,6 +930,7 @@ int main(int argc, char *argv[]) { cbreak(); // Line buffering disabled, Pass on everty thing to me. keypad(stdscr, TRUE); // I need that nifty F1 curs_set(0); // Set cursor invisible. + timeout(1000); // Make getch() timeout after timeout(...) miliseconds. height = 3; width = 10; @@ -878,13 +940,18 @@ int main(int argc, char *argv[]) { refresh(); my_win = create_newwin(height, width, starty, startx); + ch = KEY_RESIZE; do { task_t *active_task = database.tasks + database.active_task; task_t *selected_task = database.tasks + database.selected_task; + update_timers(&database); switch(ch) { + case ERR: // When getch() times out. + break; + case KEY_F(1): { task_t *new_task; @@ -950,7 +1017,7 @@ int main(int argc, char *argv[]) { task_t *next_task = selected_task; if (active_task > 0) { - // TODO Add remaining time to task. + update_timers(&database); // TODO Should I keep this even though it always does? database.active_task = -1; } if (active_task != next_task) { @@ -963,11 +1030,8 @@ int main(int argc, char *argv[]) { case KEY_RESIZE: erase(); - if (line_buffer != NULL) { - free(line_buffer); - } getmaxyx(stdscr, size_y, size_x); - line_buffer = malloc(size_x * sizeof(char)); + line_buffer = realloc(line_buffer, size_x * sizeof(char)); break; case KEY_LEFT: @@ -1011,6 +1075,7 @@ int main(int argc, char *argv[]) { } while((ch = getch()) != 'q'); + update_timers(&database); store_database(&database, DB_BIN_PATH_NAME); free_memory(); endwin(); |
