xref: /openbsd/games/grdc/grdc.c (revision 404b540a)
1 /*	$OpenBSD: grdc.c,v 1.15 2008/03/17 09:17:56 sobrado 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/types.h>
15 #include <curses.h>
16 #include <limits.h>
17 #include <signal.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <time.h>
21 #include <unistd.h>
22 
23 #define YBASE	10
24 #define XBASE	10
25 #define XLENGTH 58
26 #define YDEPTH  7
27 
28 struct timespec 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 char scrol;
37 
38 volatile sig_atomic_t sigtermed = 0;
39 
40 int hascolor = 0;
41 
42 void set(int, int);
43 void standt(int);
44 void movto(int, int);
45 void usage(void);
46 
47 void
48 sighndl(int signo)
49 {
50 	sigtermed=signo;
51 }
52 
53 int
54 main(int argc, char *argv[])
55 {
56 	long t, a;
57 	int i, j, s, k;
58 	int n = 0;
59 	struct timeval nowtv;
60 	struct timespec delay;
61 	char *ep;
62 
63 	scrol = 0;
64 	while ((i = getopt(argc, argv, "sh")) != -1)
65 		switch (i) {
66 		case 's':
67 			scrol = 1;
68 			break;
69 		case 'h':
70 		case '?':
71 		default:
72 			usage();
73 		}
74 	argv += optind;
75 	argc -= optind;
76 
77 	if (argc > 1)
78 		usage();
79 	if (argc == 1) {
80 		t = strtol(*argv, &ep, 10);
81 		if ((*argv)[0] == '\0' || *ep != '\0')
82 			usage();
83 		if (t < 1 || t >= INT_MAX) {
84 			fprintf(stderr, "number of seconds is out of range");
85 			usage();
86 		}
87 		n = t;
88 	}
89 
90 	initscr();
91 
92 	signal(SIGINT,sighndl);
93 	signal(SIGTERM,sighndl);
94 	signal(SIGHUP,sighndl);
95 
96 	cbreak();
97 	noecho();
98 
99 	hascolor = has_colors();
100 
101 	if(hascolor) {
102 		start_color();
103 		init_pair(1, COLOR_BLACK, COLOR_RED);
104 		init_pair(2, COLOR_RED, COLOR_BLACK);
105 		init_pair(3, COLOR_WHITE, COLOR_BLACK);
106 		attrset(COLOR_PAIR(2));
107 	}
108 
109 	curs_set(0);
110 	clear();
111 	refresh();
112 	if(hascolor) {
113 		attrset(COLOR_PAIR(3));
114 
115 		mvaddch(YBASE - 2,  XBASE - 3, ACS_ULCORNER);
116 		hline(ACS_HLINE, XLENGTH);
117 		mvaddch(YBASE - 2,  XBASE - 2 + XLENGTH, ACS_URCORNER);
118 
119 		mvaddch(YBASE + YDEPTH - 1,  XBASE - 3, ACS_LLCORNER);
120 		hline(ACS_HLINE, XLENGTH);
121 		mvaddch(YBASE + YDEPTH - 1,  XBASE - 2 + XLENGTH, ACS_LRCORNER);
122 
123 		move(YBASE - 1,  XBASE - 3);
124 		vline(ACS_VLINE, YDEPTH);
125 
126 		move(YBASE - 1,  XBASE - 2 + XLENGTH);
127 		vline(ACS_VLINE, YDEPTH);
128 
129 		attrset(COLOR_PAIR(2));
130 	}
131 	gettimeofday(&nowtv, NULL);
132 	TIMEVAL_TO_TIMESPEC(&nowtv, &now);
133 	do {
134 		mask = 0;
135 		tm = localtime(&now.tv_sec);
136 		set(tm->tm_sec%10, 0);
137 		set(tm->tm_sec/10, 4);
138 		set(tm->tm_min%10, 10);
139 		set(tm->tm_min/10, 14);
140 		set(tm->tm_hour%10, 20);
141 		set(tm->tm_hour/10, 24);
142 		set(10, 7);
143 		set(10, 17);
144 		for(k=0; k<6; k++) {
145 			if(scrol) {
146 				for(i=0; i<5; i++)
147 					new[i] = (new[i]&~mask) | (new[i+1]&mask);
148 				new[5] = (new[5]&~mask) | (next[k]&mask);
149 			} else
150 				new[k] = (new[k]&~mask) | (next[k]&mask);
151 			next[k] = 0;
152 			for(s=1; s>=0; s--) {
153 				standt(s);
154 				for(i=0; i<6; i++) {
155 					if((a = (new[i]^old[i])&(s ? new : old)[i]) != 0) {
156 						for(j=0,t=1<<26; t; t>>=1,j++) {
157 							if(a&t) {
158 								if(!(a&(t<<1))) {
159 									movto(YBASE + i, XBASE + 2*j);
160 								}
161 								addstr("  ");
162 							}
163 						}
164 					}
165 					if(!s) {
166 						old[i] = new[i];
167 					}
168 				}
169 				if(!s) {
170 					refresh();
171 				}
172 			}
173 		}
174 		movto(6, 0);
175 		refresh();
176 		gettimeofday(&nowtv, NULL);
177 		TIMEVAL_TO_TIMESPEC(&nowtv, &now);
178 		delay.tv_sec = 0;
179 		delay.tv_nsec = (1000000000 - now.tv_nsec);
180 		nanosleep(&delay, NULL);
181 		now.tv_sec++;
182 
183 		if (sigtermed) {
184 			standend();
185 			clear();
186 			refresh();
187 			endwin();
188 			fprintf(stderr, "grdc terminated by signal %d\n", sigtermed);
189 			exit(1);
190 		}
191 	} while(--n);
192 	standend();
193 	clear();
194 	refresh();
195 	endwin();
196 	return(0);
197 }
198 
199 void
200 set(int t, int n)
201 {
202 	int i, m;
203 
204 	m = 7<<n;
205 	for(i=0; i<5; i++) {
206 		next[i] |= ((disp[t]>>(4-i)*3)&07)<<n;
207 		mask |= (next[i]^old[i])&m;
208 	}
209 	if(mask&m)
210 		mask |= m;
211 }
212 
213 void
214 standt(int on)
215 {
216 	if (on) {
217 		if(hascolor) {
218 			attron(COLOR_PAIR(1));
219 		} else {
220 			attron(A_STANDOUT);
221 		}
222 	} else {
223 		if(hascolor) {
224 			attron(COLOR_PAIR(2));
225 		} else {
226 			attroff(A_STANDOUT);
227 		}
228 	}
229 }
230 
231 void
232 movto(int line, int col)
233 {
234 	move(line, col);
235 }
236 
237 void
238 usage(void)
239 {
240 	(void)fprintf(stderr, "usage: grdc [-s] [number]\n");
241 	exit(1);
242 }
243