tadd timer(1) - stopwatch - simple timer for console or x root window
 (HTM) git clone git://src.adamsgaard.dk/stopwatch
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 056f2e50e7795c50e3fd616034a39731ebc49d30
 (DIR) parent 4f6e38d9d743040a27ac5fdc0f49dbe5d53ec2af
 (HTM) Author: Anders Damsgaard <anders@adamsgaard.dk>
       Date:   Thu,  5 Nov 2020 09:03:59 +0100
       
       add timer(1)
       
       Diffstat:
         M Makefile                            |       7 +++----
         M stopwatch.1                         |       1 +
         A timer.1                             |      48 +++++++++++++++++++++++++++++++
         A timer.c                             |     101 +++++++++++++++++++++++++++++++
       
       4 files changed, 153 insertions(+), 4 deletions(-)
       ---
 (DIR) diff --git a/Makefile b/Makefile
       t@@ -10,10 +10,9 @@ DOCPREFIX = ${PREFIX}/share/doc/${NAME}
        
        RANLIB = ranlib
        
       -BIN = ${NAME}
       -#BIN = \
       -#        stopwatch\
       -#        timer
       +BIN = \
       +        stopwatch\
       +        timer
        SRC = ${BIN:=.c}
        HDR = timeutil.h
        
 (DIR) diff --git a/stopwatch.1 b/stopwatch.1
       t@@ -40,6 +40,7 @@ exits with 0 on success, and >0 if a a runtime error occurs.
        .Sh SEE ALSO
        .Xr dwm 1
        .Xr spoon 1
       +.Xr timer 1
        .Xr xsetroot 1
        .Sh AUTHORS
        .An Anders Damsgaard Aq Mt anders@adamsgaard.dk
 (DIR) diff --git a/timer.1 b/timer.1
       t@@ -0,0 +1,48 @@
       +.Dd $Mdocdate$
       +.Dt TIMER 1
       +.Os
       +.Sh NAME
       +.Nm timer
       +.Nd reports elapsed time after launch.
       +.Sh SYNOPSIS
       +.Nm
       +.Op Fl p Ar prefix
       +.Op Fl P Ar postfix
       +.Op Fl i Ar interval
       +.Op Fl x
       +.Ar HH:MM:SS
       +.Sh DESCRIPTION
       +The
       +.Nm
       +counts down from for the specified duration in HH:MM:SS format, and
       +prints the remaining time to standard output by default.  The time
       +is written in the format "%S s" for remaining time of less than one
       +minute long, "%M:%SS" for durations less than one hour, and
       +"%H:%MM:%SS" for all longer durations.
       +.Pp
       +The options are as follows:
       +.Bl -tag -width Ds
       +.It Fl p Ar prefix
       +Print the
       +.Ar prefix
       +string before the time stamp.
       +.It Fl P Ar postfix
       +Print the
       +.Ar postfix
       +string after the time stamp.
       +.It Fl i Ar interval
       +update the elapsed time with this interval in seconds.
       +.It Fl x
       +write the output to the X root window parameter, which
       +.Xr dwm 1
       +uses as status line.
       +.Sh EXIT STATUS
       +.Nm
       +exits with 0 on success, and >0 if a a runtime error occurs.
       +.Sh SEE ALSO
       +.Xr dwm 1
       +.Xr spoon 1
       +.Xr stopwatch 1
       +.Xr xsetroot 1
       +.Sh AUTHORS
       +.An Anders Damsgaard Aq Mt anders@adamsgaard.dk
 (DIR) diff --git a/timer.c b/timer.c
       t@@ -0,0 +1,101 @@
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <limits.h>
       +#include <unistd.h>
       +#include <time.h>
       +#include <string.h>
       +#include <err.h>
       +#include <X11/Xlib.h>
       +
       +#include "timeutil.h"
       +
       +char *argv0;
       +
       +void
       +usage(void)
       +{
       +        errx(1, "usage: %s [-p prefix] [-P postfix] [-i interval] [-x] HH:MM:SS", argv0);
       +}
       +
       +void
       +print_loop(unsigned int interval, char *prefix, char *postfix, time_t duration)
       +{
       +        char buf[LINE_MAX];
       +        time_t t_start = time(NULL);
       +        time_t t_elapsed = 0;
       +
       +        while ((t_elapsed = time(NULL) - t_start) < duration) {
       +                format_time(buf, sizeof(buf), duration - t_elapsed, prefix, postfix);
       +                printf("\r%s ", buf);
       +                fflush(stdout);
       +                sleep(interval);
       +        }
       +}
       +
       +void
       +xroot_loop(unsigned int interval, char *prefix, char *postfix, time_t duration)
       +{
       +        Display *dpy;
       +        char buf[LINE_MAX];
       +        time_t t_start = time(NULL);
       +        time_t t_elapsed = 0;
       +
       +        dpy = XOpenDisplay(NULL);
       +        if (dpy == NULL)
       +                errx(1, "cannot open display");
       +        while ((t_elapsed = time(NULL) - t_start) < duration) {
       +                format_time(buf, sizeof(buf), duration - t_elapsed, prefix, postfix);
       +                XStoreName(dpy, DefaultRootWindow(dpy), buf);
       +                XSync(dpy, False);
       +                sleep(interval);
       +        }
       +}
       +
       +int
       +main(int argc, char *argv[])
       +{
       +        int h, m, s;
       +        time_t duration;
       +        int ch, xflag = 0;
       +        unsigned int interval = 1;
       +        char prefix[LINE_MAX] = "", postfix[LINE_MAX] = "";
       +        const char *errstr;
       +
       +        argv0 = *argv;
       +
       +        while ((ch = getopt(argc, argv, "p:P:i:x")) != -1) {
       +                switch (ch) {
       +                case 'p':
       +                        strlcpy(prefix, optarg, sizeof(prefix));
       +                        break;
       +                case 'P':
       +                        strlcpy(postfix, optarg, sizeof(postfix));
       +                        break;
       +                case 'i':
       +                        interval = strtonum(optarg, 1, UINT_MAX, &errstr);
       +                        if (errstr != NULL)
       +                                errx(1, "interval is %s: %s", errstr, optarg);
       +                        break;
       +                case 'x':
       +                        xflag = 1;
       +                        break;
       +                default:
       +                        usage();
       +                }
       +        }
       +        argc -= optind;
       +        argv += optind;
       +        if (argc != 1)
       +                usage();
       +
       +        if (sscanf(argv[0], "%d:%d:%d", &h, &m, &s) != 3)
       +                errx(2, "could not parse time in HH:MM:SS format");
       +        duration = h * 3600 + m * 60 + s;
       +
       +        if (xflag)
       +                xroot_loop(interval, prefix, postfix, duration);
       +        else
       +                print_loop(interval, prefix, postfix, duration);
       +
       +        return 0;
       +}