1 /* 2 * Grand digital clock for curses compatible terminals 3 * Usage: grdc [-st] [n] -- run for n seconds (default infinity) 4 * Flags: -s: scroll 5 * -t: output time in 12-hour format 6 * 7 * 8 * modified 10-18-89 for curses (jrl) 9 * 10-18-89 added signal handling 10 * 11 * modified 03-25-03 for 12 hour option 12 * - Samy Al Bahra <samy@kerneled.com> 13 * 14 * $FreeBSD$ 15 */ 16 17 #include <err.h> 18 #include <ncurses.h> 19 #include <signal.h> 20 #include <stdlib.h> 21 #include <time.h> 22 #include <unistd.h> 23 24 #define YBASE 10 25 #define XBASE 10 26 #define XLENGTH 58 27 #define YDEPTH 7 28 29 static struct timespec now; 30 static struct tm *tm; 31 32 static short disp[11] = { 33 075557, 011111, 071747, 071717, 055711, 34 074717, 074757, 071111, 075757, 075717, 002020 35 }; 36 static long old[6], next[6], new[6], mask; 37 38 static volatile sig_atomic_t sigtermed; 39 40 static int hascolor = 0; 41 42 static void set(int, int); 43 static void standt(int); 44 static void movto(int, int); 45 static void sighndl(int); 46 static void usage(void); 47 48 static void 49 sighndl(int signo) 50 { 51 52 sigtermed = signo; 53 } 54 55 int 56 main(int argc, char *argv[]) 57 { 58 struct timespec delay; 59 time_t prev_sec; 60 long t, a; 61 int i, j, s, k; 62 int n; 63 int ch; 64 int scrol; 65 int t12; 66 67 t12 = scrol = 0; 68 69 while ((ch = getopt(argc, argv, "ts")) != -1) 70 switch (ch) { 71 case 's': 72 scrol = 1; 73 break; 74 case 't': 75 t12 = 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) + 1; 92 if (n < 1) { 93 warnx("number of seconds is out of range"); 94 usage(); 95 /* NOTREACHED */ 96 } 97 } else 98 n = 0; 99 100 initscr(); 101 102 signal(SIGINT,sighndl); 103 signal(SIGTERM,sighndl); 104 signal(SIGHUP,sighndl); 105 106 cbreak(); 107 noecho(); 108 curs_set(0); 109 110 hascolor = has_colors(); 111 112 if(hascolor) { 113 start_color(); 114 init_pair(1, COLOR_BLACK, COLOR_RED); 115 init_pair(2, COLOR_RED, COLOR_BLACK); 116 init_pair(3, COLOR_WHITE, COLOR_BLACK); 117 attrset(COLOR_PAIR(2)); 118 } 119 120 clear(); 121 refresh(); 122 123 if(hascolor) { 124 attrset(COLOR_PAIR(3)); 125 126 mvaddch(YBASE - 2, XBASE - 3, ACS_ULCORNER); 127 hline(ACS_HLINE, XLENGTH); 128 mvaddch(YBASE - 2, XBASE - 2 + XLENGTH, ACS_URCORNER); 129 130 mvaddch(YBASE + YDEPTH - 1, XBASE - 3, ACS_LLCORNER); 131 hline(ACS_HLINE, XLENGTH); 132 mvaddch(YBASE + YDEPTH - 1, XBASE - 2 + XLENGTH, ACS_LRCORNER); 133 134 move(YBASE - 1, XBASE - 3); 135 vline(ACS_VLINE, YDEPTH); 136 137 move(YBASE - 1, XBASE - 2 + XLENGTH); 138 vline(ACS_VLINE, YDEPTH); 139 140 attrset(COLOR_PAIR(2)); 141 } 142 clock_gettime(CLOCK_REALTIME_FAST, &now); 143 prev_sec = now.tv_sec; 144 do { 145 mask = 0; 146 tm = localtime(&now.tv_sec); 147 set(tm->tm_sec%10, 0); 148 set(tm->tm_sec/10, 4); 149 set(tm->tm_min%10, 10); 150 set(tm->tm_min/10, 14); 151 152 if (t12) { 153 if (tm->tm_hour < 12) { 154 if (tm->tm_hour == 0) 155 tm->tm_hour = 12; 156 mvaddstr(YBASE + 5, XBASE + 52, "AM"); 157 } else { 158 if (tm->tm_hour > 12) 159 tm->tm_hour -= 12; 160 mvaddstr(YBASE + 5, XBASE + 52, "PM"); 161 } 162 } 163 164 set(tm->tm_hour%10, 20); 165 set(tm->tm_hour/10, 24); 166 set(10, 7); 167 set(10, 17); 168 for(k=0; k<6; k++) { 169 if(scrol) { 170 for(i=0; i<5; i++) 171 new[i] = (new[i]&~mask) | (new[i+1]&mask); 172 new[5] = (new[5]&~mask) | (next[k]&mask); 173 } else 174 new[k] = (new[k]&~mask) | (next[k]&mask); 175 next[k] = 0; 176 for(s=1; s>=0; s--) { 177 standt(s); 178 for(i=0; i<6; i++) { 179 if((a = (new[i]^old[i])&(s ? new : old)[i]) != 0) { 180 for(j=0,t=1<<26; t; t>>=1,j++) { 181 if(a&t) { 182 if(!(a&(t<<1))) { 183 movto(YBASE + i, XBASE + 2*j); 184 } 185 addstr(" "); 186 } 187 } 188 } 189 if(!s) { 190 old[i] = new[i]; 191 } 192 } 193 if(!s) { 194 refresh(); 195 } 196 } 197 } 198 movto(6, 0); 199 refresh(); 200 clock_gettime(CLOCK_REALTIME_FAST, &now); 201 if (now.tv_sec == prev_sec) { 202 if (delay.tv_nsec > 0) { 203 delay.tv_sec = 0; 204 delay.tv_nsec = 1000000000 - now.tv_nsec; 205 } else { 206 delay.tv_sec = 1; 207 delay.tv_nsec = 0; 208 } 209 nanosleep(&delay, NULL); 210 clock_gettime(CLOCK_REALTIME_FAST, &now); 211 } 212 n -= now.tv_sec - prev_sec; 213 prev_sec = now.tv_sec; 214 if (sigtermed) { 215 standend(); 216 clear(); 217 refresh(); 218 endwin(); 219 errx(1, "terminated by signal %d", (int)sigtermed); 220 } 221 } while (n); 222 standend(); 223 clear(); 224 refresh(); 225 endwin(); 226 return(0); 227 } 228 229 static 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 static 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 static void 262 movto(int line, int col) 263 { 264 move(line, col); 265 } 266 267 static void 268 usage(void) 269 { 270 271 (void)fprintf(stderr, "usage: grdc [-st] [n]\n"); 272 exit(1); 273 } 274