stopwatch

simple timer for console or x root window
git clone git://src.adamsgaard.dk/stopwatch
Log | Files | Refs | README | LICENSE Back to index

commit 3390af26250ccad0fd7e796c2325c94f5dbe538c
Author: Anders Damsgaard <anders@adamsgaard.dk>
Date:   Wed,  4 Nov 2020 14:56:30 +0100

first commit

Diffstat:
ALICENSE | 15+++++++++++++++
AMakefile | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AREADME | 18++++++++++++++++++
Astopwatch.1 | 45+++++++++++++++++++++++++++++++++++++++++++++
Astopwatch.c | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 246 insertions(+), 0 deletions(-)

diff --git a/LICENSE b/LICENSE @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) 2020 Anders Damsgaard <anders@adamsgaard.dk> + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/Makefile b/Makefile @@ -0,0 +1,63 @@ +.POSIX: + +NAME = stopwatch +VERSION = 0.1 + +# paths +PREFIX = /usr/local +MANPREFIX = ${PREFIX}/share/man +DOCPREFIX = ${PREFIX}/share/doc/${NAME} + +BIN = ${NAME} +SRC = ${BIN:=.c} +MAN1 = ${BIN:=.1} +DOC = \ + LICENSE\ + README + +all: ${BIN} + +CFLAGS = -DVERSION=\"${VERSION}\" -I/usr/X11R6/include +LDFLAGS = -L/usr/X11R6/lib -lX11 + +${BIN}: ${@:=.o} + +.o: + ${CC} ${LDFLAGS} -o $@ $< + +.c.o: + ${CC} ${CFLAGS} ${CPPFLAGS} -o $@ -c $< + +dist: + rm -rf "${NAME}-${VERSION}" + mkdir -p "${NAME}-${VERSION}" + cp -f ${MAN1} ${DOC} ${SRC} Makefile "${NAME}-${VERSION}" + tar cf - "${NAME}-${VERSION}" | gzip -c > "${NAME}-${VERSION}.tar.gz" + rm -rf "${NAME}-${VERSION}" + +clean: + rm -f ${BIN} ${OBJ} + +install: + # installing executable files. + mkdir -p "${DESTDIR}${PREFIX}/bin" + cp -f ${BIN} "${DESTDIR}${PREFIX}/bin" + for f in ${BIN}; do chmod 755 "${DESTDIR}${PREFIX}/bin/$$f"; done + # installing documentation files. + mkdir -p "${DESTDIR}${DOCPREFIX}" + cp -f ${DOC} "${DESTDIR}${DOCPREFIX}" + # installing manual pages for general commands: section 1. + mkdir -p "${DESTDIR}${DOCPREFIX}/man1" + cp -f ${MAN1} "${DESTDIR}${MANPREFIX}/man1" + for m in ${MAN1}; do chmod 644 "${DESTDIR}${MANPREFIX}/man1/$$m"; done + +uninstall: + # removing executable files. + for f in ${BIN}; do rm -f "${DESTDIR}${PREFIX}/bin/$$f"; done + # removing documentation files. + for d in ${DOC}; do rm -f "${DESTDIR}${DOCPREFIX}/$$d"; done + -rmdir "${DESTDIR}${DOCPREFIX}" + # removing manual pages. + for m in ${MAN1}; do rm -f "${DESTDIR}${MANPREFIX}/man1/$$m"; done + +.PHONY: all clean dist install uninstall diff --git a/README b/README @@ -0,0 +1,18 @@ +# stopwatch + +About: A simple stopwatch which can print the output to the terminal or + the X root window parameter. The latter is used for setting the + dwm(1) title bar. + +Compiling: `make && make install` + (optionally prefix the install comman with sudo(1) or doas(1)) + +Compatibility: Tested on OpenBSD 6.8 + +Documentation: `man 1 stopwatch` + +Copyright: See LICENSE + +Author: Anders Damsgaard <anders@adamsgaard.dk> + git://src.adamsgaard.dk/stopwatch + https://src.adamsgaard.dk/stopwatch diff --git a/stopwatch.1 b/stopwatch.1 @@ -0,0 +1,45 @@ +.Dd $Mdocdate$ +.Dt STOPWATCH 1 +.Os +.Sh NAME +.Nm stopwatch +.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 +.Sh DESCRIPTION +The +.Nm +prints the elapsed time to standard output by default. The time +is written in the format "%S s" for elapsed durations 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 xsetroot 1 +.Sh AUTHORS +.An Anders Damsgaard Aq Mt anders@adamsgaard.dk diff --git a/stopwatch.c b/stopwatch.c @@ -0,0 +1,105 @@ +#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> + +void +usage(char *argv0) +{ + errx(1, "usage: %s [-p prefix] [-P postfix] [-i interval] [-x]", argv0); +} + +void +format_time(char *out, size_t outsiz, time_t t_elapsed, char *prefix, char *postfix) +{ + time_t h = 0, m = 0, s = 0; + + h = t_elapsed / 3600; + m = (t_elapsed % 3600) / 60; + s = t_elapsed % 60; + + if (h > 0) + snprintf(out, outsiz, "%s%lld:%02lld:%02lld%s", + prefix, h, m, s, postfix); + else if (m > 0) + snprintf(out, outsiz, "%s%lld:%02lld%s", prefix, m, s, postfix); + else + snprintf(out, outsiz, "%s%lld s%s", prefix, s, postfix); +} + +void +print_loop(unsigned int interval, char *prefix, char *postfix) +{ + char buf[LINE_MAX]; + time_t t_start = time(NULL); + + while (1) { + format_time(buf, sizeof(buf), time(NULL) - t_start, prefix, postfix); + printf("\r%s\n", buf); + fflush(stdout); + sleep(interval); + } +} + +void +xroot_loop(unsigned int interval, char *prefix, char *postfix) +{ + Display *dpy; + char buf[LINE_MAX]; + time_t t_start = time(NULL); + + dpy = XOpenDisplay(NULL); + if (dpy == NULL) + errx(1, "cannot open display"); + while (1) { + format_time(buf, sizeof(buf), time(NULL) - t_start, prefix, postfix); + XStoreName(dpy, DefaultRootWindow(dpy), buf); + XSync(dpy, False); + sleep(interval); + } +} + +int +main(int argc, char *argv[]) +{ + int ch, xflag = 0; + unsigned int interval = 1; + char prefix[LINE_MAX] = "", postfix[LINE_MAX] = ""; + const char *errstr; + + 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(argv[0]); + } + } + argc -= optind; + argv += optind; + if (argc > 0) + usage(argv[0]); + + if (xflag) + xroot_loop(interval, prefix, postfix); + else + print_loop(interval, prefix, postfix); + + return 0; +}