1 /* 2 * Grand digital clock for curses compatible terminals 3 * Usage: grdc [-s] [-d msecs] [n] -- run for n seconds (default infinity) 4 * Flags: -s: scroll (default scroll duration 120msec) 5 * -d msecs: specify scroll duration (implies -s) 6 * 7 * modified 10-18-89 for curses (jrl) 8 * 10-18-89 added signal handling 9 * 03-23-04 added centering, scroll delay (cap) 10 * 11 * $FreeBSD: src/games/grdc/grdc.c,v 1.8.2.1 2001/10/02 11:51:49 ru Exp $ 12 * $DragonFly: src/games/grdc/grdc.c,v 1.6 2007/04/18 18:32:12 swildner Exp $ 13 */ 14 15 #include <err.h> 16 #include <time.h> 17 #include <signal.h> 18 #include <ncurses.h> 19 #include <stdlib.h> 20 #ifndef NONPOSIX 21 #include <unistd.h> 22 #endif 23 #include <time.h> 24 25 #define XLENGTH 58 26 #define YDEPTH 7 27 28 time_t now; 29 struct tm *tm; 30 31 short disp[11] = { 32 075557, 011111, 071747, 071717, 055711, 33 074717, 074757, 071111, 075757, 075717, 002020 34 }; 35 long old[6], next[6], new[6], mask; 36 37 volatile sig_atomic_t sigtermed; 38 39 int hascolor = 0; 40 long int scroll_msecs = 120; 41 int xbase, ybase, xmax, ymax; 42 43 static void set(int, int); 44 static void standt(int); 45 static void sighndl(int); 46 static void usage(void); 47 static void draw_row(int, int); 48 static void snooze(long int); 49 50 void 51 sighndl(int signo) 52 { 53 sigtermed = signo; 54 } 55 56 int 57 main(int argc, char **argv) 58 { 59 int i, s, k; 60 int n = 0; 61 int ch; 62 int scrol; 63 int forever = 1; 64 65 scrol = 0; 66 67 while ((ch = getopt(argc, argv, "d:s")) != -1) 68 switch (ch) { 69 case 'd': 70 scroll_msecs = atol(optarg); 71 if (scroll_msecs < 0) 72 errx(1, "scroll duration may not be negative"); 73 /* FALLTHROUGH */ 74 case 's': 75 scrol = 1; 76 break; 77 case '?': 78 default: 79 usage(); 80 /* NOTREACHED */ 81 } 82 argc -= optind; 83 argv += optind; 84 85 if (argc > 1) { 86 usage(); 87 /* NOTREACHED */ 88 } 89 90 if (argc > 0) { 91 n = atoi(*argv); 92 forever = 0; 93 } 94 95 initscr(); 96 97 getmaxyx(stdscr, ymax, xmax); 98 if (ymax < YDEPTH + 2 || xmax < XLENGTH + 4) { 99 endwin(); 100 errx(1, "terminal too small"); 101 } 102 xbase = (xmax - XLENGTH) / 2 + 2; 103 ybase = (ymax - YDEPTH) / 2 + 1; 104 105 signal(SIGINT, sighndl); 106 signal(SIGTERM, sighndl); 107 signal(SIGHUP, sighndl); 108 109 cbreak(); 110 noecho(); 111 curs_set(0); 112 113 hascolor = has_colors(); 114 115 if (hascolor) { 116 start_color(); 117 init_pair(1, COLOR_BLACK, COLOR_RED); 118 init_pair(2, COLOR_RED, COLOR_BLACK); 119 init_pair(3, COLOR_WHITE, COLOR_BLACK); 120 attrset(COLOR_PAIR(2)); 121 } 122 123 clear(); 124 refresh(); 125 126 if (hascolor) { 127 attrset(COLOR_PAIR(3)); 128 129 mvaddch(ybase - 2, xbase - 3, ACS_ULCORNER); 130 hline(ACS_HLINE, XLENGTH); 131 mvaddch(ybase - 2, xbase - 2 + XLENGTH, ACS_URCORNER); 132 133 mvaddch(ybase + YDEPTH - 1, xbase - 3, ACS_LLCORNER); 134 hline(ACS_HLINE, XLENGTH); 135 mvaddch(ybase + YDEPTH - 1, xbase - 2 + XLENGTH, ACS_LRCORNER); 136 137 move(ybase - 1, xbase - 3); 138 vline(ACS_VLINE, YDEPTH); 139 140 move(ybase - 1, xbase - 2 + XLENGTH); 141 vline(ACS_VLINE, YDEPTH); 142 143 attrset(COLOR_PAIR(2)); 144 refresh(); 145 } 146 do { 147 mask = 0; 148 time(&now); 149 tm = localtime(&now); 150 set(tm->tm_sec % 10, 0); 151 set(tm->tm_sec / 10, 4); 152 set(tm->tm_min % 10, 10); 153 set(tm->tm_min / 10, 14); 154 set(tm->tm_hour % 10, 20); 155 set(tm->tm_hour / 10, 24); 156 set(10, 7); 157 set(10, 17); 158 for(k = 0; k < 6; k++) { 159 if (scrol) { 160 snooze(scroll_msecs / 6); 161 for(i = 0; i < 5; i++) 162 new[i] = (new[i] & ~mask) | 163 (new[i+1] & mask); 164 new[5] = (new[5] & ~mask) | (next[k] & mask); 165 } else 166 new[k] = (new[k] & ~mask) | (next[k] & mask); 167 next[k] = 0; 168 for (s = 1; s >= 0; s--) { 169 standt(s); 170 for (i = 0; i < 6; i++) { 171 draw_row(i, s); 172 } 173 if (!s) { 174 move(ybase, 0); 175 refresh(); 176 } 177 } 178 } 179 move(ybase, 0); 180 refresh(); 181 snooze(1000 - (scrol ? scroll_msecs : 0)); 182 } while (forever ? 1 : --n); 183 standend(); 184 clear(); 185 refresh(); 186 endwin(); 187 return(0); 188 } 189 190 void 191 snooze(long int msecs) 192 { 193 struct timespec ts; 194 195 ts.tv_sec = 0; 196 ts.tv_nsec = 1000000 * msecs; 197 198 nanosleep(&ts, NULL); 199 200 if (sigtermed) { 201 standend(); 202 clear(); 203 refresh(); 204 endwin(); 205 errx(1, "terminated by signal %d", (int)sigtermed); 206 } 207 } 208 209 void 210 draw_row(int i, int s) 211 { 212 long a, t; 213 int j; 214 215 if ((a = (new[i] ^ old[i]) & (s ? new : old)[i]) != 0) { 216 for (j = 0, t = 1 << 26; t; t >>= 1, j++) { 217 if (a & t) { 218 if (!(a & (t << 1))) { 219 move(ybase + i, xbase + 2 * j); 220 } 221 addstr(" "); 222 } 223 } 224 } 225 if (!s) { 226 old[i] = new[i]; 227 } 228 } 229 230 void 231 set(int t, int n) 232 { 233 int i, m; 234 235 m = 7 << n; 236 for (i = 0; i < 5; i++) { 237 next[i] |= ((disp[t] >> (4 - i) * 3) & 07) << n; 238 mask |= (next[i] ^ old[i]) & m; 239 } 240 if (mask & m) 241 mask |= m; 242 } 243 244 void 245 standt(int on) 246 { 247 if (on) { 248 if (hascolor) { 249 attron(COLOR_PAIR(1)); 250 } else { 251 attron(A_STANDOUT); 252 } 253 } else { 254 if (hascolor) { 255 attron(COLOR_PAIR(2)); 256 } else { 257 attroff(A_STANDOUT); 258 } 259 } 260 } 261 262 void 263 usage(void) 264 { 265 fprintf(stderr, "usage: grdc [-s] [-d msecs] [n]\n"); 266 exit(1); 267 } 268