14974Sache/* 24974Sache * Grand digital clock for curses compatible terminals 3112749Smux * Usage: grdc [-st] [n] -- run for n seconds (default infinity) 44974Sache * Flags: -s: scroll 5112749Smux * -t: output time in 12-hour format 64974Sache * 7112749Smux * 84974Sache * modified 10-18-89 for curses (jrl) 94974Sache * 10-18-89 added signal handling 1051358Sgreen * 11112749Smux * modified 03-25-03 for 12 hour option 12112749Smux * - Samy Al Bahra <samy@kerneled.com> 13112749Smux * 1451358Sgreen * $FreeBSD$ 154974Sache */ 164974Sache 1783928Sru#include <err.h> 18210809Suqs#include <ncurses.h> 194974Sache#include <signal.h> 204974Sache#include <stdlib.h> 21210809Suqs#include <time.h> 224974Sache#include <unistd.h> 234974Sache 244974Sache#define YBASE 10 254974Sache#define XBASE 10 264974Sache#define XLENGTH 58 274974Sache#define YDEPTH 7 284974Sache 29249840Seadlerstatic struct timespec now; 30249840Seadlerstatic struct tm *tm; 314974Sache 32249840Seadlerstatic short disp[11] = { 334974Sache 075557, 011111, 071747, 071717, 055711, 344974Sache 074717, 074757, 071111, 075757, 075717, 002020 354974Sache}; 36249840Seadlerstatic long old[6], next[6], new[6], mask; 374974Sache 38249840Seadlerstatic volatile sig_atomic_t sigtermed; 394974Sache 40249840Seadlerstatic int hascolor = 0; 414974Sache 42249840Seadlerstatic void set(int, int); 43249840Seadlerstatic void standt(int); 44249840Seadlerstatic void movto(int, int); 45249840Seadlerstatic void sighndl(int); 46249840Seadlerstatic void usage(void); 474974Sache 48249840Seadlerstatic void 49203920Suqssighndl(int signo) 504974Sache{ 51249840Seadler 52249840Seadler sigtermed = signo; 534974Sache} 544974Sache 554974Sacheint 56203920Suqsmain(int argc, char *argv[]) 574974Sache{ 58210755Suqs struct timespec delay; 59210827Suqs time_t prev_sec; 60203920Suqs long t, a; 61203920Suqs int i, j, s, k; 62203920Suqs int n; 63203920Suqs int ch; 64203920Suqs int scrol; 65203920Suqs int t12; 664974Sache 67112749Smux t12 = scrol = 0; 6883928Sru 69112749Smux while ((ch = getopt(argc, argv, "ts")) != -1) 7083928Sru switch (ch) { 7183928Sru case 's': 7283928Sru scrol = 1; 7383928Sru break; 74112749Smux case 't': 75112749Smux t12 = 1; 76112749Smux break; 7783928Sru case '?': 7883928Sru default: 7983928Sru usage(); 8083928Sru /* NOTREACHED */ 8183928Sru } 8283928Sru argc -= optind; 8383928Sru argv += optind; 8483928Sru 8583928Sru if (argc > 1) { 8683928Sru usage(); 8783928Sru /* NOTREACHED */ 8883928Sru } 8983928Sru 90210809Suqs if (argc > 0) { 91210755Suqs n = atoi(*argv) + 1; 92210809Suqs if (n < 1) { 93210809Suqs warnx("number of seconds is out of range"); 94210809Suqs usage(); 95210809Suqs /* NOTREACHED */ 96210809Suqs } 97210809Suqs } else 9883928Sru n = 0; 9983928Sru 1004974Sache initscr(); 1014974Sache 1024974Sache signal(SIGINT,sighndl); 1034974Sache signal(SIGTERM,sighndl); 1044974Sache signal(SIGHUP,sighndl); 1054974Sache 1064974Sache cbreak(); 1074974Sache noecho(); 10851358Sgreen curs_set(0); 1098856Srgrimes 1104974Sache hascolor = has_colors(); 1114974Sache 1128856Srgrimes if(hascolor) { 1134974Sache start_color(); 1144974Sache init_pair(1, COLOR_BLACK, COLOR_RED); 1154974Sache init_pair(2, COLOR_RED, COLOR_BLACK); 1164974Sache init_pair(3, COLOR_WHITE, COLOR_BLACK); 1174974Sache attrset(COLOR_PAIR(2)); 1184974Sache } 1198856Srgrimes 1204974Sache clear(); 1214974Sache refresh(); 1224974Sache 1238856Srgrimes if(hascolor) { 1244974Sache attrset(COLOR_PAIR(3)); 1254974Sache 1264974Sache mvaddch(YBASE - 2, XBASE - 3, ACS_ULCORNER); 1274974Sache hline(ACS_HLINE, XLENGTH); 1284974Sache mvaddch(YBASE - 2, XBASE - 2 + XLENGTH, ACS_URCORNER); 1294974Sache 1304974Sache mvaddch(YBASE + YDEPTH - 1, XBASE - 3, ACS_LLCORNER); 1314974Sache hline(ACS_HLINE, XLENGTH); 1324974Sache mvaddch(YBASE + YDEPTH - 1, XBASE - 2 + XLENGTH, ACS_LRCORNER); 1334974Sache 1344974Sache move(YBASE - 1, XBASE - 3); 1354974Sache vline(ACS_VLINE, YDEPTH); 1364974Sache 1374974Sache move(YBASE - 1, XBASE - 2 + XLENGTH); 1384974Sache vline(ACS_VLINE, YDEPTH); 1394974Sache 1404974Sache attrset(COLOR_PAIR(2)); 1414974Sache } 142210755Suqs clock_gettime(CLOCK_REALTIME_FAST, &now); 143210827Suqs prev_sec = now.tv_sec; 1444974Sache do { 1454974Sache mask = 0; 146210755Suqs tm = localtime(&now.tv_sec); 1474974Sache set(tm->tm_sec%10, 0); 1484974Sache set(tm->tm_sec/10, 4); 1494974Sache set(tm->tm_min%10, 10); 1504974Sache set(tm->tm_min/10, 14); 151112749Smux 152112749Smux if (t12) { 153112749Smux if (tm->tm_hour > 12) { 154112749Smux tm->tm_hour -= 12; 155112749Smux mvaddstr(YBASE + 5, XBASE + 52, "PM"); 156116739Swill } else { 157116739Swill if (tm->tm_hour == 0) 158116739Swill tm->tm_hour = 12; 159116739Swill 160112749Smux mvaddstr(YBASE + 5, XBASE + 52, "AM"); 161116739Swill } 162112749Smux } 163112749Smux 1644974Sache set(tm->tm_hour%10, 20); 1654974Sache set(tm->tm_hour/10, 24); 1664974Sache set(10, 7); 1674974Sache set(10, 17); 1684974Sache for(k=0; k<6; k++) { 1694974Sache if(scrol) { 1704974Sache for(i=0; i<5; i++) 1714974Sache new[i] = (new[i]&~mask) | (new[i+1]&mask); 1724974Sache new[5] = (new[5]&~mask) | (next[k]&mask); 1734974Sache } else 1744974Sache new[k] = (new[k]&~mask) | (next[k]&mask); 1754974Sache next[k] = 0; 1764974Sache for(s=1; s>=0; s--) { 1774974Sache standt(s); 1784974Sache for(i=0; i<6; i++) { 1794974Sache if((a = (new[i]^old[i])&(s ? new : old)[i]) != 0) { 1804974Sache for(j=0,t=1<<26; t; t>>=1,j++) { 1814974Sache if(a&t) { 1824974Sache if(!(a&(t<<1))) { 1834974Sache movto(YBASE + i, XBASE + 2*j); 1844974Sache } 1854974Sache addstr(" "); 1864974Sache } 1874974Sache } 1884974Sache } 1894974Sache if(!s) { 1904974Sache old[i] = new[i]; 1914974Sache } 1924974Sache } 1934974Sache if(!s) { 1944974Sache refresh(); 1954974Sache } 1964974Sache } 1974974Sache } 1984974Sache movto(6, 0); 1994974Sache refresh(); 200210827Suqs clock_gettime(CLOCK_REALTIME_FAST, &now); 201210827Suqs if (now.tv_sec == prev_sec) { 202210809Suqs if (delay.tv_nsec > 0) { 203210809Suqs delay.tv_sec = 0; 204210827Suqs delay.tv_nsec = 1000000000 - now.tv_nsec; 205210809Suqs } else { 206210809Suqs delay.tv_sec = 1; 207210809Suqs delay.tv_nsec = 0; 208210809Suqs } 209210809Suqs nanosleep(&delay, NULL); 210210827Suqs clock_gettime(CLOCK_REALTIME_FAST, &now); 211210755Suqs } 212210827Suqs n -= now.tv_sec - prev_sec; 213210827Suqs prev_sec = now.tv_sec; 2144974Sache if (sigtermed) { 2154974Sache standend(); 2164974Sache clear(); 2174974Sache refresh(); 2184974Sache endwin(); 21983928Sru errx(1, "terminated by signal %d", (int)sigtermed); 2204974Sache } 221210809Suqs } while (n); 2224974Sache standend(); 2234974Sache clear(); 2244974Sache refresh(); 2254974Sache endwin(); 2264974Sache return(0); 2274974Sache} 2284974Sache 229249840Seadlerstatic void 2304974Sacheset(int t, int n) 2314974Sache{ 232203920Suqs int i, m; 2334974Sache 2344974Sache m = 7<<n; 2354974Sache for(i=0; i<5; i++) { 2364974Sache next[i] |= ((disp[t]>>(4-i)*3)&07)<<n; 2374974Sache mask |= (next[i]^old[i])&m; 2384974Sache } 2394974Sache if(mask&m) 2404974Sache mask |= m; 2414974Sache} 2424974Sache 243249840Seadlerstatic void 2444974Sachestandt(int on) 2454974Sache{ 2464974Sache if (on) { 2474974Sache if(hascolor) { 2484974Sache attron(COLOR_PAIR(1)); 2494974Sache } else { 2508856Srgrimes attron(A_STANDOUT); 2518856Srgrimes } 2524974Sache } else { 2534974Sache if(hascolor) { 2544974Sache attron(COLOR_PAIR(2)); 2554974Sache } else { 2564974Sache attroff(A_STANDOUT); 2574974Sache } 2584974Sache } 2594974Sache} 2604974Sache 261249840Seadlerstatic void 2624974Sachemovto(int line, int col) 2634974Sache{ 2644974Sache move(line, col); 2654974Sache} 2664974Sache 267249840Seadlerstatic void 26883928Sruusage(void) 26983928Sru{ 27083928Sru 271112749Smux (void)fprintf(stderr, "usage: grdc [-st] [n]\n"); 27283928Sru exit(1); 27383928Sru} 274