aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2021-02-07 00:24:39 +0100
committerMattias Andrée <maandree@kth.se>2021-02-07 00:24:39 +0100
commit68dd947b82c6508cb72558130759c9eb2480f1eb (patch)
tree519b32f07c9f46d48849acb88c6687ecb28db12b
parentAdd posix time support (diff)
downloadmongotimer-68dd947b82c6508cb72558130759c9eb2480f1eb.tar.gz
mongotimer-68dd947b82c6508cb72558130759c9eb2480f1eb.tar.bz2
mongotimer-68dd947b82c6508cb72558130759c9eb2480f1eb.tar.xz
Fork mongoclock and turn into a timer and stopwatch
Signed-off-by: Mattias Andrée <maandree@kth.se>
-rw-r--r--.gitignore2
-rw-r--r--Makefile33
-rw-r--r--README39
-rw-r--r--config.mk2
-rwxr-xr-xdigit.sh22
-rw-r--r--mongoclock.152
-rw-r--r--mongoclock.c290
-rw-r--r--mongotimer.146
-rw-r--r--mongotimer.c342
9 files changed, 443 insertions, 385 deletions
diff --git a/.gitignore b/.gitignore
index e0f6042..76c7b24 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,4 +4,4 @@
*.out
*.su
mongo_*.h
-/mongoclock
+/mongotimer
diff --git a/Makefile b/Makefile
index f197990..c27a730 100644
--- a/Makefile
+++ b/Makefile
@@ -6,15 +6,15 @@ include $(CONFIGFILE)
DIGITS =\
mongo_0.h mongo_1.h mongo_2.h mongo_3.h mongo_4.h \
mongo_5.h mongo_6.h mongo_7.h mongo_8.h mongo_9.h \
- mongo_c.h
+ mongo_c.h mongo_m.h
-all: mongoclock
+all: mongotimer
-mongoclock: mongoclock.o
- $(CC) -o $@ $^ $(LDFLAGS)
+mongotimer: mongotimer.o
+ $(CC) -o $@ mongotimer.o $(LDFLAGS)
-mongoclock.o: mongoclock.c arg.h $(DIGITS)
- $(CC) -c -o $@ mongoclock.c $(CPPFLAGS) $(CFLAGS)
+mongotimer.o: mongotimer.c arg.h $(DIGITS)
+ $(CC) -c -o $@ mongotimer.c $(CPPFLAGS) $(CFLAGS)
mongo_0.h: digit.sh
./digit.sh 0 > $@
@@ -49,20 +49,23 @@ mongo_9.h: digit.sh
mongo_c.h: digit.sh
./digit.sh c > $@
-install: mongoclock
+mongo_m.h: digit.sh
+ ./digit.sh m > $@
+
+install: mongotimer
mkdir -p -- "$(DESTDIR)$(PREFIX)/bin"
- mkdir -p -- "$(DESTDIR)$(PREFIX)/share/licenses/mongoclock"
+ mkdir -p -- "$(DESTDIR)$(PREFIX)/share/licenses/mongotimer"
mkdir -p -- "$(DESTDIR)$(MANPREFIX)/man1"
- cp -- mongoclock "$(DESTDIR)$(PREFIX)/bin/"
- cp -- LICENSE "$(DESTDIR)$(PREFIX)/share/licenses/mongoclock/"
- cp -- mongoclock.1 "$(DESTDIR)$(MANPREFIX)/man1/"
+ cp -- mongotimer "$(DESTDIR)$(PREFIX)/bin/"
+ cp -- LICENSE "$(DESTDIR)$(PREFIX)/share/licenses/mongotimer/"
+ cp -- mongotimer.1 "$(DESTDIR)$(MANPREFIX)/man1/"
uninstall:
- -rm -- "$(DESTDIR)$(PREFIX)/bin/mongoclock"
- -rm -- "$(DESTDIR)$(MANPREFIX)/man1/mongoclock.1"
- -rm -r -- "$(DESTDIR)$(PREFIX)/share/licenses/mongoclock"
+ -rm -- "$(DESTDIR)$(PREFIX)/bin/mongotimer"
+ -rm -- "$(DESTDIR)$(MANPREFIX)/man1/mongotimer.1"
+ -rm -r -- "$(DESTDIR)$(PREFIX)/share/licenses/mongotimer"
clean:
- -rm -f -- *.o mongoclock mongo_*.h
+ -rm -f -- *.o mongotimer mongo_*.h
.PHONY: all install uninstall clean
diff --git a/README b/README
index c9d800d..a5c89fa 100644
--- a/README
+++ b/README
@@ -1,17 +1,20 @@
NAME
- mongoclock - Just a humongous clock for the terminal
+ mongotimer - A humongous timer or stopwatch for the terminal
SYNOPSIS
- mongoclock
+ mongotimer [[-e] [[hh:]mm:]ss]
DESCRIPTION
- Type mongoclock in the terminal and it will either,
- depending on the terminal size, show the time HH:MM
- or HH:MM:SS with humongous digits.
+ mongotimer will, if no arguments are specified,
+ simply display time since it started. If a time
+ is specified, it will count down from that time.
- If the terminal is too small, it will not run.
+ Pressing space will pause the timer/stopwatch,
+ and the time be displayed in yellow will
+ paused. Pressing space again will unpause the
+ timer/stopwatch.
- mongoclock is designed to be fit on most screens
+ mongotimer is designed to be fit on most screens
and be readable from all practical distances, so
that it can be used in place of a standard wall-
or alarm-clock. If the font is not big enough for
@@ -22,26 +25,14 @@ DESCRIPTION
OPTIONS
The mongoclock utility shall conform to the Base
- Definitions volume of POSIX.1‐2008, Section 12.2,
+ Definitions volume of POSIX.1-2008, Section 12.2,
Utility Syntax Guidelines.
The following options shall be supported:
- -s Display the posix time (seconds since
- 1970-01-01 00:00:00 UTC, ignoring inserted
- and removed leap seconds).
-
-RATIONALE
- It is really nice to have a large clock on your
- computer, instead of a small clock somewhere in
- your room, when your are sleeping. It is also
- nice to have a glansable clock available on your
- netbook for when you need to keep track of the
- time but are not working on a computer.
- Pocket-watches are just too much work to getting
- up, opening, closing, and putting down, and you
- would not like to forget it when you leave if
- you are in a public place.
+ -e Exit with status 0 when the timer reaches 0.
+ If not specified, the timer will continue
+ into negative times but with a red font.
SEE ALSO
- watch(1)
+ mongoclock(1), watch(1)
diff --git a/config.mk b/config.mk
index 0911b00..9e148ca 100644
--- a/config.mk
+++ b/config.mk
@@ -2,5 +2,5 @@ PREFIX = /usr/local
MANPREFIX = $(PREFIX)/share/man
CFLAGS = -std=c99 -Wall -Wextra -O2
-CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -DUSE_ADJTIMEX
+CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700
LDFLAGS = -s
diff --git a/digit.sh b/digit.sh
index c7e7fe7..8297043 100755
--- a/digit.sh
+++ b/digit.sh
@@ -176,6 +176,22 @@ mongo_c() {
' '
}
+mongo_m() {
+ printf '%s\n' \
+ ' ' \
+ ' ' \
+ ' ' \
+ ' ' \
+ ' ' \
+ ' [XXXXXXXXXX] ' \
+ ' [XXXXXXXXXX] ' \
+ ' ' \
+ ' ' \
+ ' ' \
+ ' ' \
+ ' '
+}
+
digit() {
if test "$1" = 0; then
mongo_0
@@ -197,14 +213,16 @@ digit() {
mongo_8
elif test "$1" = 9; then
mongo_9
- else
+ elif test "$1" = c; then
mongo_c
+ else
+ mongo_m
fi
}
printf 'static const char *mongo_%s[] = {\n' "$1"
digit "$1" | \
- sed -e 's/X/ /g' -e 's/\[/\\033\[7m /g' -e 's/\]/\\033\[m /g' | \
+ sed -e 's/X/ /g' -e 's/\[/\\033\[7m /g' -e 's/\]/\\033\[27m /g' | \
sed -e 's/^/"/' -e 's/$/",/' | \
sed '$s/,$//'
printf '};\n'
diff --git a/mongoclock.1 b/mongoclock.1
deleted file mode 100644
index 46131ff..0000000
--- a/mongoclock.1
+++ /dev/null
@@ -1,52 +0,0 @@
-.TH MONGOCLOCK 1 MONGOCLOCK
-.SH NAME
-mongoclock - Just a humongous clock for the terminal
-.SH SYNOPSIS
-.BR mongoclock
-.SH DESCRIPTION
-Type
-.BR mongoclock
-in the terminal and it will either, depending on
-the terminal size, show the time \fIHH:MM\fP or
-\fIHH:MM:SS\fP with humongous digits.
-.PP
-If the terminal is too small, it will not run.
-.PP
-.BR mongoclock
-is designed to be fit on most screens and be
-readable from all practical distances, so that
-it can be used in place of a standard wall- or
-alarm-clock. If the font is not big enough for
-your (or if it is too large,) just change the
-font size on your terminal. If it is not the
-right colour for you, simply change the font
-colour on your terminal
-.SH OPTIONS
-The
-.B cp
-utility shall conform to the Base Definitions
-volume of POSIX.1-2008,
-.IR "Section 12.2, Utility Syntax Guidelines" .
-.PP
-The following options shall be supported:
-.TP
-.B -s
-Display the posix time (seconds since 1970-01-01
-00:00:00 UTC, ignoring inserted and removed leap
-seconds).
-.SH RATIONALE
-It is really nice to have a large clock on your
-computer, instead of a small clock somewhere in
-your room, when your are sleeping. It is also
-nice to have a glansable clock available on your
-netbook for when you need to keep track of the
-time but are not working on a computer.
-Pocket-watches are just too much work to getting
-up, opening, closing, and putting down, and you
-would not like to forget it when you leave if
-you are in a public place.
-.SH "SEE ALSO"
-.BR watch (1)
-.SH AUTHORS
-Mattias Andrée
-.RI < maandree@kth.se >
diff --git a/mongoclock.c b/mongoclock.c
deleted file mode 100644
index b98cc67..0000000
--- a/mongoclock.c
+++ /dev/null
@@ -1,290 +0,0 @@
-/* See LICENSE file for copyright and license details. */
-#include <sys/ioctl.h>
-#include <sys/timerfd.h>
-#include <errno.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#ifdef USE_ADJTIMEX
-# include <sys/timex.h>
-#endif
-
-#include "arg.h"
-
-#define DX 16
-#define DY 12
-#define DC 16
-
-#include "mongo_0.h"
-#include "mongo_1.h"
-#include "mongo_2.h"
-#include "mongo_3.h"
-#include "mongo_4.h"
-#include "mongo_5.h"
-#include "mongo_6.h"
-#include "mongo_7.h"
-#include "mongo_8.h"
-#include "mongo_9.h"
-#include "mongo_c.h"
-
-static const char **mongo_ds[] = {
- mongo_0, mongo_1, mongo_2, mongo_3, mongo_4,
- mongo_5, mongo_6, mongo_7, mongo_8, mongo_9
-};
-
-static volatile sig_atomic_t caught_sigterm = 0;
-static volatile sig_atomic_t caught_sigwinch = 1;
-
-char *argv0;
-
-static void
-usage(void)
-{
- fprintf(stderr, "usage: %s\n", argv0);
- exit(1);
-}
-
-static void
-sigterm(int signo)
-{
- caught_sigterm = 1;
- (void) signo;
-}
-
-static void
-sigwinch(int signo)
-{
- caught_sigwinch = 1;
- (void) signo;
-}
-
-static void
-print_time(const char ***str, size_t y, size_t x)
-{
- size_t r, c;
-
- fprintf(stdout, "\033[%zu;1H\033[1J", y + 1);
-
- for (r = 0; r < DY; r++) {
- fprintf(stdout, "\033[%zu;%zuH\033[1K", y + r + 1, x + 1);
- for (c = 0; str[c]; c++)
- fprintf(stdout, "%s", str[c][r]);
- fprintf(stdout, "\033[0K");
- }
-
- fprintf(stdout, "\033[0J");
- fflush(stdout);
-}
-
-static int
-display_time(int timerfd)
-{
- const char **digits[9];
- int small = 0;
- uint64_t _overrun;
- struct winsize winsize;
- size_t x = 0, y = 0;
- struct tm *now;
-#ifdef USE_ADJTIMEX
- struct timex timex;
- int r;
-#else
- time_t now_;
-#endif
-
-#ifdef USE_ADJTIMEX
- memset(&timex, 0, sizeof(timex));
-#endif
-
- digits[8] = NULL;
-
- while (!caught_sigterm) {
- if (caught_sigwinch) {
- if (ioctl(STDOUT_FILENO, (unsigned long)TIOCGWINSZ, &winsize) < 0) {
- if (errno == EINTR)
- continue;
- goto fail;
- }
- caught_sigwinch = 0;
- y = winsize.ws_row;
- x = winsize.ws_col;
- if (y < DY) small = 2;
- else if (x < 4 * DX + DC) small = 2;
- else if (x < 6 * DX + 2 * DC) small = 1;
- else small = 0;
- y -= DY;
- x -= 4 * DX + DC;
- if (!small)
- x -= 2 * DX + DC;
- y /= 2;
- x /= 2;
- }
-
- if (small == 2) {
- fprintf(stdout, "\033[H\033[2J%s\n", "Screen is too small");
- fflush(stdout);
- pause();
- continue;
- }
-
-#ifdef USE_ADJTIMEX
- r = adjtimex(&timex);
- if (r == -1)
- goto fail;
- now = localtime(&timex.time.tv_sec);
- if (now == NULL)
- goto fail;
- if (r == TIME_OOP)
- now->tm_sec += 1;
-#else
- now_ = time(NULL);
- if (now_ == -1)
- goto fail;
- now = localtime(&now_);
- if (now == NULL)
- goto fail;
-#endif
-
- digits[0] = mongo_ds[now->tm_hour / 10];
- digits[1] = mongo_ds[now->tm_hour % 10];
- digits[2] = mongo_c;
- digits[3] = mongo_ds[now->tm_min / 10];
- digits[4] = mongo_ds[now->tm_min % 10];
- digits[5] = small ? NULL : mongo_c;
- digits[6] = mongo_ds[now->tm_sec / 10];
- digits[7] = mongo_ds[now->tm_sec % 10];
-
- print_time(digits, y, x);
-
- if (read(timerfd, &_overrun, sizeof(_overrun)) < 0)
- if (errno != EINTR)
- goto fail;
- }
-
- return 0;
-
-fail:
- return -1;
-}
-
-static int
-display_posixtime(int timerfd)
-{
- const char **digits[21];
- uint64_t _overrun;
- struct winsize winsize;
- size_t w = 0, h = 0, x, y;
- time_t now;
- size_t first_digit, ndigits;
-
- digits[20] = NULL;
-
- while (!caught_sigterm) {
- if (caught_sigwinch) {
- if (ioctl(STDOUT_FILENO, (unsigned long)TIOCGWINSZ, &winsize) < 0) {
- if (errno == EINTR)
- continue;
- goto fail;
- }
- caught_sigwinch = 0;
- h = winsize.ws_row;
- w = winsize.ws_col;
- }
-
- now = time(NULL);
- if (now < 0)
- goto fail;
-
- first_digit = 20;
- do {
- if (!first_digit)
- abort();
- digits[--first_digit] = mongo_ds[now % 10];
- } while (now /= 10);
- ndigits = 20 - first_digit;
-
- if (h < DY || w < ndigits * DX) {
- fprintf(stdout, "\033[H\033[2J%s\n", "Screen is too small");
- fflush(stdout);
- pause();
- continue;
- }
-
- y = (h - DY) / 2;
- x = (w - ndigits * DX) / 2;
- print_time(&digits[first_digit], y, x);
-
- if (read(timerfd, &_overrun, sizeof(_overrun)) < 0)
- if (errno != EINTR)
- goto fail;
- }
-
- return 0;
-
-fail:
- return -1;
-}
-
-int
-main(int argc, char *argv[])
-{
- int timerfd = -1;
- int posixtime = 0;
- struct itimerspec itimerspec;
- struct sigaction sigact;
-
- ARGBEGIN {
- case 's':
- posixtime = 1;
- break;
- default:
- usage();
- } ARGEND;
-
- if (argc)
- usage();
-
- fprintf(stdout, "\033[?1049h\033[?25l");
-
- if (clock_gettime(CLOCK_REALTIME, &itimerspec.it_value))
- goto fail;
- itimerspec.it_interval.tv_sec = 1;
- itimerspec.it_interval.tv_nsec = 0;
- itimerspec.it_value.tv_sec += 1;
- itimerspec.it_value.tv_nsec = 0;
- timerfd = timerfd_create(CLOCK_REALTIME, 0);
- if (timerfd < 0)
- goto fail;
- if (timerfd_settime(timerfd, TFD_TIMER_ABSTIME, &itimerspec, NULL))
- goto fail;
-
- memset(&sigact, 0, sizeof(sigact));
-
- sigact.sa_handler = sigterm;
- sigaction(SIGTERM, &sigact, NULL);
- sigaction(SIGQUIT, &sigact, NULL);
- sigaction(SIGINT, &sigact, NULL);
-
- sigact.sa_handler = sigwinch;
- sigaction(SIGWINCH, &sigact, NULL);
-
- if (posixtime ? display_posixtime(timerfd) : display_time(timerfd))
- goto fail;
-
- fprintf(stdout, "\033[?25h\n\033[?1049l");
- fflush(stdout);
- close(timerfd);
- return 0;
-
-fail:
- perror(argv0 ? argv0 : "mongoclock");
- fprintf(stdout, "\033[?25h\n\033[?1049l");
- fflush(stdout);
- if (timerfd >= 0)
- close(timerfd);
- return 1;
-}
diff --git a/mongotimer.1 b/mongotimer.1
new file mode 100644
index 0000000..7067e68
--- /dev/null
+++ b/mongotimer.1
@@ -0,0 +1,46 @@
+.TH MONGOTIMER 1 MONGOTIMER
+.SH NAME
+mongotimer - A humongous timer or stopwatch for the terminal
+.SH SYNOPSIS
+.BR mongotimer
+[[-e]
+.RI [[ hh\fB: ] mm\fB: ] ss ]
+.SH DESCRIPTION
+.B mongotimer
+will, if no arguments are specified, simply
+display time since it started. If a time is
+specified, it will count down from that time.
+.PP
+Pressing space will pause the timer/stopwatch,
+and the time be displayed in yellow will paused.
+Pressing space again will unpause the
+timer/stopwatch.
+.PP
+.B mongotimer
+is designed to be fit on most screens and be
+readable from all practical distances, so that
+it can be used in place of a standard wall- or
+alarm-clock. If the font is not big enough for
+your (or if it is too large,) just change the
+font size on your terminal. If it is not the
+right colour for you, simply change the font
+colour on your terminal
+.SH OPTIONS
+The
+.B cp
+utility shall conform to the Base Definitions
+volume of POSIX.1-2008,
+.IR "Section 12.2, Utility Syntax Guidelines" .
+.PP
+The following options shall be supported:
+.TP
+.B -e
+Exit with status 0 when the timer reaches 0.
+If not specified, the timer will continue
+into negative times but with a red font.
+.SH "SEE ALSO"
+.BR mongoclock (1)
+.BR watch (1)
+.SH AUTHORS
+Mattias Andrée
+.RI < maandree@kth.se >
diff --git a/mongotimer.c b/mongotimer.c
new file mode 100644
index 0000000..692d7a2
--- /dev/null
+++ b/mongotimer.c
@@ -0,0 +1,342 @@
+/* See LICENSE file for copyright and license details. */
+#include <sys/ioctl.h>
+#include <sys/timerfd.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "arg.h"
+
+#define DX 16
+#define DY 12
+#define DC 16
+#define DM 16
+
+#include "mongo_0.h"
+#include "mongo_1.h"
+#include "mongo_2.h"
+#include "mongo_3.h"
+#include "mongo_4.h"
+#include "mongo_5.h"
+#include "mongo_6.h"
+#include "mongo_7.h"
+#include "mongo_8.h"
+#include "mongo_9.h"
+#include "mongo_c.h"
+#include "mongo_m.h"
+
+static const char **mongo_ds[] = {
+ mongo_0, mongo_1, mongo_2, mongo_3, mongo_4,
+ mongo_5, mongo_6, mongo_7, mongo_8, mongo_9
+};
+
+static volatile sig_atomic_t caught_sigterm = 0;
+static volatile sig_atomic_t caught_sigwinch = 1;
+
+char *argv0;
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: %s [[-e] [[hh]:mm:]ss]\n", argv0);
+ exit(1);
+}
+
+static void
+sigterm(int signo)
+{
+ caught_sigterm = 1;
+ (void) signo;
+}
+
+static void
+sigwinch(int signo)
+{
+ caught_sigwinch = 1;
+ (void) signo;
+}
+
+static void
+print_time(const char ***str, size_t y, size_t x)
+{
+ size_t r, c;
+
+ fprintf(stdout, "\033[%zu;1H\033[1J", y + 1);
+
+ for (r = 0; r < DY; r++) {
+ fprintf(stdout, "\033[%zu;%zuH\033[1K", y + r + 1, x + 1);
+ for (c = 0; str[c]; c++)
+ fprintf(stdout, "%s", str[c][r]);
+ fprintf(stdout, "\033[0K");
+ }
+
+ fprintf(stdout, "\033[0J");
+ fflush(stdout);
+}
+
+static int
+display_stopwatch(int timerfd)
+{
+ uint64_t overrun, total_overrun = 0;
+ struct winsize winsize;
+ size_t x = 0, y = 0, width, i;
+ const char **digits[23];
+ uint64_t h, m, s, h_div = 1, th;
+ size_t h_digits = 0;
+ int small = 0;
+
+ /* TODO pause (yellow text) on <space> */
+
+ while (!caught_sigterm) {
+ if (caught_sigwinch) {
+ if (ioctl(STDOUT_FILENO, (unsigned long)TIOCGWINSZ, &winsize) < 0) {
+ if (errno == EINTR)
+ continue;
+ goto fail;
+ }
+ caught_sigwinch = 0;
+ recenter:
+ y = winsize.ws_row;
+ x = winsize.ws_col;
+ width = 4 * DX + DC;
+ if (h_digits) {
+ width += DC;
+ width += h_digits * DX;
+ }
+ if (y < DY) small = 1;
+ else if (x < width) small = 1;
+ else small = 0;
+ y -= DY;
+ x -= width;
+ y /= 2;
+ x /= 2;
+ }
+
+ if (small) {
+ fprintf(stdout, "\033[H\033[2J%s\n", "Screen is too small");
+ fflush(stdout);
+ pause();
+ continue;
+ }
+
+ s = total_overrun % 60;
+ m = total_overrun / 60 % 60;
+ h = total_overrun / 60 / 60;
+ if (h / h_div) {
+ h_div *= 10;
+ h_digits++;
+ goto recenter;
+ }
+
+ i = 0;
+ if (h_digits) {
+ for (th = h; th; th /= 10)
+ digits[h_digits - ++i] = mongo_ds[th % 10];
+ digits[i++] = mongo_c;
+ }
+ digits[i++] = mongo_ds[m / 10];
+ digits[i++] = mongo_ds[m % 10];
+ digits[i++] = mongo_c;
+ digits[i++] = mongo_ds[s / 10];
+ digits[i++] = mongo_ds[s % 10];
+ digits[i++] = NULL;
+
+ print_time(digits, y, x);
+
+ if (read(timerfd, &overrun, sizeof(overrun)) < 0) {
+ if (errno != EINTR)
+ goto fail;
+ } else {
+ total_overrun += overrun;
+ }
+ }
+
+ return 0;
+
+fail:
+ return -1;
+}
+
+static int
+display_timer(int timerfd, int64_t time, int exit_on_zero)
+{
+ uint64_t overrun, abstime;
+ struct winsize winsize;
+ size_t x = 0, y = 0, width;
+ const char **digits[24];
+ uint64_t h, m, s, th, h_div;
+ size_t h_digits, i;
+ int small = 0;
+
+ /* TODO pause (yellow text) on <space> */
+
+ while (!caught_sigterm) {
+ if (caught_sigwinch) {
+ if (ioctl(STDOUT_FILENO, (unsigned long)TIOCGWINSZ, &winsize) < 0) {
+ if (errno == EINTR)
+ continue;
+ goto fail;
+ }
+ caught_sigwinch = 0;
+ }
+
+ abstime = time < 0 ? (uint64_t)-time : (uint64_t)time;
+ s = abstime % 60;
+ m = abstime / 60 % 60;
+ h = abstime / 60 / 60;
+
+ y = winsize.ws_row;
+ x = winsize.ws_col;
+ for (h_div = 1, h_digits = 0; h / h_div; h_div *= 10, h_digits += 1);
+ width = 4 * DX + DC;
+ if (time < 0)
+ width += DM;
+ if (h_digits)
+ width += h_digits * DX + DC;
+ if (y < DY) small = 1;
+ else if (x < width) small = 1;
+ else small = 0;
+ y -= DY;
+ x -= width;
+ y /= 2;
+ x /= 2;
+
+ if (small) {
+ fprintf(stdout, "\033[H\033[2J%s\n", "Screen is too small");
+ fflush(stdout);
+ pause();
+ continue;
+ }
+
+ i = 0;
+ if (time < 0)
+ digits[i++] = mongo_m;
+ if (h_digits) {
+ for (th = h; th; th /= 10)
+ digits[h_digits - ++i] = mongo_ds[th % 10];
+ digits[i++] = mongo_c;
+ }
+ digits[i++] = mongo_ds[m / 10];
+ digits[i++] = mongo_ds[m % 10];
+ digits[i++] = mongo_c;
+ digits[i++] = mongo_ds[s / 10];
+ digits[i++] = mongo_ds[s % 10];
+ digits[i++] = NULL;
+
+ if (time >= 0) {
+ print_time(digits, y, x);
+ } else {
+ fprintf(stdout, "\033[31m\n");
+ print_time(digits, y, x);
+ fprintf(stdout, "\033[39m\n");
+ }
+
+ if (read(timerfd, &overrun, sizeof(overrun)) < 0) {
+ if (errno != EINTR)
+ goto fail;
+ } else {
+ time -= (int64_t)overrun;
+ if (time <= 0 && exit_on_zero)
+ break;
+ }
+ }
+
+ if (caught_sigterm && exit_on_zero)
+ return -1;
+
+ return 0;
+
+fail:
+ return -1;
+}
+
+int
+main(int argc, char *argv[])
+{
+ int timerfd = -1;
+ int exit_on_zero = 0;
+ struct itimerspec itimerspec;
+ struct sigaction sigact;
+ int64_t time = 0, t = 0;
+ size_t colons = 0;
+ char *s;
+
+ ARGBEGIN {
+ case 'e':
+ exit_on_zero = 1;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if (argc > 1 || (exit_on_zero && !argc))
+ usage();
+
+ fprintf(stdout, "\033[?1049h\033[?25l");
+
+ itimerspec.it_interval.tv_sec = 1;
+ itimerspec.it_interval.tv_nsec = 0;
+ itimerspec.it_value.tv_sec = 1;
+ itimerspec.it_value.tv_nsec = 0;
+ timerfd = timerfd_create(CLOCK_BOOTTIME, 0);
+ if (timerfd < 0)
+ goto fail;
+ if (timerfd_settime(timerfd, 0, &itimerspec, NULL))
+ goto fail;
+
+ memset(&sigact, 0, sizeof(sigact));
+
+ sigact.sa_handler = sigterm;
+ sigaction(SIGTERM, &sigact, NULL);
+ sigaction(SIGQUIT, &sigact, NULL);
+ sigaction(SIGINT, &sigact, NULL);
+
+ sigact.sa_handler = sigwinch;
+ sigaction(SIGWINCH, &sigact, NULL);
+
+ if (argc) {
+ for (s = argv[0]; *s; s++) {
+ if ('0' <= *s && *s <= '9') {
+ t = t * 10 + (*s & 15);
+ } else if (*s == ':' && colons++ < 2) {
+ if (s == argv[0] || s[-1] == ':')
+ goto fail_usage;
+ time = (time + t) * 60;
+ t = 0;
+ } else {
+ goto fail_usage;
+ }
+ }
+ if (s == argv[0] || s[-1] == ':')
+ goto fail_usage;
+ time += t;
+ if (display_timer(timerfd, time, exit_on_zero))
+ goto fail;
+ } else {
+ if (display_stopwatch(timerfd))
+ goto fail;
+ }
+
+ fprintf(stdout, "\033[?25h\n\033[?1049l");
+ fflush(stdout);
+ close(timerfd);
+ return 0;
+
+fail:
+ perror(argv0 ? argv0 : "mongotimer");
+ fprintf(stdout, "\033[?25h\n\033[?1049l");
+ fflush(stdout);
+ if (timerfd >= 0)
+ close(timerfd);
+ return 1;
+
+fail_usage:
+ fprintf(stdout, "\033[?25h\n\033[?1049l");
+ fflush(stdout);
+ usage();
+}