diff --git a/main.c b/main.c index 1af55d8..274f1e9 100644 --- a/main.c +++ b/main.c @@ -175,67 +175,74 @@ void switch_activity(activity *activities, U32 *current_activity, activity_type } } +struct tm *today() +{ + U64 secs = now(); + struct tm *t = localtime((time_t *)(&secs)); + t->tm_hour = 0; + t->tm_min = 0; + t->tm_sec = 0; + return t; +} + +U64 start_of_day_seconds(struct tm *t) +{ + // NOTE: Technically, this can fail only if the year is >2038 on 32-bit + // platforms as size_t--a 32-bit--value would overflow. ON 64-bit, + // this is a non-issue. + time_t ts = mktime(t); + return ts; +} + +char *get_dir() +{ + local_persist char buffer[128]; + snprintf(buffer, sizeof(buffer), "%s/.timetracker", get_home_dir()); + return buffer; +} + +char *get_date_str(struct tm *t) +{ + local_persist char buffer[16]; + strftime(buffer, sizeof(buffer), "%Y_%m_%d", t); + return buffer; +} + +char *get_file(char *dir, struct tm *t) +{ + local_persist char buffer[256]; + snprintf(buffer, sizeof(buffer), "%s/%s", dir, get_date_str(t)); + return buffer; +} + int main(int argc, char *argv[]) { - activity activities[100]; + activity activities[256]; // TODO: This should be a dynamic array. memset(activities, 0, sizeof(activities)); U32 current_activity = 0; Activity_Stat activities_stats[activity_type_COUNT]; memset(activities_stats, 0, sizeof(activities_stats)); - U64 secs = now(); - struct tm *t = localtime((time_t *)(&secs)); - t->tm_hour = 0; - t->tm_min = 0; - t->tm_sec = 0; + struct tm *t = today(); + U64 ts = start_of_day_seconds(t); - time_t ts = mktime(t); - if(ts == (time_t)-1) { - fprintf(stderr, "mktime failed.\n"); + char *dir_path = get_dir(); + char *file_path = get_file(dir_path, t); + + if(!is_directory(dir_path)) { + mkdir(dir_path, 0700); // WARNING: Might fail, what then? + } + + FILE *f; + f = fopen(file_path, "r+"); + if(!f) { + fprintf(stderr, "fopen(%s) failed: %s\n", file_path, strerror(errno)); return 1; } - // TODO: Clean up. - // TODO: Clean up. - // TODO: Clean up. - - // Check if 2025-02-10 available - // build array - // then, save the file periodically (every ~5 seconds) - // TODO: Make global constant or in config file - char date_buffer[16]; - char dir_buffer[128]; - char file_buffer[256]; - - strftime(date_buffer, sizeof(date_buffer), "%Y_%m_%d", t); - snprintf(dir_buffer, sizeof(dir_buffer), "%s/.timetracker", - get_home_dir()); - snprintf(file_buffer, sizeof(file_buffer), "%s/%s", dir_buffer, - date_buffer); - - if(!is_directory(dir_buffer)) { - mkdir(dir_buffer, 0700); // WARNING: Might fail, what then? - } - - // TODO: Fix error handling. - // WARNING: Not bullet proof, yet. - FILE *f; - if(path_exists(file_buffer)) { - f = fopen(file_buffer, "r"); - if(!f) { - fprintf(stderr, "fopen(%s) failed: %s\n", file_buffer, - strerror(errno)); - return 1; - } - } else { - f = fopen(file_buffer, "w+"); - } - char line[4096]; - if(file_size(f) < 1) { - printf("EMPTY\n"); - } else { + if(file_size(f) > 0) { while(fgets(line, sizeof line, f)) { size_t n = strcspn(line, "\r\n"); line[n] = '\0'; @@ -281,7 +288,7 @@ int main(int argc, char *argv[]) U64 last_save = 0; - U64 lower_bound_s = (U64)ts; + U64 lower_bound_s = ts; U64 upper_bound_s = lower_bound_s + 86400; // U64 upper_bound_s = lower_bound_s + 3600; @@ -318,34 +325,21 @@ int main(int argc, char *argv[]) while(!WindowShouldClose()) { U64 now_s = now(); - // NOTE: WARNING: TODO: Temporary solution; to be cleaned up. if(now_s >= upper_bound_s) { - U64 secs = now(); + t = today(); + ts = start_of_day_seconds(t); - t = localtime((time_t *)(&secs)); - t->tm_hour = 0; - t->tm_min = 0; - t->tm_sec = 0; - - time_t ts = mktime(t); - if(ts == (time_t)-1) { - fprintf(stderr, "mktime failed.\n"); - return 1; - } - - lower_bound_s = (U64)ts; + lower_bound_s = ts; upper_bound_s = lower_bound_s + 86400; fclose(f); - strftime(date_buffer, sizeof(date_buffer), "%Y_%m_%d", t); - snprintf(file_buffer, sizeof(file_buffer), "%s/%s", dir_buffer, - date_buffer); + file_path = get_file(dir_path, t); - f = fopen(file_buffer, "w+"); + f = fopen(file_path, "r"); if(!f) { - fprintf(stderr, "Failed to create file: %s\n", file_buffer); - return 1; + fprintf(stderr, "Failed to create file: %s\n", file_path); + return 1; // TODO: REMOVE. } activity_type type = activities[current_activity].type; @@ -384,41 +378,23 @@ int main(int argc, char *argv[]) DrawRectangle(0, 0, window_w, 40, GRAY); for(U32 i = 0; i <= current_activity; i++) { - F32 start_x = - floor((F32)(activities[i].began - lower_bound_s) / - (F32)(upper_bound_s - lower_bound_s) * (F32)window_w); - F32 end_x = - floor(((F32)(activities[i].ended - lower_bound_s) / - (F32)(upper_bound_s - lower_bound_s)) * window_w); - DrawRectangle(start_x, 0, end_x - start_x, 40, - activities[i].color); + F32 start_x = floor((F32)(activities[i].began - lower_bound_s) / (F32)(upper_bound_s - lower_bound_s) * (F32)window_w); + F32 end_x = floor(((F32)(activities[i].ended - lower_bound_s) / (F32)(upper_bound_s - lower_bound_s)) * window_w); + DrawRectangle(start_x, 0, end_x - start_x, 40, activities[i].color); } - // TODO: CLEAN UP. - F32 width = - (window_w-padding_x*(float)(activity_type_COUNT+1)) / - (float)activity_type_COUNT; + F32 width = (window_w-padding_x*(float)(activity_type_COUNT+1)) / (float)activity_type_COUNT; for(U32 i = 0; i <= current_activity; i++) { - activities_stats[activities[i].type].total_seconds += - activities[i].ended - activities[i].began; + activities_stats[activities[i].type].total_seconds += activities[i].ended - activities[i].began; } for(U32 i = 0; i < activity_type_COUNT; i ++) { Hours time = break_time(activities_stats[i].total_seconds); - snprintf(activities_stats[i].seconds_str, - sizeof(activities_stats[i].seconds_str), - "%02llu:%02llu:%02llu", - time.hours, time.minutes, time.seconds); - - Rectangle rect = - { (padding_x*(i+1))+(width*i), 60, width, (window_h-70) }; - if(activity_button(rect, - activity_type_string_representation[i], - activities_stats[i].seconds_str, font_size, - (activities[current_activity].type == i ? WHITE : BLACK), - activity_type_color_representation[i])) - { + snprintf(activities_stats[i].seconds_str, sizeof(activities_stats[i].seconds_str), "%02llu:%02llu:%02llu", time.hours, time.minutes, time.seconds); + + Rectangle rect = { (padding_x*(i+1))+(width*i), 60, width, (window_h-70) }; + if(activity_button(rect, activity_type_string_representation[i], activities_stats[i].seconds_str, font_size, (activities[current_activity].type == i ? WHITE : BLACK), activity_type_color_representation[i])) { if(activities[current_activity].type != i) { switch_activity(activities, ¤t_activity, i, now_s); } @@ -428,9 +404,7 @@ int main(int argc, char *argv[]) char index_buf[8]; snprintf(index_buf, sizeof(index_buf), "%d", i + 1); - DrawTextEx(state.font, index_buf, - (Vector2){ rect.x + 10.0f, rect.y + 10.0f }, - font_size - 5.0f, 2, BLACK); + DrawTextEx(state.font, index_buf, (Vector2){ rect.x + 10.0f, rect.y + 10.0f }, font_size - 5.0f, 2, BLACK); } EndDrawing(); @@ -439,29 +413,24 @@ int main(int argc, char *argv[]) activities_stats[activities[i].type].total_seconds = 0; } - // WARNING: This is error prone. // Save the state every 5 seconds. if((now_s - last_save) >= 5) { - f = freopen(file_buffer, "w", f); // WARNING: TODO: Might fail. + f = freopen(file_path, "w+", f); // NOTE: We want to clear file contents before the next write. + if(f) { + char write_buffer[128]; + for(U32 i = 0; i <= current_activity; i++) { + snprintf(write_buffer, sizeof(write_buffer), "%s %llu %llu\n", activity_type_string_representation[activities[i].type], activities[i].began, activities[i].ended); - char write_buffer[128]; - for(U32 i = 0; i <= current_activity; i++) { - snprintf(write_buffer, sizeof(write_buffer), - "%s %llu %llu\n", - activity_type_string_representation[activities[i].type], - activities[i].began, - activities[i].ended); - - size_t write_buffer_len = strlen(write_buffer); - if(fwrite(write_buffer, 1, write_buffer_len, f) != - write_buffer_len) - { - perror("fwrite"); + size_t write_buffer_len = strlen(write_buffer); + if(fwrite(write_buffer, 1, write_buffer_len, f) != write_buffer_len) { + // NOTE: We do not care, probably for now, that it might have failed to write some data. + // The program will either overwrite everything again or the next launch will ignore the corrupted line. + } } - } - if(fflush(f) != 0) - perror("fflush"); + if(fflush(f) != 0) + perror("fflush"); + } last_save = now_s; }