153537Sbrian/* 280728Sbrian * Grand digital clock for curses compatible terminals 353537Sbrian * Usage: grdc [-st] [n] -- run for n seconds (default infinity) 453537Sbrian * Flags: -s: scroll 553537Sbrian * -t: output time in 12-hour format 653537Sbrian * 753537Sbrian * 853537Sbrian * modified 10-18-89 for curses (jrl) 953537Sbrian * 10-18-89 added signal handling 1053537Sbrian * 1153537Sbrian * modified 03-25-03 for 12 hour option 1253537Sbrian * - Samy Al Bahra <samy@kerneled.com> 1353537Sbrian * 1453537Sbrian * $FreeBSD$ 1553537Sbrian */ 1653537Sbrian 1753537Sbrian#include <err.h> 1853537Sbrian#include <ncurses.h> 1953537Sbrian#include <signal.h> 2053537Sbrian#include <stdlib.h> 2153537Sbrian#include <time.h> 2253537Sbrian#include <unistd.h> 2353537Sbrian 2453537Sbrian#define YBASE 10 2553537Sbrian#define XBASE 10 2653537Sbrian#define XLENGTH 58 2753537Sbrian#define YDEPTH 7 2853537Sbrian 2953537Sbrianstatic struct timespec now; 3053537Sbrianstatic struct tm *tm; 3153537Sbrian 3253537Sbrianstatic short disp[11] = { 3353537Sbrian 075557, 011111, 071747, 071717, 055711, 3453537Sbrian 074717, 074757, 071111, 075757, 075717, 002020 3553537Sbrian}; 3653537Sbrianstatic long old[6], next[6], new[6], mask; 3753537Sbrian 3853537Sbrianstatic volatile sig_atomic_t sigtermed; 3953537Sbrian 4053537Sbrianstatic int hascolor = 0; 4153537Sbrian 4253537Sbrianstatic void set(int, int); 4353537Sbrianstatic void standt(int); 4453537Sbrianstatic void movto(int, int); 4553537Sbrianstatic void sighndl(int); 4653537Sbrianstatic void usage(void); 4753537Sbrian 4866602Sbrianstatic void 4953537Sbriansighndl(int signo) 5053537Sbrian{ 5153537Sbrian 5253537Sbrian sigtermed = signo; 5353537Sbrian} 5453537Sbrian 5553537Sbrianint 5653537Sbrianmain(int argc, char *argv[]) 5753537Sbrian{ 5853537Sbrian struct timespec delay; 5953537Sbrian time_t prev_sec; 6053537Sbrian long t, a; 6153537Sbrian int i, j, s, k; 6253537Sbrian int n; 6353537Sbrian int ch; 6486705Sbrian int scrol; 6586705Sbrian int t12; 6696580Sbrian 6753537Sbrian t12 = scrol = 0; 6890160Skris 6990160Skris while ((ch = getopt(argc, argv, "ts")) != -1) 7069582Sbrian switch (ch) { 7169582Sbrian case 's': 7253537Sbrian scrol = 1; 7353537Sbrian break; 7453537Sbrian case 't': 7595258Sdes t12 = 1; 76141589Sru break; 7753537Sbrian case '?': 7853537Sbrian default: 7953537Sbrian usage(); 8053537Sbrian /* NOTREACHED */ 8169582Sbrian } 8253537Sbrian argc -= optind; 8369582Sbrian argv += optind; 8453537Sbrian 8553537Sbrian if (argc > 1) { 8653537Sbrian usage(); 8753537Sbrian /* NOTREACHED */ 8853537Sbrian } 8953537Sbrian 9053537Sbrian if (argc > 0) { 9153537Sbrian n = atoi(*argv) + 1; 9253537Sbrian if (n < 1) { 9353537Sbrian warnx("number of seconds is out of range"); 9453537Sbrian usage(); 9553537Sbrian /* NOTREACHED */ 9653537Sbrian } 9753537Sbrian } else 9853537Sbrian n = 0; 9953537Sbrian 10053537Sbrian initscr(); 10153537Sbrian 10253537Sbrian signal(SIGINT,sighndl); 10353537Sbrian signal(SIGTERM,sighndl); 10453537Sbrian signal(SIGHUP,sighndl); 10553537Sbrian 10653537Sbrian cbreak(); 10753537Sbrian noecho(); 10853537Sbrian curs_set(0); 10953537Sbrian 11053537Sbrian hascolor = has_colors(); 11153537Sbrian 11253537Sbrian if(hascolor) { 11353537Sbrian start_color(); 11453537Sbrian init_pair(1, COLOR_BLACK, COLOR_RED); 11553537Sbrian init_pair(2, COLOR_RED, COLOR_BLACK); 11653537Sbrian init_pair(3, COLOR_WHITE, COLOR_BLACK); 11753537Sbrian attrset(COLOR_PAIR(2)); 11853537Sbrian } 11953537Sbrian 12053537Sbrian clear(); 12153537Sbrian refresh(); 12253537Sbrian 12353537Sbrian if(hascolor) { 12453537Sbrian attrset(COLOR_PAIR(3)); 12553537Sbrian 12653537Sbrian mvaddch(YBASE - 2, XBASE - 3, ACS_ULCORNER); 12753537Sbrian hline(ACS_HLINE, XLENGTH); 12853537Sbrian mvaddch(YBASE - 2, XBASE - 2 + XLENGTH, ACS_URCORNER); 12953537Sbrian 13053537Sbrian mvaddch(YBASE + YDEPTH - 1, XBASE - 3, ACS_LLCORNER); 13153537Sbrian hline(ACS_HLINE, XLENGTH); 13253537Sbrian mvaddch(YBASE + YDEPTH - 1, XBASE - 2 + XLENGTH, ACS_LRCORNER); 13353537Sbrian 13453537Sbrian move(YBASE - 1, XBASE - 3); 13553537Sbrian vline(ACS_VLINE, YDEPTH); 13653537Sbrian 13753537Sbrian move(YBASE - 1, XBASE - 2 + XLENGTH); 13853537Sbrian vline(ACS_VLINE, YDEPTH); 13953537Sbrian 14053537Sbrian attrset(COLOR_PAIR(2)); 14153537Sbrian } 14253537Sbrian clock_gettime(CLOCK_REALTIME_FAST, &now); 14353537Sbrian prev_sec = now.tv_sec; 14453537Sbrian do { 14553537Sbrian mask = 0; 14653537Sbrian tm = localtime(&now.tv_sec); 14753537Sbrian set(tm->tm_sec%10, 0); 14882276Sbrian set(tm->tm_sec/10, 4); 14953537Sbrian set(tm->tm_min%10, 10); 15053537Sbrian set(tm->tm_min/10, 14); 15153537Sbrian 15253537Sbrian if (t12) { 15353537Sbrian if (tm->tm_hour < 12) { 15453537Sbrian if (tm->tm_hour == 0) 15553537Sbrian tm->tm_hour = 12; 15653537Sbrian mvaddstr(YBASE + 5, XBASE + 52, "AM"); 15753537Sbrian } else { 15853537Sbrian if (tm->tm_hour > 12) 15953537Sbrian tm->tm_hour -= 12; 16053537Sbrian mvaddstr(YBASE + 5, XBASE + 52, "PM"); 16153537Sbrian } 16253537Sbrian } 16353537Sbrian 16453537Sbrian set(tm->tm_hour%10, 20); 16553537Sbrian set(tm->tm_hour/10, 24); 16653537Sbrian set(10, 7); 16753537Sbrian set(10, 17); 16853537Sbrian for(k=0; k<6; k++) { 16953537Sbrian if(scrol) { 17053537Sbrian for(i=0; i<5; i++) 17153537Sbrian new[i] = (new[i]&~mask) | (new[i+1]&mask); 17253537Sbrian new[5] = (new[5]&~mask) | (next[k]&mask); 17353537Sbrian } else 17453537Sbrian new[k] = (new[k]&~mask) | (next[k]&mask); 17553537Sbrian next[k] = 0; 17653537Sbrian for(s=1; s>=0; s--) { 17753537Sbrian standt(s); 17853537Sbrian for(i=0; i<6; i++) { 17953537Sbrian if((a = (new[i]^old[i])&(s ? new : old)[i]) != 0) { 18053537Sbrian for(j=0,t=1<<26; t; t>>=1,j++) { 18153537Sbrian if(a&t) { 18253537Sbrian if(!(a&(t<<1))) { 18353537Sbrian movto(YBASE + i, XBASE + 2*j); 18453537Sbrian } 18553537Sbrian addstr(" "); 18653537Sbrian } 18753537Sbrian } 18853537Sbrian } 18953537Sbrian if(!s) { 19053537Sbrian old[i] = new[i]; 19153537Sbrian } 19253537Sbrian } 19353537Sbrian if(!s) { 19453537Sbrian refresh(); 19553537Sbrian } 19653537Sbrian } 19753537Sbrian } 19853537Sbrian movto(6, 0); 19953537Sbrian refresh(); 20053537Sbrian clock_gettime(CLOCK_REALTIME_FAST, &now); 20153537Sbrian if (now.tv_sec == prev_sec) { 20253537Sbrian if (delay.tv_nsec > 0) { 20353537Sbrian delay.tv_sec = 0; 20453537Sbrian delay.tv_nsec = 1000000000 - now.tv_nsec; 20553537Sbrian } else { 20653537Sbrian delay.tv_sec = 1; 20753537Sbrian delay.tv_nsec = 0; 20853537Sbrian } 20953537Sbrian nanosleep(&delay, NULL); 21053537Sbrian clock_gettime(CLOCK_REALTIME_FAST, &now); 21153537Sbrian } 21253537Sbrian n -= now.tv_sec - prev_sec; 21353537Sbrian prev_sec = now.tv_sec; 21453537Sbrian if (sigtermed) { 21553537Sbrian standend(); 21653537Sbrian clear(); 21753537Sbrian refresh(); 21853537Sbrian endwin(); 21953537Sbrian errx(1, "terminated by signal %d", (int)sigtermed); 22053537Sbrian } 22153537Sbrian } while (n); 22253537Sbrian standend(); 22353537Sbrian clear(); 22453537Sbrian refresh(); 22568032Sbrian endwin(); 22653537Sbrian return(0); 22768846Sbrian} 22868846Sbrian 22953537Sbrianstatic void 23053537Sbrianset(int t, int n) 23153537Sbrian{ 23253537Sbrian int i, m; 23353537Sbrian 23453537Sbrian m = 7<<n; 23553537Sbrian for(i=0; i<5; i++) { 23653537Sbrian next[i] |= ((disp[t]>>(4-i)*3)&07)<<n; 23753537Sbrian mask |= (next[i]^old[i])&m; 23853537Sbrian } 23953537Sbrian if(mask&m) 24053537Sbrian mask |= m; 24153537Sbrian} 24253537Sbrian 24353537Sbrianstatic void 24453537Sbrianstandt(int on) 24553537Sbrian{ 24653537Sbrian if (on) { 24753537Sbrian if(hascolor) { 24853537Sbrian attron(COLOR_PAIR(1)); 24953537Sbrian } else { 25053537Sbrian attron(A_STANDOUT); 25153537Sbrian } 25253537Sbrian } else { 25369948Sjulian if(hascolor) { 25486705Sbrian attron(COLOR_PAIR(2)); 25586705Sbrian } else { 25653537Sbrian attroff(A_STANDOUT); 25753537Sbrian } 25853537Sbrian } 25953537Sbrian} 26053537Sbrian 261171195Sscfstatic void 26286705Sbrianmovto(int line, int col) 26353537Sbrian{ 26453537Sbrian move(line, col); 26553537Sbrian} 26653537Sbrian 26753537Sbrianstatic void 26853537Sbrianusage(void) 26953537Sbrian{ 27053537Sbrian 27153537Sbrian (void)fprintf(stderr, "usage: grdc [-st] [n]\n"); 27253537Sbrian exit(1); 27353537Sbrian} 27453537Sbrian