make the timer fancy

This commit is contained in:
2025-09-01 22:18:12 -04:00
parent 18500e163c
commit 5ba46284fe
4 changed files with 208 additions and 60 deletions

1
include/util.h Normal file
View File

@@ -0,0 +1 @@
#define numlen(x) (x > 0 ? floor(log10(abs(x))) + 1 : 0)

View File

@@ -27,10 +27,14 @@ srcfiles = files(
'src/conf.c'
) + luafiles + subcmds
cc = meson.get_compiler('c')
math_dep = cc.find_library('m', required: true)
# build the executable
executable('wom', srcfiles,
dependencies: [
dependency('lua', version: '>=5.1 <6.0'),
math_dep,
],
include_directories: [
include_directories('include'),

View File

@@ -69,8 +69,7 @@ main(int argc, char *argv[])
int l;
lua_State *L;
const char *cag_path;
char *config_path;
bool show_help = false;
char *config_path = { 0 };
cag_option_context context;
/* general options for womblic */
@@ -87,8 +86,7 @@ main(int argc, char *argv[])
case 'h':
printf("Usage: wom [OPTION]...\n");
cag_option_print(options, CAG_ARRAY_SIZE(options), stdout);
show_help = true;
break;
exit(0);
case '?':
cag_option_print_error(&context, stdout);
break;
@@ -117,12 +115,6 @@ main(int argc, char *argv[])
lua_pop(L, lua_gettop(L));
}
/* show help info about which subcmds are available */
if (show_help) {
subcmds_subcmd(NULL, 0, NULL);
exit(0);
}
run_subcmds(argc, argv);
lua_close(L);

View File

@@ -1,10 +1,92 @@
#include <math.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include <unistd.h>
#include "util.h"
#include "subcmds.h"
#define S_AS_MSEC 1000000
#define PB_LEN 30
#define PB_FULL "┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃┃"
#define set_str_len(u, us, hu) str_len += (u > 0) ? (numlen(u) + 1 + (u > 1 ? strlen(us"s") : strlen(us)) + ((hu > 0) ? 1 : 0)) : 0
#define write_str(u, us) do { \
if (u > 0) { \
if (str[0] != '\0') { \
strcat(str, " "); \
} \
size_t sz = numlen(u) + (u > 1 ? strlen(us"s") : strlen(us)) + 2; \
tmp = calloc(sz, sizeof(char)); \
snprintf(tmp, sz, "%d %s", u, u > 1 ? us"s" : us); \
strcat(str, tmp); \
free(tmp); \
} \
} while (0)
int i, total_delay_s;
/**
* @brief convert a time to a string in seconds ie:
* 12 -> 12 seconds
*
* 720 -> 12 minutes
*
* 43,200 -> 12 hours
*
* 1,036,800 -> 12 days
*
* @param sec input time
* @return time
*/
static char
*sec2str(int sec)
{
int days, hours, minutes, seconds, str_len;
char *str, *tmp;
if (sec < 0) {
return 0;
}
for (str_len = days = hours = minutes = seconds = 0; sec > 0;) {
if (sec >= 60 * 60 * 24) {
sec -= 60 * 60 * 24;
days++;
} else if (sec >= 60 * 60) {
sec -= 60 * 60;
hours++;
} else if (sec >= 60) {
sec -= 60;
minutes++;
} else if (sec >= 1) {
sec -= 1;
seconds++;
}
}
set_str_len(days, "day", 0);
set_str_len(hours, "hour", days);
set_str_len(minutes, "minute", hours);
set_str_len(seconds, "second", minutes);
str_len += 1;
str = malloc(str_len * sizeof(char));
str[0] = '\0';
write_str(days, "day");
write_str(hours, "hour");
write_str(minutes, "minute");
write_str(seconds, "second");
return str;
}
/**
* @brief convert a sting to a time in seconds ie:
* 12s -> 12 seconds
@@ -19,75 +101,144 @@
* @return time in seconds
*/
static int
string2time(char *str)
str2sec(char *str)
{
char *d;
int i;
double time;
char *time_buffer;
int i, si, ei, ste, temp_total, total;
/* find the length of the string */
for (i = 0; str[i] != '\0'; i++)
;
for (total = si = ei = i = 0; i < strlen(str); i++, temp_total = 0) {
/**
* if the char is not a number we need to take all the previous numbers
* and attempt to convert this to a proper time
*/
if (str[i] < '0' || str[i] > '9') {
ei = i - 1;
ste = ei - si + 1;
time_buffer = malloc((ste * sizeof(char)) + 1);
memcpy(time_buffer, str + si, ste);
time_buffer[ste] = '\0';
temp_total += strtol(time_buffer, NULL, 10);
free(time_buffer);
/* if there is a trailing character make sure to remove it */
if (str[i] < '0' || str[i] > '9') {
i--;
}
switch (str[i]) {
default: case 's': break;
case 'm': temp_total *= 60; break;
case 'h': temp_total *= 60 * 60; break;
case 'd': temp_total *= 60 * 60 * 24; break;
}
/* allocate space for numerical string */
d = (char *)calloc(i, sizeof(char));
strncpy(d, str, i);
total += temp_total;
si = i + 1;
}
}
/* atoi the numerical string into an int */
time = atof(d);
free(d);
/* modify the time using the last trailing character */
switch (str[i]) {
case 's': break;
case 'm': time *= 60; break;
case 'h': time *= 60 * 60; break;
case 'd': time *= 60 * 60 * 24; break;
default: return -1; break;
}
return time;
return total;
}
static void
timer_exit(void)
{
char *time_str;
time_t t;
struct tm tm;
printf("\033[?25h");
time_str = sec2str(total_delay_s - i);
t = time(NULL);
tm = *localtime(&t);
printf(
"\033[3A\033[43;30;1m wom timer \033[0m %s elapsed at %d/%02d/%02d %02d:%02d:%02d\n",
time_str,
tm.tm_year + 1900,
tm.tm_mon + 1,
tm.tm_mday,
tm.tm_hour,
tm.tm_min,
tm.tm_sec
);
free(time_str);
}
static void
timer_sig_exit(int sig)
{
puts("\n");
timer_exit();
exit(sig);
}
void
timer_subcmd(void *, int argc, char *argv[])
{
int i, l, sum;
char *s;
bool first;
int j, slp, sec, rollover, wi, tick, sub;
char *pb_elapsed, *pb_left, *time_str;
for (i = 1, sum = 0, l = 0; i < argc; i++) {
sum += string2time(argv[i]);
l += strlen(argv[i]);
for (i = 1, total_delay_s = 0; i < argc; i++) {
total_delay_s += str2sec(argv[i]);
}
/* allocate and populate a string with the length of the timer */
s = (char *)calloc(l + i - 1, sizeof(char));
for (i = 1; i < argc; i++) {
/* TODO: reorder based on magnitude */
s = strcat(s, argv[i]);
if (i != argc - 1) {
s = strcat(s, " ");
}
}
if (sum <= 0) {
if (total_delay_s <= 0) {
exit(1);
}
/* print out the number of time */
printf("Waiting for %s...\n", s);
/* create the progress bar */
pb_left = calloc(strlen(PB_FULL), sizeof(char) + 1);
strcpy(pb_left, PB_FULL);
pb_elapsed = calloc(strlen(PB_FULL), sizeof(char) + 1);
/* TODO: instead of sleeping implement polling that way if need be we can have
* a countdown */
sleep(sum);
/* render ui */
printf("\033[?25l");
atexit(timer_exit);
signal(SIGINT, timer_sig_exit);
puts("");
rollover = 0;
first = true;
tick = (total_delay_s / (float)PB_LEN) * S_AS_MSEC;
puts("returned");
for (sub = j = 0, i = total_delay_s; i > 0; i--) {
/* sub second handler */
for (sec = S_AS_MSEC; sec > 0;) {
if (!first) {
printf("\033[2A");
}
first = false;
if (rollover > 0) {
sub = rollover;
rollover = 0;
} else {
sub = tick;
}
if (sec - sub < 0) {
slp = sec;
rollover = fabs((float)sec - sub);
sec = 0;
} else {
sec -= sub;
slp = sub;
}
printf("\033[2K\033[43;30;1m wom timer \033[0m \033[33m%s\033[30m%s\033[0m\n", pb_left, pb_elapsed);
time_str = sec2str(i);
printf("\033[2K\033[90m %s\033[0m\n", time_str);
free(time_str);
/* change the progress bar */
if (rollover == 0) {
wi = strlen(PB_FULL) - (j * strlen("")) - strlen("");
strncat(pb_elapsed, "", strlen(PB_FULL));
pb_left[wi] = '\0';
j++;
}
usleep(slp);
}
}
free(pb_left);
free(pb_elapsed);
return;
}