diff options
| -rw-r--r-- | main.c | 113 | ||||
| -rw-r--r-- | readme.md | 17 |
2 files changed, 63 insertions, 67 deletions
@@ -107,9 +107,16 @@ bool is_file_accessible(const char *path) { return is_file_accessible; } +// Returns true if string to_compare is equal to any of the other passed strings, false otherwise. +bool inline static is_equal_to_any(const char *to_compare, const char *test_a, const char *test_b) { + return strncmp(to_compare, test_a, strlen(test_a)+1) == 0 + || strncmp(to_compare, test_b, strlen(test_b)+1) == 0; +} + // 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. // The terminating null byte ('\0') is included in length. +// TODO null byte should not be part of the length. // Returns the amount of items discarded. size_t truncate_string_utf8(char *string, size_t length) { @@ -120,7 +127,7 @@ size_t truncate_string_utf8(char *string, size_t length) { // Search for a non-UTF8-sequence-item so we can truncate the string. size_t idx = length - 1; - while(idx > 0 && ((string[idx] & 0xC0) == 0x80)) { + while(idx > 0 && ((string[idx] & 0xC0) == 0x80)) { // TODO Only needs to back up 3 items... because of UTF8 being limited to 4bytes idx--; } string[idx] = '\0'; @@ -156,61 +163,50 @@ char *replace_char(char *string, char find, char replace) { return string; } -// Prints time into string using 5 characters centered according to length. -// The string should have capacity for at least length number of items. -// The terminating null byte ('\0') is included in length. -// TODO Should the null byte be included int he length or not? -char *sprint_time_5cc(char *string, intmax_t time, int length) { - assert(length >= 6); - - int left_padding = (length - 6) / 2; - int right_padding = length - 6 - left_padding; - - if (time >= (intmax_t)(9999.5 * SECONDS_IN_YEAR)) { - snprintf(string, length, "%*s ∞ %*s", - left_padding, "", - right_padding, ""); +// Prints time into string using 5 characters centered on space. +// The string buffer should be able to store space UTF8 characters plus '\0'. +char *sprint_time5_utf8(char *string, intmax_t time, int space) { + const int TIME_CHARS = 5; + assert(space >= TIME_CHARS); + + int buffer_space = space * 4 + 1; // Each that UTF8 char can have 4 bytes. + int left_padding = (space - TIME_CHARS) / 2; + int right_padding = space - TIME_CHARS - left_padding; + + if (time < 0) { + snprintf(string, buffer_space, "%*s - %*s", left_padding, "", right_padding, ""); } - else if (time >= (intmax_t)(9999.5 * SECONDS_IN_DAY)) { - double value = (double)time / (double)SECONDS_IN_YEAR; - int decimals = - time >= 99.95 * SECONDS_IN_YEAR ? 0 : - time >= 9.995 * SECONDS_IN_YEAR ? 1 : - 2; - - snprintf(string, length, "%*s%4.*fy%*s", - left_padding, "", - decimals, - value, - right_padding, ""); + else if (time == 0) { + snprintf(string, buffer_space, "%*s 0 %*s", left_padding, "", right_padding, ""); + } + else if (time < SECONDS_IN_MINUTE) { + snprintf(string, buffer_space, "%*s%3jds %*s", left_padding, "", time, right_padding, ""); + } + else if (time < (intmax_t)100 * SECONDS_IN_HOUR) { + intmax_t hours = (double)time / (double)SECONDS_IN_HOUR; + intmax_t minutes = (time - (hours * SECONDS_IN_HOUR) ) / SECONDS_IN_MINUTE; + snprintf(string, buffer_space, "%*s%02jd:%02jd%*s", left_padding, "", hours, minutes, right_padding, ""); } - else if (time >= (intmax_t)100 * SECONDS_IN_HOUR) { + else if (time < (intmax_t)(9999.5 * SECONDS_IN_DAY)) { double value = (double)time / (double)SECONDS_IN_DAY; int decimals = time >= 99.95 * SECONDS_IN_DAY ? 0 : time >= 9.995 * SECONDS_IN_DAY ? 1 : 2; - - snprintf(string, length, "%*s%4.*fd%*s", - left_padding, "", - decimals, - value, - right_padding, ""); - } - else if (time >= SECONDS_IN_MINUTE) { - intmax_t hours = (double)time / (double)SECONDS_IN_HOUR; - intmax_t minutes = (time - (hours * SECONDS_IN_HOUR) ) / SECONDS_IN_MINUTE; - snprintf(string, length, "%*s%02jd:%02jd%*s", left_padding, "", hours, minutes, right_padding, ""); + snprintf(string, buffer_space, "%*s%4.*fd%*s", left_padding, "", decimals, value, right_padding, ""); } - else if (time > 0) { - snprintf(string, length, "%*s%3jds %*s", left_padding, "", time, right_padding, ""); - } - else if (time == 0) { - snprintf(string, length, "%*s 0 %*s", left_padding, "", right_padding, ""); + else if (time < (intmax_t)(9999.5 * SECONDS_IN_YEAR)) { + double value = (double)time / (double)SECONDS_IN_YEAR; + int decimals = + time >= 99.95 * SECONDS_IN_YEAR ? 0 : + time >= 9.995 * SECONDS_IN_YEAR ? 1 : + 2; + snprintf(string, buffer_space, "%*s%4.*fy%*s", left_padding, "", decimals, value, right_padding, ""); } else { - snprintf(string, length, "%*s - %*s", left_padding, "", right_padding, ""); + snprintf(string, buffer_space, "%*s ∞ %*s", left_padding, "", right_padding, ""); } + return string; } @@ -989,14 +985,14 @@ void draw_tui(database_st *db, layout_st *layout) { column_width = layout->columns[L_DAYS_IDX + day_idx].width; int64_t task_stime = task->times[day_idx]; total_time = add_int64(total_time, task_stime); - sprint_time_5cc(string_buffer, task_stime, column_width + 1); + sprint_time5_utf8(string_buffer, task_stime, column_width); mvaddstr(y, x, string_buffer); x += column_width; } // Task total. x++; - sprint_time_5cc(string_buffer, total_time, layout->columns[L_TOTAL_IDX].width + 1); + sprint_time5_utf8(string_buffer, total_time, layout->columns[L_TOTAL_IDX].width); mvaddstr(y, x, string_buffer); // Reset theme. @@ -1024,7 +1020,7 @@ void draw_tui(database_st *db, layout_st *layout) { column_width = layout->columns[L_DAYS_IDX + idx].width; total_time = add_int64(total_time, daily_total); - sprint_time_5cc(string_buffer, daily_total, column_width + 1); + sprint_time5_utf8(string_buffer, daily_total, column_width); // Apply theme. if (idx == now_week_day && active_task != NULL) { @@ -1041,7 +1037,7 @@ void draw_tui(database_st *db, layout_st *layout) { attrset(A_NORMAL); } x++; - sprint_time_5cc(string_buffer, total_time, layout->columns[L_TOTAL_IDX].width + 1); + sprint_time5_utf8(string_buffer, total_time, layout->columns[L_TOTAL_IDX].width); mvaddstr(y, x, string_buffer); } @@ -1116,15 +1112,6 @@ void exit_gracefully(int signal) { ungetch('q'); } -// Returns true if any of the action parameters is equal to arg, false otherwise. -bool is_action_detected(const char *arg, const char *action_name, const char *action_abbreviation) { - assert(arg != NULL); - assert(action_name != NULL); - assert(action_abbreviation != NULL); - - return strncmp(arg, action_name, strlen(action_name)+1) == 0 - || strncmp(arg, action_abbreviation, strlen(action_abbreviation)+1) == 0; -} int main(int argc, char *argv[]) { @@ -1147,7 +1134,7 @@ int main(int argc, char *argv[]) { if (argc > 1) { bool is_exit_requested = false; for (unsigned idx = 1; idx < argc; idx++) { - if (is_action_detected(argv[idx], "--help", "-h")) { + if (is_equal_to_any(argv[idx], "--help", "-h")) { // TODO Maybe rearrange the order of the command. fprintf(stdout, "Usage: ttt [OPTION]... [FILE]...\n" @@ -1188,13 +1175,13 @@ int main(int argc, char *argv[]) { return EXIT_SUCCESS; } - if (is_action_detected(argv[idx], "--version", "-v")) { + if (is_equal_to_any(argv[idx], "--version", "-v")) { fprintf(stdout, "Task Time Tracker version " VERSION "\n"); free_memory(); return EXIT_SUCCESS; } - if (is_action_detected(argv[idx], "--import-csv", "-i")) { + if (is_equal_to_any(argv[idx], "--import-csv", "-i")) { idx++; if (idx >= argc) { fprintf(stdout, "Missing CSV file path to import.\n"); @@ -1210,7 +1197,7 @@ int main(int argc, char *argv[]) { continue; } - if (is_action_detected(argv[idx], "--export-csv", "-e")) { + if (is_equal_to_any(argv[idx], "--export-csv", "-e")) { idx++; if (idx >= argc) { fprintf(stdout, "Missing CSV file path to export.\n"); @@ -1225,7 +1212,7 @@ int main(int argc, char *argv[]) { continue; } - if (is_action_detected(argv[idx], "--no-autosave", "-n")) { + if (is_equal_to_any(argv[idx], "--no-autosave", "-n")) { is_autosave_enabled = false; continue; } @@ -59,9 +59,18 @@ Task Time Tracker - [x] Check if string_buffer needs to be cleared. We may be leaking info on the string_buffer. - [x] Replaced `sprintf` by `snprintf`; - [x] Make sure that string_buffer bounds are respected; -- [ ] Move database actions into functions: - - [ ] select_by_id/delta/task - - [ ] set_active(db, task) -- [ ] Re-check if draw_tui may be simplified. +- [ ] Compress code: + - [x] Re-do sprint_time5_utf8: -12 LOC; + - [ ] Re-do truncate_string_utf8: 1761 - XXXX = LOC; + - [ ] Get input using `get_input(char *input, size_t size, int row, int column)` (what does it returns???): + - [ ] wrap malloc (and maybe others) in a function with error checking + ```c + static inline void *MallocOrDie(size_t MemSize) { void *AllocMem = malloc(MemSize); /* Some implementations return null on a 0 length alloc, * we may as well allow this as it increases compatibility * with very few side effects */ if(!AllocMem && MemSize) { printf("Could not allocate memory!"); exit(-1); } return AllocMem; } + ``` + - [ ] Move database actions into functions: + - `select_task_by_delta(database_st *db, ptrdiff???)` + - `select_task_by_index(database_st *db, size_t???)` + - `sect_active(database_st *db, task_st *task)` + - [ ] Check if draw_tui may be simplified by drawing entire lines of tasks at once and draw columns separators after; - [ ] Review all code for bugs related to auto-cast on ptrdiff_t/size_t (signed/unsigned); - [ ] Go over all `TODO` items; |
