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