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.5 2005/03/15 20:53:39 dillon 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 sighndl(int signo) 51 { 52 sigtermed = signo; 53 } 54 55 int 56 main(int argc, char **argv) 57 { 58 int i, s, k; 59 int n = 0; 60 int ch; 61 int scrol; 62 int forever = 1; 63 64 scrol = 0; 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 ts.tv_sec = 0; 195 ts.tv_nsec = 1000000 * msecs; 196 197 nanosleep(&ts, NULL); 198 199 if (sigtermed) { 200 standend(); 201 clear(); 202 refresh(); 203 endwin(); 204 errx(1, "terminated by signal %d", (int)sigtermed); 205 } 206 } 207 208 void 209 draw_row(int i, int s) 210 { 211 long a, t; 212 int j; 213 214 if ((a = (new[i] ^ old[i]) & (s ? new : old)[i]) != 0) { 215 for (j = 0, t = 1 << 26; t; t >>= 1, j++) { 216 if (a & t) { 217 if (!(a & (t << 1))) { 218 move(ybase + i, xbase + 2 * j); 219 } 220 addstr(" "); 221 } 222 } 223 } 224 if (!s) { 225 old[i] = new[i]; 226 } 227 } 228 229 void 230 set(int t, int n) 231 { 232 int i, m; 233 234 m = 7 << n; 235 for (i = 0; i < 5; i++) { 236 next[i] |= ((disp[t] >> (4 - i) * 3) & 07) << n; 237 mask |= (next[i] ^ old[i]) & m; 238 } 239 if (mask & m) 240 mask |= m; 241 } 242 243 void 244 standt(int on) 245 { 246 if (on) { 247 if (hascolor) { 248 attron(COLOR_PAIR(1)); 249 } else { 250 attron(A_STANDOUT); 251 } 252 } else { 253 if (hascolor) { 254 attron(COLOR_PAIR(2)); 255 } else { 256 attroff(A_STANDOUT); 257 } 258 } 259 } 260 261 void 262 usage(void) 263 { 264 fprintf(stderr, "usage: grdc [-s] [-d msecs] [n]\n"); 265 exit(1); 266 } 267