git: 71ed1adda83d - main - grdc: add countdown timer mode

From: Warner Losh <imp_at_FreeBSD.org>
Date: Fri, 10 May 2024 15:25:26 UTC
The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=71ed1adda83dfaa5d1a2482341b47bd7919498e3

commit 71ed1adda83dfaa5d1a2482341b47bd7919498e3
Author:     Gavin Atkinson <gavin@FreeBSD.org>
AuthorDate: 2024-05-10 15:22:38 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2024-05-10 15:22:38 +0000

    grdc: add countdown timer mode
    
    PR: 35113
    Differential Revision:  https://reviews.freebsd.org/D43463
---
 usr.bin/grdc/grdc.6 | 19 +++++++++++-
 usr.bin/grdc/grdc.c | 83 ++++++++++++++++++++++++++++++++++-------------------
 2 files changed, 71 insertions(+), 31 deletions(-)

diff --git a/usr.bin/grdc/grdc.6 b/usr.bin/grdc/grdc.6
index 3c9660055e2b..7420c8ecbe8b 100644
--- a/usr.bin/grdc/grdc.6
+++ b/usr.bin/grdc/grdc.6
@@ -1,4 +1,4 @@
-.Dd September 25, 2001
+.Dd January 15, 2023
 .Dt GRDC 6
 .Os
 .Sh NAME
@@ -8,6 +8,9 @@
 .Nm
 .Op Fl st
 .Op Ar n
+.Nm
+.Fl c
+.Ar n
 .Sh DESCRIPTION
 .Nm
 runs a digital clock made of reverse-video blanks on a curses
@@ -17,6 +20,11 @@ With an optional numeric argument
 it stops after
 .Ar n
 seconds (default never).
+The clock can act as a countdown timer with the
+.Fl c
+flag,
+.Ar n
+specifies the number of seconds to time for.
 The optional
 .Fl s
 flag makes digits scroll as they change.
@@ -37,8 +45,17 @@ for more information.
 If this variable is not set, the time zone is determined based on
 .Pa /etc/localtime .
 .El
+.Sh NOTES
+In countdown timer mode, the specifying of
+.Fl n
+> 360000 seconds (100 hours) will lead to the counter displaying
+incorrect remaining time, however it will time correctly, and
+display correctly when the remaining time becomes less than
+100 hours.
 .Sh AUTHORS
 .An -nosplit
 .An Amos Shapir ,
 modified for curses by
 .An John Lupien .
+Countdown timer mode by
+.An Gavin Atkinson .
diff --git a/usr.bin/grdc/grdc.c b/usr.bin/grdc/grdc.c
index e2a694ebc461..07d12f5a7fb0 100644
--- a/usr.bin/grdc/grdc.c
+++ b/usr.bin/grdc/grdc.c
@@ -1,12 +1,15 @@
 /*
  * Grand digital clock for curses compatible terminals
  * Usage: grdc [-st] [n]   -- run for n seconds (default infinity)
- * Flags: -s: scroll
+ *        grdc -c n        -- countdown n seconds
+ * Flags: -c: Countdown timer mode
+ *        -s: scroll
  *        -t: output time in 12-hour format
  *
  *
  * modified 10-18-89 for curses (jrl)
  * 10-18-89 added signal handling
+ * 02-18-02 added countdown timer mode
  *
  * modified 03-25-03 for 12 hour option
  *     - Samy Al Bahra <samy@kerneled.com>
@@ -26,6 +29,7 @@
 
 static struct timespec now;
 static struct tm *tm;
+static struct timespec end;
 
 static short disp[11] = {
 	075557, 011111, 071747, 071717, 055711,
@@ -59,18 +63,19 @@ main(int argc, char *argv[])
 	int i, j, s, k;
 	int n;
 	int ch;
-	int scrol;
-	int t12;
+	bool scrol = false, t12 = false, timer = false;
+	int hour, minute, second;
 
-	t12 = scrol = 0;
-
-	while ((ch = getopt(argc, argv, "ts")) != -1)
+	while ((ch = getopt(argc, argv, "cst")) != -1)
 	switch (ch) {
+	case 'c':
+		timer = true;
+		break;
 	case 's':
-		scrol = 1;
+		scrol = true;
 		break;
 	case 't':
-		t12 = 1;
+		t12 = true;
 		break;
 	case '?':
 	default:
@@ -80,7 +85,7 @@ main(int argc, char *argv[])
 	argc -= optind;
 	argv += optind;
 
-	if (argc > 1) {
+	if ((argc > 1) || (argc == 0 && timer)) {
 		usage();
 		/* NOTREACHED */
 	}
@@ -95,6 +100,9 @@ main(int argc, char *argv[])
 	} else
 		n = 0;
 
+	if (timer && n == 0)
+		return(0);
+
 	initscr();
 
 	signal(SIGINT,sighndl);
@@ -107,7 +115,7 @@ main(int argc, char *argv[])
 
 	hascolor = has_colors();
 
-	if(hascolor) {
+	if (hascolor) {
 		start_color();
 		init_pair(1, COLOR_BLACK, COLOR_RED);
 		init_pair(2, COLOR_RED, COLOR_BLACK);
@@ -118,7 +126,7 @@ main(int argc, char *argv[])
 	clear();
 	refresh();
 
-	if(hascolor) {
+	if (hascolor) {
 		attrset(COLOR_PAIR(3));
 
 		mvaddch(YBASE - 2,  XBASE - 3, ACS_ULCORNER);
@@ -139,28 +147,42 @@ main(int argc, char *argv[])
 	}
 	clock_gettime(CLOCK_REALTIME_FAST, &now);
 	prev_sec = now.tv_sec;
+	if (timer) {
+		end = now;
+		end.tv_sec += n;
+	}
 	do {
 		mask = 0;
-		tm = localtime(&now.tv_sec);
-		set(tm->tm_sec%10, 0);
-		set(tm->tm_sec/10, 4);
-		set(tm->tm_min%10, 10);
-		set(tm->tm_min/10, 14);
-
-		if (t12) {
-			if (tm->tm_hour < 12) {
-				if (tm->tm_hour == 0)
-					tm->tm_hour = 12;
-				mvaddstr(YBASE + 5, XBASE + 52, "AM");
-			} else {
-				if (tm->tm_hour > 12)
-					tm->tm_hour -= 12;
-				mvaddstr(YBASE + 5, XBASE + 52, "PM");
+		if (!timer) {
+			tm = localtime(&now.tv_sec);
+			if (t12) {
+				if (tm->tm_hour < 12) {
+					if (tm->tm_hour == 0)
+						tm->tm_hour = 12;
+					mvaddstr(YBASE + 5, XBASE + 52, "AM");
+				} else {
+					if (tm->tm_hour > 12)
+						tm->tm_hour -= 12;
+					mvaddstr(YBASE + 5, XBASE + 52, "PM");
+				}
 			}
+			hour = tm->tm_hour;
+			minute = tm->tm_min;
+			second = tm->tm_sec;
+		} else {
+			n = end.tv_sec - now.tv_sec;
+			if (n <= 0)
+				break;
+			hour = (n / 3600) % 100;
+			minute = (n / 60) % 60;
+			second = n % 60;
 		}
-
-		set(tm->tm_hour%10, 20);
-		set(tm->tm_hour/10, 24);
+		set(second % 10, 0);
+		set(second / 10, 4);
+		set(minute % 10, 10);
+		set(minute / 10, 14);
+		set(hour % 10, 20);
+		set(hour / 10, 24);
 		set(10, 7);
 		set(10, 17);
 		for(k=0; k<6; k++) {
@@ -266,6 +288,7 @@ static void
 usage(void)
 {
 
-	(void)fprintf(stderr, "usage: grdc [-st] [n]\n");
+	(void)fprintf(stderr, "usage: grdc [-st] [n]\n"
+	    "      grdc -c n\n");
 	exit(1);
 }