1 /* $OpenBSD: grdc.c,v 1.26 2016/03/07 12:07:56 mestre Exp $ */ 2 /* 3 * 4 * Copyright 2002 Amos Shapir. Public domain. 5 * 6 * Grand digital clock for curses compatible terminals 7 * Usage: grdc [-s] [n] -- run for n seconds (default infinity) 8 * Flags: -s: scroll 9 * 10 * modified 10-18-89 for curses (jrl) 11 * 10-18-89 added signal handling 12 */ 13 14 #include <sys/ioctl.h> 15 16 #include <curses.h> 17 #include <err.h> 18 #include <limits.h> 19 #include <signal.h> 20 #include <stdlib.h> 21 #include <unistd.h> 22 23 #define XLENGTH 58 24 #define YDEPTH 7 25 26 struct timespec 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 = 0; 36 volatile sig_atomic_t sigwinched = 0; 37 38 int hascolor = 0; 39 40 void set(int, int); 41 void standt(int); 42 void getwinsize(int *, int *); 43 __dead void usage(void); 44 45 void 46 sighndl(int signo) 47 { 48 sigtermed=signo; 49 } 50 51 void 52 sigresize(int signo) 53 { 54 sigwinched = signo; 55 } 56 57 int 58 main(int argc, char *argv[]) 59 { 60 long t, a; 61 int i, j, s, k; 62 int scrol; 63 int n = 0; 64 struct timeval nowtv, endtv; 65 struct timespec delay; 66 const char *errstr; 67 long scroldelay = 50000000; 68 int xbase; 69 int ybase; 70 int wintoosmall; 71 72 if (pledge("stdio rpath tty", NULL) == -1) 73 err(1, "pledge"); 74 75 scrol = wintoosmall = 0; 76 while ((i = getopt(argc, argv, "sh")) != -1) 77 switch (i) { 78 case 's': 79 scrol = 1; 80 break; 81 case 'h': 82 default: 83 usage(); 84 } 85 argv += optind; 86 argc -= optind; 87 88 if (argc > 1) 89 usage(); 90 if (argc == 1) { 91 n = strtonum(*argv, 1, INT_MAX, &errstr); 92 if (errstr) { 93 fprintf(stderr, "number of seconds is %s\n", errstr); 94 usage(); 95 } 96 } 97 98 initscr(); 99 100 signal(SIGINT,sighndl); 101 signal(SIGTERM,sighndl); 102 signal(SIGHUP,sighndl); 103 signal(SIGWINCH, sigresize); 104 signal(SIGCONT, sigresize); /* for resizes during suspend */ 105 106 cbreak(); 107 noecho(); 108 109 hascolor = has_colors(); 110 111 if(hascolor) { 112 start_color(); 113 init_pair(1, COLOR_BLACK, COLOR_RED); 114 init_pair(2, COLOR_RED, COLOR_BLACK); 115 init_pair(3, COLOR_WHITE, COLOR_BLACK); 116 attrset(COLOR_PAIR(2)); 117 } 118 119 curs_set(0); 120 sigwinched = 1; /* force initial sizing */ 121 122 gettimeofday(&nowtv, NULL); 123 TIMEVAL_TO_TIMESPEC(&nowtv, &now); 124 if (n) 125 endtv.tv_sec = nowtv.tv_sec + n - 1; 126 do { 127 if (sigwinched) { 128 sigwinched = 0; 129 wintoosmall = 0; 130 getwinsize(&i, &j); 131 if (i >= XLENGTH + 2) 132 xbase = (i - XLENGTH) / 2; 133 else 134 wintoosmall = 1; 135 if (j >= YDEPTH + 2) 136 ybase = (j - YDEPTH) / 2; 137 else 138 wintoosmall = 1; 139 resizeterm(j, i); 140 clear(); 141 refresh(); 142 if (hascolor && !wintoosmall) { 143 attrset(COLOR_PAIR(3)); 144 145 mvaddch(ybase - 1, xbase - 1, ACS_ULCORNER); 146 hline(ACS_HLINE, XLENGTH); 147 mvaddch(ybase - 1, xbase + XLENGTH, ACS_URCORNER); 148 149 mvaddch(ybase + YDEPTH, xbase - 1, ACS_LLCORNER); 150 hline(ACS_HLINE, XLENGTH); 151 mvaddch(ybase + YDEPTH, xbase + XLENGTH, ACS_LRCORNER); 152 153 move(ybase, xbase - 1); 154 vline(ACS_VLINE, YDEPTH); 155 156 move(ybase, xbase + XLENGTH); 157 vline(ACS_VLINE, YDEPTH); 158 159 attrset(COLOR_PAIR(2)); 160 } 161 for (k = 0; k < 6; k++) 162 old[k] = 0; 163 } 164 mask = 0; 165 tm = localtime(&now.tv_sec); 166 set(tm->tm_sec%10, 0); 167 set(tm->tm_sec/10, 4); 168 set(tm->tm_min%10, 10); 169 set(tm->tm_min/10, 14); 170 set(tm->tm_hour%10, 20); 171 set(tm->tm_hour/10, 24); 172 set(10, 7); 173 set(10, 17); 174 if (wintoosmall) { 175 move(0, 0); 176 printw("%02d:%02d:%02d", tm->tm_hour, tm->tm_min, 177 tm->tm_sec); 178 } else for (k = 0; k < 6; k++) { 179 if(scrol) { 180 for(i=0; i<5; i++) 181 new[i] = (new[i]&~mask) | (new[i+1]&mask); 182 new[5] = (new[5]&~mask) | (next[k]&mask); 183 } else 184 new[k] = (new[k]&~mask) | (next[k]&mask); 185 next[k] = 0; 186 for(s=1; s>=0; s--) { 187 standt(s); 188 for(i=0; i<6; i++) { 189 if((a = (new[i]^old[i])&(s ? new : old)[i]) != 0) { 190 for(j=0,t=1<<26; t; t>>=1,j++) { 191 if(a&t) { 192 if(!(a&(t<<1))) { 193 move(ybase + i+1, xbase + 2*(j+1)); 194 } 195 addstr(" "); 196 } 197 } 198 } 199 if(!s) { 200 old[i] = new[i]; 201 } 202 } 203 if(!s) { 204 refresh(); 205 } 206 } 207 if (scrol && k <= 4) { 208 gettimeofday(&nowtv, NULL); 209 TIMEVAL_TO_TIMESPEC(&nowtv, &now); 210 delay.tv_sec = 0; 211 delay.tv_nsec = 1000000000 - now.tv_nsec 212 - (4-k) * scroldelay; 213 if (delay.tv_nsec <= scroldelay && 214 delay.tv_nsec > 0) 215 nanosleep(&delay, NULL); 216 } 217 } 218 move(6, 0); 219 refresh(); 220 gettimeofday(&nowtv, NULL); 221 TIMEVAL_TO_TIMESPEC(&nowtv, &now); 222 delay.tv_sec = 0; 223 delay.tv_nsec = (1000000000 - now.tv_nsec); 224 /* want scrolling to END on the second */ 225 if (scrol && !wintoosmall) 226 delay.tv_nsec -= 5 * scroldelay; 227 nanosleep(&delay, NULL); 228 now.tv_sec++; 229 230 if (sigtermed) { 231 standend(); 232 clear(); 233 refresh(); 234 endwin(); 235 fprintf(stderr, "%s terminated by signal %d\n", 236 getprogname(), sigtermed); 237 return 1; 238 } 239 } while (n == 0 || nowtv.tv_sec < endtv.tv_sec); 240 standend(); 241 clear(); 242 refresh(); 243 endwin(); 244 return 0; 245 } 246 247 void 248 set(int t, int n) 249 { 250 int i, m; 251 252 m = 7<<n; 253 for(i=0; i<5; i++) { 254 next[i] |= ((disp[t]>>(4-i)*3)&07)<<n; 255 mask |= (next[i]^old[i])&m; 256 } 257 if(mask&m) 258 mask |= m; 259 } 260 261 void 262 standt(int on) 263 { 264 if (on) { 265 if(hascolor) { 266 attron(COLOR_PAIR(1)); 267 } else { 268 attron(A_STANDOUT); 269 } 270 } else { 271 if(hascolor) { 272 attron(COLOR_PAIR(2)); 273 } else { 274 attroff(A_STANDOUT); 275 } 276 } 277 } 278 279 void 280 getwinsize(int *wid, int *ht) 281 { 282 struct winsize size; 283 284 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &size) < 0) { 285 *wid = 80; /* Default */ 286 *ht = 24; 287 } else { 288 *wid = size.ws_col; 289 *ht = size.ws_row; 290 } 291 } 292 293 void 294 usage(void) 295 { 296 (void)fprintf(stderr, "usage: %s [-s] [number]\n", getprogname()); 297 exit(1); 298 } 299