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