summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--clock.c5
-rw-r--r--counter.c5
-rwxr-xr-xlarge.sh25
-rw-r--r--stopwatch.c10
-rw-r--r--timer.c362
6 files changed, 400 insertions, 10 deletions
diff --git a/Makefile b/Makefile
index 6ff3e18..5515f77 100644
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,8 @@ BIN_ =\
clock\
counter\
dice\
- stopwatch
+ stopwatch\
+ timer
OBJ =\
common.o\
diff --git a/clock.c b/clock.c
index c3040f4..846854d 100644
--- a/clock.c
+++ b/clock.c
@@ -246,6 +246,7 @@ int
main(int argc, char *argv[])
{
int timerfd = -1, tcset = 0, old_flags = -1, old_sig = 0, owner_set = 0;
+ int saved_errno;
struct itimerspec itimerspec;
struct sigaction sigact;
struct termios stty, saved_stty;
@@ -338,9 +339,11 @@ main(int argc, char *argv[])
return 0;
fail:
- perror(argv0 ? argv0 : "clock");
+ saved_errno = errno;
fprintf(stdout, "\033[?25h\n\033[?1049l");
fflush(stdout);
+ errno = saved_errno;
+ perror(argv0 ? argv0 : "clock");
if (owner_set)
fcntl(STDIN_FILENO, F_SETOWN_EX, &old_owner);
if (old_flags != -1)
diff --git a/counter.c b/counter.c
index f7bada6..1b8f637 100644
--- a/counter.c
+++ b/counter.c
@@ -174,6 +174,7 @@ int
main(int argc, char *argv[])
{
int tcset = 0, old_flags = -1, old_sig = 0, owner_set = 0;
+ int saved_errno;
struct sigaction sigact;
struct termios stty, saved_stty;
struct f_owner_ex old_owner, new_owner;
@@ -241,9 +242,11 @@ main(int argc, char *argv[])
return 0;
fail:
- perror(argv0 ? argv0 : "counter");
+ saved_errno = errno;
fprintf(stdout, "\033[?25h\n\033[?1049l");
fflush(stdout);
+ errno = saved_errno;
+ perror(argv0 ? argv0 : "counter");
if (owner_set)
fcntl(STDIN_FILENO, F_SETOWN_EX, &old_owner);
if (old_flags != -1)
diff --git a/large.sh b/large.sh
index e1d2a22..3b35d3d 100755
--- a/large.sh
+++ b/large.sh
@@ -121,6 +121,17 @@ large_colon() {
' '
}
+large_dot() {
+ printf '%s\n' \
+ ' ' \
+ ' ' \
+ ' ' \
+ ' ' \
+ ' ' \
+ ' ' \
+ ' [] '
+}
+
large_minus() {
printf '%s\n' \
' ' \
@@ -133,24 +144,28 @@ large_minus() {
}
printf '#define LARGE_Y %i\n' $(large_0 | wc -l)
-printf '#define LARGE_X %i\n' $(large_0 | head -n 1 | tr -d '\n' | wc -c)
+printf '#define LARGE_X %i\n' $(large_0 | head -n 1 | tr -d '\n' | wc -c)
printf '#define LARGE_XC %i\n' $(large_colon | head -n 1 | tr -d '\n' | wc -c)
+printf '#define LARGE_XD %i\n' $(large_dot | head -n 1 | tr -d '\n' | wc -c)
printf '#define LARGE_XM %i\n' $(large_minus | head -n 1 | tr -d '\n' | wc -c)
printf '#define SMALL_Y %i\n' $(expr \( $(large_0 | wc -l) + 1 \) / 2)
-printf '#define SMALL_X %i\n' $(expr \( $(large_0 | head -n 1 | tr -d '\n' | wc -c) + 1 \) / 2)
+printf '#define SMALL_X %i\n' $(expr \( $(large_0 | head -n 1 | tr -d '\n' | wc -c) + 1 \) / 2)
printf '#define SMALL_XC %i\n' $(expr \( $(large_colon | head -n 1 | tr -d '\n' | wc -c) + 1 \) / 2)
+printf '#define SMALL_XD %i\n' $(expr \( $(large_dot | head -n 1 | tr -d '\n' | wc -c) + 1 \) / 2)
printf '#define SMALL_XM %i\n' $(expr \( $(large_minus | head -n 1 | tr -d '\n' | wc -c) + 1 \) / 2)
-for c in 0 1 2 3 4 5 6 7 8 9 colon minus; do
+for c in 0 1 2 3 4 5 6 7 8 9 colon dot minus; do
if test $c = colon; then
printf '%s\n' '#ifdef INCLUDE_LARGE_COLON'
+ elif test $c = dot; then
+ printf '%s\n' '#ifdef INCLUDE_LARGE_DOT'
elif test $c = minus; then
printf '%s\n' '#ifdef INCLUDE_LARGE_MINUS'
fi
printf 'static const char *large_%s[] = {\n' $c
large_$c | \
- 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'
@@ -209,7 +224,7 @@ for c in 0 1 2 3 4 5 6 7 8 9 colon minus; do
printf '\n'
done | sed -e 's/^/"/' -e 's/$/",/' | sed '$s/,$//'
printf '};\n'
- if test $c = colon || test $c = minus; then
+ if test $c = colon || test $c = dot || test $c = minus; then
printf '%s\n' '#endif'
fi
done
diff --git a/stopwatch.c b/stopwatch.c
index 5bfa69c..dcb36dd 100644
--- a/stopwatch.c
+++ b/stopwatch.c
@@ -142,6 +142,7 @@ int
main(int argc, char *argv[])
{
int timerfd = -1, old_flags = -1, tcset = 0, old_sig = 0;
+ int saved_errno;
struct sigaction sigact;
int64_t owner_set = 0;
struct f_owner_ex old_owner, new_owner;
@@ -218,9 +219,14 @@ main(int argc, char *argv[])
return 0;
fail:
- printf("\033[?25h\n");
- perror(argv0 ? argv0 : "stopwatch");
+ saved_errno = errno;
+ if (quadsize)
+ printf("\n\n\033#5\033[?25h");
+ else
+ printf("\033[?25h\n");
fflush(stdout);
+ errno = saved_errno;
+ perror(argv0 ? argv0 : "stopwatch");
if (owner_set)
fcntl(STDIN_FILENO, F_SETOWN_EX, &old_owner);
if (old_flags != -1)
diff --git a/timer.c b/timer.c
new file mode 100644
index 0000000..4a6b051
--- /dev/null
+++ b/timer.c
@@ -0,0 +1,362 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+/* TODO add support for in application entering of time */
+/* TODO add support for rat input */
+/* TODO add support for audible alert */
+/* TODO add support for vibration alert */
+/* TODO add support for flash/led/screen alert */
+/* TODO add support for messages */
+/* TODO add support for multiple timers */
+/* TODO add support for CLOCK_BOOTTIME_ALARM */
+/* TODO add support for ptuting timer in the background */
+
+USAGE("[-2s] [[hours:]minutes:]second[.deciseconds]");
+
+
+#define INCLUDE_LARGE_COLON
+#define INCLUDE_LARGE_DOT
+#define INCLUDE_LARGE_MINUS
+#include "large.h"
+
+
+static volatile sig_atomic_t caught_sigterm = 0;
+static volatile sig_atomic_t caught_sigwinch = 1;
+static volatile sig_atomic_t caught_sigio = 1;
+static struct itimerspec orig_time;
+static int64_t initial = 0;
+static int with_small = 0;
+static int with_quad = 0;
+
+static const char **large_digits[] = {
+ large_0, large_1, large_2, large_3, large_4,
+ large_5, large_6, large_7, large_8, large_9
+};
+
+static const char **small_digits[] = {
+ small_0, small_1, small_2, small_3, small_4,
+ small_5, small_6, small_7, small_8, small_9
+};
+
+
+
+static void
+sigterm(int signo)
+{
+ caught_sigterm = 1;
+ (void) signo;
+}
+
+static void
+sigwinch(int signo)
+{
+ caught_sigwinch = 1;
+ (void) signo;
+}
+
+static void
+sigio(int signo)
+{
+ caught_sigio = 1;
+ (void) signo;
+}
+
+
+static void
+print_time(const char ***str, int left, size_t height)
+{
+ size_t r, c;
+
+ for (r = 0;;) {
+ printf("%*.s", left, "");
+ for (c = 0; str[c]; c++)
+ fprintf(stdout, "%s", str[c][r]);
+ if (++r == height) {
+ fprintf(stdout, "\033[K");
+ break;
+ } else {
+ fprintf(stdout, "\033[K\n");
+ }
+ }
+}
+
+
+static int
+display_timer(int timerfd)
+{
+ const char **digits[sizeof(int64_t) * 3 + sizeof("-:00:00.0")];
+ char buffer[sizeof(int64_t) * 3 + sizeof("-:00:00.0")];
+ int r, x = 0, y = 0, was_quad = 0, paused = 0, large_width, small_width, len, neg;
+ int64_t overrun, now = initial, h, m, s, ds;
+ struct itimerspec zero_time, old_time;
+ struct winsize winsize;
+ char c;
+ ssize_t rd;
+ size_t i;
+
+ memset(&zero_time, 0, sizeof(zero_time));
+
+ 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 (was_quad) {
+ was_quad = 0;
+ for (r = 0; r < y; r++)
+ printf("%s\033#5", r ? "\n" : "\033[H");
+ }
+ }
+
+ if (caught_sigio) {
+ caught_sigio = 0;
+ for (;;) {
+ rd = read(STDIN_FILENO, &c, 1);
+ if (rd <= 0) {
+ if (!rd)
+ goto out;
+ if (errno == EAGAIN)
+ break;
+ if (errno == EINTR)
+ continue;
+ goto fail;
+ }
+ if (c == 'q') {
+ goto out;
+ } else if (c == 'r') {
+ now = initial;
+ if (paused)
+ memcpy(&old_time, &orig_time, sizeof(orig_time));
+ else if (timerfd_settime(timerfd, 0, &orig_time, NULL))
+ goto fail;
+ } else if (c == ' ' || c == 'p') {
+ paused ^= 1;
+ if (paused) {
+ if (timerfd_settime(timerfd, 0, &zero_time, &old_time))
+ goto fail;
+ } else {
+ if (timerfd_settime(timerfd, 0, &old_time, NULL))
+ goto fail;
+ }
+ }
+ }
+ }
+
+ neg = now < 0;
+ ds = neg ? -now : now;
+ s = ds / 10;
+ ds %= 10;
+ m = s / 60;
+ s %= 60;
+ h = m / 60;
+ m %= 60;
+
+ if (h)
+ len = sprintf(buffer, "%s%02ji:%02ji:%02ji.%ji", neg ? "-" : "", h, m, s, ds);
+ else
+ len = sprintf(buffer, "%s%02ji:%02ji.%ji", neg ? "-" : "", m, s, ds);
+
+ large_width = neg * LARGE_XM + (1 + (h > 0)) * LARGE_XC + LARGE_XD + (len - neg - 2 - (h > 0)) * LARGE_X;
+ small_width = neg * SMALL_XM + (1 + (h > 0)) * SMALL_XC + SMALL_XD + (len - neg - 2 - (h > 0)) * SMALL_X;
+
+ printf("\033[H");
+ if (paused)
+ printf("\033[33m");
+ else if (neg)
+ printf("\033[31m");
+
+ if (x >= large_width && y >= LARGE_Y + paused) {
+ for (i = 0; buffer[i]; i++) {
+ if (buffer[i] == '-')
+ digits[i] = large_minus;
+ else if (buffer[i] == ':')
+ digits[i] = large_colon;
+ else if (buffer[i] == '.')
+ digits[i] = large_dot;
+ else
+ digits[i] = large_digits[buffer[i] & 15];
+ }
+ digits[i] = NULL;
+ print_time(digits, (x - large_width) / 2, LARGE_Y);
+ } else if (with_small && x >= small_width && y >= SMALL_Y + paused) {
+ for (i = 0; buffer[i]; i++) {
+ if (buffer[i] == '-')
+ digits[i] = small_minus;
+ else if (buffer[i] == ':')
+ digits[i] = small_colon;
+ else if (buffer[i] == '.')
+ digits[i] = small_dot;
+ else
+ digits[i] = small_digits[buffer[i] & 15];
+ }
+ digits[i] = NULL;
+ print_time(digits, (x - small_width) / 2, SMALL_Y);
+ } else if (with_quad && x > 8 * 2 && y > 2) {
+ printf("\033#3%*.s%s\033[K\n", (x / 2 - len) / 2, "", buffer);
+ printf("\033#4%*.s%s\033[K\n", (x / 2 - len) / 2, "", buffer);
+ printf("\033#5");
+ if (paused)
+ printf("%*.s(paused)\033[K", (x - 8) / 2, "");
+ was_quad = 1;
+ goto paused_printed;
+ } else {
+ printf("%*.s%s\033[K", (x - len) / 2, "", buffer);
+ }
+ if (paused)
+ printf("\n%*.s(paused)\033[K", (x - 8) / 2, "");
+ paused_printed:
+
+ if (paused || neg)
+ printf("\033[m");
+ printf("\033[J");
+ fflush(stdout);
+
+ if (read(timerfd, &overrun, sizeof(overrun)) < 0) {
+ if (errno != EINTR)
+ goto fail;
+ } else {
+ now -= overrun;
+ }
+ }
+
+out:
+ return 0;
+
+fail:
+ return -1;
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ int timerfd = -1, tcset = 0, old_flags = -1, old_sig = 0, owner_set = 0;
+ int saved_errno, colons = 0, dots = 0;
+ int64_t part = 0;
+ struct sigaction sigact;
+ struct termios stty, saved_stty;
+ struct f_owner_ex old_owner, new_owner;
+ char *p;
+
+ ARGBEGIN {
+ case '2':
+ with_quad = 1;
+ break;
+ case 's':
+ with_small = 1;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if (argc != 1)
+ usage();
+
+ if (!isdigit(argv[0][0]))
+ usage();
+ for (p = argv[0]; *p; p++) {
+ if (isdigit(*p)) {
+ part *= 10;
+ part += (int64_t)(*p & 15);
+ } else if (*p == ':') {
+ if (dots || ++colons > 2 || !isdigit(p[1]))
+ usage();
+ initial += part;
+ initial *= 60;
+ part = 0;
+ } else if (*p == '.') {
+ if (dots++ || !isdigit(p[1]) || p[2])
+ usage();
+ initial += part;
+ initial *= 10;
+ part = 0;
+ } else {
+ usage();
+ }
+ }
+ initial += part;
+ if (!dots)
+ initial *= 10;
+
+ fprintf(stdout, "\033[?1049h\033[?25l");
+
+ orig_time.it_interval.tv_sec = 0;
+ orig_time.it_interval.tv_nsec = 100000000L;
+ orig_time.it_value.tv_sec = 0;
+ orig_time.it_value.tv_nsec = 100000000L;
+ timerfd = timerfd_create(CLOCK_BOOTTIME, 0);
+ if (timerfd < 0)
+ goto fail;
+ if (timerfd_settime(timerfd, 0, &orig_time, 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);
+
+ sigact.sa_handler = sigio;
+ sigaction(SIGIO, &sigact, NULL);
+ sigaction(SIGURG, &sigact, NULL);
+
+ if (fcntl(STDIN_FILENO, F_GETOWN_EX, &old_owner))
+ goto fail;
+ memset(&new_owner, 0, sizeof(new_owner));
+ new_owner.type = F_OWNER_PID;
+ new_owner.pid = getpid();
+ if (fcntl(STDIN_FILENO, F_SETOWN_EX, &new_owner))
+ goto fail;
+ owner_set = 1;
+ old_flags = fcntl(STDIN_FILENO, F_GETFL);
+ fcntl(STDIN_FILENO, F_SETFL, old_flags | FASYNC | O_NONBLOCK);
+ fcntl(STDIN_FILENO, F_GETSIG, &old_sig);
+ if (old_sig)
+ fcntl(STDIN_FILENO, F_SETSIG, 0);
+
+ if (!tcgetattr(STDIN_FILENO, &stty)) {
+ saved_stty = stty;
+ stty.c_lflag &= (tcflag_t)~(ECHO | ICANON);
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &stty);
+ tcset = 1;
+ }
+
+ if (display_timer(timerfd))
+ goto fail;
+
+ fprintf(stdout, "\033[?25h\n\033[?1049l");
+ fflush(stdout);
+ close(timerfd);
+ fcntl(STDIN_FILENO, F_SETOWN_EX, &old_owner);
+ fcntl(STDIN_FILENO, F_SETFL, old_flags);
+ fcntl(STDIN_FILENO, F_SETSIG, old_sig);
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_stty);
+ return 0;
+
+fail:
+ saved_errno = errno;
+ fprintf(stdout, "\033[?25h\n\033[?1049l");
+ fflush(stdout);
+ errno = saved_errno;
+ perror(argv0 ? argv0 : "timer");
+ if (owner_set)
+ fcntl(STDIN_FILENO, F_SETOWN_EX, &old_owner);
+ if (old_flags != -1)
+ fcntl(STDIN_FILENO, F_SETFL, old_flags);
+ if (old_sig)
+ fcntl(STDIN_FILENO, F_SETSIG, old_sig);
+ if (tcset)
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_stty);
+ if (timerfd >= 0)
+ close(timerfd);
+ return 1;
+}