diff --git a/usr.bin/grdc/grdc.6 b/usr.bin/grdc/grdc.6 index 4af2cab53517..7420c8ecbe8b 100644 --- a/usr.bin/grdc/grdc.6 +++ b/usr.bin/grdc/grdc.6 @@ -1,66 +1,61 @@ -.\" SPDX-License-Identifier: BSD-3-Clause -.\" -.\" Copyright 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994 -.\" The Regents of the University of California. All rights reserved. -.\" .Dd January 15, 2023 .Dt GRDC 6 .Os .Sh NAME .Nm grdc .Nd grand digital clock (curses) .Sh SYNOPSIS .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 compatible VDU screen. With an optional numeric argument .Ar n 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. The optional .Fl t flag tells grdc to output the time in a 12-hour format. In this curses mode implementation, the scrolling option has trouble keeping up. .Sh ENVIRONMENT .Bl -tag -width Ds .It Ev TZ The time zone to use for displaying the time. It is normally specified as a pathname relative to .Pa /usr/share/zoneinfo , though see .Xr tzset 3 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 f9e5a9e36bba..07d12f5a7fb0 100644 --- a/usr.bin/grdc/grdc.c +++ b/usr.bin/grdc/grdc.c @@ -1,301 +1,294 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - */ - /* * Grand digital clock for curses compatible terminals * Usage: grdc [-st] [n] -- run for n seconds (default infinity) * 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 */ #include #include #include #include #include #include #define YBASE 10 #define XBASE 10 #define XLENGTH 58 #define YDEPTH 7 static struct timespec now; static struct tm *tm; static struct timespec end; static short disp[11] = { 075557, 011111, 071747, 071717, 055711, 074717, 074757, 071111, 075757, 075717, 002020 }; static long old[6], next[6], new[6], mask; static volatile sig_atomic_t sigtermed; static int hascolor = 0; static void set(int, int); static void standt(int); static void movto(int, int); static void sighndl(int); static void usage(void) __dead2; static void sighndl(int signo) { sigtermed = signo; } int main(int argc, char *argv[]) { struct timespec delay; time_t prev_sec; long t, a; int i, j, s, k; int n; int ch; bool scrol = false, t12 = false, timer = false; int hour, minute, second; while ((ch = getopt(argc, argv, "cst")) != -1) switch (ch) { case 'c': timer = true; break; case 's': scrol = true; break; case 't': t12 = true; break; case '?': default: usage(); /* NOTREACHED */ } argc -= optind; argv += optind; if ((argc > 1) || (argc == 0 && timer)) { usage(); /* NOTREACHED */ } if (argc > 0) { n = atoi(*argv) + 1; if (n < 1) { warnx("number of seconds is out of range"); usage(); /* NOTREACHED */ } } else n = 0; if (timer && n == 0) return(0); initscr(); signal(SIGINT,sighndl); signal(SIGTERM,sighndl); signal(SIGHUP,sighndl); cbreak(); noecho(); curs_set(0); hascolor = has_colors(); if (hascolor) { start_color(); init_pair(1, COLOR_BLACK, COLOR_RED); init_pair(2, COLOR_RED, COLOR_BLACK); init_pair(3, COLOR_WHITE, COLOR_BLACK); attrset(COLOR_PAIR(2)); } clear(); refresh(); if (hascolor) { attrset(COLOR_PAIR(3)); mvaddch(YBASE - 2, XBASE - 3, ACS_ULCORNER); hline(ACS_HLINE, XLENGTH); mvaddch(YBASE - 2, XBASE - 2 + XLENGTH, ACS_URCORNER); mvaddch(YBASE + YDEPTH - 1, XBASE - 3, ACS_LLCORNER); hline(ACS_HLINE, XLENGTH); mvaddch(YBASE + YDEPTH - 1, XBASE - 2 + XLENGTH, ACS_LRCORNER); move(YBASE - 1, XBASE - 3); vline(ACS_VLINE, YDEPTH); move(YBASE - 1, XBASE - 2 + XLENGTH); vline(ACS_VLINE, YDEPTH); attrset(COLOR_PAIR(2)); } clock_gettime(CLOCK_REALTIME_FAST, &now); prev_sec = now.tv_sec; if (timer) { end = now; end.tv_sec += n; } do { mask = 0; 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(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++) { if(scrol) { for(i=0; i<5; i++) new[i] = (new[i]&~mask) | (new[i+1]&mask); new[5] = (new[5]&~mask) | (next[k]&mask); } else new[k] = (new[k]&~mask) | (next[k]&mask); next[k] = 0; for(s=1; s>=0; s--) { standt(s); for(i=0; i<6; i++) { if((a = (new[i]^old[i])&(s ? new : old)[i]) != 0) { for(j=0,t=1<<26; t; t>>=1,j++) { if(a&t) { if(!(a&(t<<1))) { movto(YBASE + i, XBASE + 2*j); } addstr(" "); } } } if(!s) { old[i] = new[i]; } } if(!s) { refresh(); } } } movto(6, 0); refresh(); clock_gettime(CLOCK_REALTIME_FAST, &now); if (now.tv_sec == prev_sec) { if (delay.tv_nsec > 0) { delay.tv_sec = 0; delay.tv_nsec = 1000000000 - now.tv_nsec; } else { delay.tv_sec = 1; delay.tv_nsec = 0; } nanosleep(&delay, NULL); clock_gettime(CLOCK_REALTIME_FAST, &now); } n -= now.tv_sec - prev_sec; prev_sec = now.tv_sec; if (sigtermed) { standend(); clear(); refresh(); endwin(); errx(1, "terminated by signal %d", (int)sigtermed); } } while (n); standend(); clear(); refresh(); endwin(); return(0); } static void set(int t, int n) { int i, m; m = 7<>(4-i)*3)&07)<