From 4d99702f60f96279511ab5ab5d360bf0c2577e47 Mon Sep 17 00:00:00 2001 From: Tomasz Kramkowski Date: Sat, 12 Dec 2015 23:05:59 +0000 Subject: timer.c: cleanup --- timer.c | 169 ++++++++++++++++++++++++++-------------------------------------- 1 file changed, 68 insertions(+), 101 deletions(-) diff --git a/timer.c b/timer.c index 3d43a7c..f2490d1 100644 --- a/timer.c +++ b/timer.c @@ -22,62 +22,25 @@ #include #include -#define SEC_SECOND 1 -#define SEC_MINUTE 60 -#define SEC_HOUR 3600 -#define SEC_DAY 86400 -#define SEC_MONTH 2629746 -#define SEC_YEAR 31556940 - +static const unsigned long long SEC_SECOND = 1, SEC_MINUTE = 60, + SEC_HOUR = 3600, SEC_DAY = 86400, SEC_MONTH = 2629746, + SEC_YEAR = 31556940; static const unsigned long interval_nsec = 1000000000 / 4; -unsigned short term_width = 0; /* Maybe volatile? */ + +volatile unsigned short term_width = 0; void sigwinch(int sig) { + struct winsize ws; + if (sig != SIGWINCH) return; - struct winsize ws; - if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1) error(1, errno, "Failed to get terminal width"); term_width = ws.ws_col; } -unsigned long int get_seconds(char *code) -{ - int length = strlen(code), multiplier = 0; - char suffix = code[length - 1], value[length + 1]; - unsigned long retval; - - if (length < 2) { - return 0; - } - - switch (suffix) { - case 's': multiplier = SEC_SECOND; break; // 1 second - case 'm': multiplier = SEC_MINUTE; break; // 1 minute - case 'h': multiplier = SEC_HOUR; break; // 1 hour - case 'D': multiplier = SEC_DAY; break; // 1 day - case 'M': multiplier = SEC_MONTH; break; // 30.4368 days - case 'Y': multiplier = SEC_YEAR; break; // 365.242 days - default : return 0; - } - - strncpy(value, code, length + 1); - - value[length - 1] = '\0'; - - errno = 0; - - retval = strtoul(value, NULL, 10) * multiplier; - - if (retval == ULONG_MAX && errno != 0) - error(1, errno, "Error converting time specifier %s", code); - - return retval; -} - void clear_line(void) { if (term_width <= 1) @@ -85,49 +48,39 @@ void clear_line(void) for (unsigned short i = 0; i < term_width - 1; i++) putchar(' '); - putchar('\r'); if (fflush(stdout) != 0) error(1, errno, "Failed to flush stdout"); } +void format_dmy(char *dest, size_t size, const char *name, + unsigned long long count) +{ + if (count == 1) + snprintf(dest, size, "%llu %s, ", count, name); + else if (count > 1) + snprintf(dest, size, "%llu %ss, ", count, name); + else + dest[0] = '\0'; +} -void print_time(unsigned long total_sec, bool show_colon) +void print_time(unsigned long long total_sec, bool show_colon) { - unsigned long years, months, days, hours, minutes, seconds; - char colon = show_colon ? ':' : ' ', syears[128], smonths[16], - sdays[16]; + unsigned long long count, hours, minutes, seconds; + char colon = show_colon ? ':' : ' ', syears[128], smonths[16], sdays[16]; - years = total_sec / SEC_YEAR; + count = total_sec / SEC_YEAR; total_sec %= SEC_YEAR; + format_dmy(syears, sizeof syears, "year", count); - if (years == 1) - snprintf(syears, sizeof syears, "%lu year, ", years); - else if (years > 1) - snprintf(syears, sizeof syears, "%lu years, ", years); - else - syears[0] = '\0'; - - months = total_sec / SEC_MONTH; + count = total_sec / SEC_MONTH; total_sec %= SEC_MONTH; + format_dmy(smonths, sizeof smonths, "month", count); - if (months == 1) - snprintf(smonths, sizeof smonths, "%lu month, ", months); - else if (months > 1) - snprintf(smonths, sizeof smonths, "%lu months, ", months); - else - smonths[0] = '\0'; - - days = total_sec / SEC_DAY; + count = total_sec / SEC_DAY; total_sec %= SEC_DAY; - - if (days == 1) - snprintf(sdays, sizeof sdays, "%lu day, ", days); - else if (days > 1) - snprintf(sdays, sizeof sdays, "%lu days, ", days); - else - sdays[0] = '\0'; + format_dmy(sdays, sizeof sdays, "day", count); hours = total_sec / SEC_HOUR; total_sec %= SEC_HOUR; @@ -139,18 +92,45 @@ void print_time(unsigned long total_sec, bool show_colon) total_sec %= SEC_SECOND; if (total_sec != 0) - error(1, 0, "An error occured during time formatting"); + error(1, 0, "A bug occured during time formatting"); - printf(" %s%s%s%.2lu%c%.2lu%c%.2lu\r", syears, smonths, sdays, hours, + printf(" %s%s%s%.2llu%c%.2llu%c%.2llu\r", syears, smonths, sdays, hours, colon, minutes, colon, seconds); if (fflush(stdout) != 0) error(1, errno, "Failed to flush stdout"); } -void usage(char *cmd) +unsigned long long get_seconds(char *code) { - printf("Usage:\n\t%s {s,m,h,D,M,Y} ...\n", cmd); + size_t length = strlen(code); + unsigned long long multiplier, retval; + char suffix, value[length]; + + if (length < 2) + return 0; + + suffix = code[length - 1]; + switch (suffix) { + case 's': multiplier = SEC_SECOND; break; /* 1 second */ + case 'm': multiplier = SEC_MINUTE; break; /* 1 minute */ + case 'h': multiplier = SEC_HOUR; break; /* 1 hour */ + case 'D': multiplier = SEC_DAY; break; /* 1 day */ + case 'M': multiplier = SEC_MONTH; break; /* 30.4368 days */ + case 'Y': multiplier = SEC_YEAR; break; /* 365.242 days */ + default: return 0; + } + + strncpy(value, code, sizeof value); + + value[sizeof value - 1] = '\0'; + + errno = 0; + retval = strtoul(value, NULL, 10) * multiplier; /* Possibly might overflow */ + if (retval == ULONG_MAX && errno != 0) + error(1, errno, "Error converting time specifier %s", code); + + return retval; } int main(int argc, char **argv) @@ -158,42 +138,29 @@ int main(int argc, char **argv) bool blink = false; int sig; sigset_t sigset; - struct itimerspec its; - struct sigevent sev; - struct sigaction sigact; + struct itimerspec its = {{0, interval_nsec}, {0, interval_nsec}}; + struct sigaction sigact = {.sa_handler = sigwinch}; timer_t timerid; - - unsigned long total_seconds = 0; + struct sigevent sev = {.sigev_notify = SIGEV_SIGNAL, + .sigev_signo = SIGRTMIN, .sigev_value.sival_ptr = &timerid}; + unsigned long long total_seconds = 0; if (!isatty(STDOUT_FILENO)) error(1, 0, "Error: stdout is not a tty"); - if (argc < 2) { - fprintf(stderr, "Not enough arguments.\n"); - usage(argv[0]); - exit(1); - } + if (argc < 2) + error(1, 0, "Not enough arguments.\nUsage:\n" + "\t%s {s,m,h,D,M,Y} ...", argv[0]); for (int i = 1; i < argc; i++) total_seconds += get_seconds(argv[i]); - sigact.sa_handler = sigwinch; - if (sigaction(SIGWINCH, &sigact, NULL) != 0) error(1, errno, "Unable to set SIGWINCH signal action"); - sev.sigev_notify = SIGEV_SIGNAL; - sev.sigev_signo = SIGRTMIN; - sev.sigev_value.sival_ptr = &timerid; - if (timer_create(CLOCK_MONOTONIC, &sev, &timerid) != 0) error(1, errno, "Could not create timer"); - its = (struct itimerspec){ - {0, interval_nsec}, - {0, interval_nsec} - }; - if (sigemptyset(&sigset) != 0) error(1, errno, "Could not empty signal set"); @@ -208,12 +175,12 @@ int main(int argc, char **argv) sigwinch(SIGWINCH); - for (unsigned long i = 0; i < total_seconds; i++) + for (unsigned long long i = 0; i < total_seconds; i++) for (int ii = 0; ii < 4; ii++) { if (sigwait(&sigset, &sig), sig != SIGRTMIN) error(1, 0, "sigwait returned unexpected signal %d", sig); if (sigaddset(&sigset, SIGRTMIN) != 0) - error(1, errno, "Could not add signal to set"); + error(1, errno, "Could not add SIGRTMIN to signal set"); clear_line(); print_time(total_seconds - i, ii < 2); @@ -229,7 +196,7 @@ int main(int argc, char **argv) break; if (sigaddset(&sigset, SIGRTMIN) != 0) - error(1, errno, "Could not add signal to set"); + error(1, errno, "Could not add SIGRTMIN to signal set"); clear_line(); -- cgit v1.2.3-54-g00ecf