blob: ef220fed59ba7f6ead313bc6f46622c56f247336 [file] [log] [blame]
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301/****************************************************************************
2 * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc. *
3 * *
4 * Permission is hereby granted, free of charge, to any person obtaining a *
5 * copy of this software and associated documentation files (the *
6 * "Software"), to deal in the Software without restriction, including *
7 * without limitation the rights to use, copy, modify, merge, publish, *
8 * distribute, distribute with modifications, sublicense, and/or sell *
9 * copies of the Software, and to permit persons to whom the Software is *
10 * furnished to do so, subject to the following conditions: *
11 * *
12 * The above copyright notice and this permission notice shall be included *
13 * in all copies or substantial portions of the Software. *
14 * *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
22 * *
23 * Except as contained in this notice, the name(s) of the above copyright *
24 * holders shall not be used in advertising or otherwise to promote the *
25 * sale, use or other dealings in this Software without prior written *
26 * authorization. *
27 ****************************************************************************/
28/*
29 * Grand digital clock for curses compatible terminals
30 * Usage: gdc [-s] [n] -- run for n seconds (default infinity)
31 * Flags: -s: scroll
32 *
33 * modified 10-18-89 for curses (jrl)
34 * 10-18-89 added signal handling
35 *
36 * $Id: gdc.c,v 1.31 2008/08/03 23:58:42 tom Exp $
37 */
38
39#include <test.priv.h>
40
41#include <time.h>
42
43#define YBASE 10
44#define XBASE 10
45#define XLENGTH 54
46#define YDEPTH 5
47
48#define PAIR_DIGITS 1
49#define PAIR_OTHERS 2
50#define PAIR_FRAMES 3
51
52static short disp[11] =
53{
54 075557, 011111, 071747, 071717, 055711,
55 074717, 074757, 071111, 075757, 075717, 002020
56};
57static long older[6], next[6], newer[6], mask;
58
59static int sigtermed = 0;
60static bool redirected = FALSE;
61static bool hascolor = FALSE;
62
63static RETSIGTYPE
64sighndl(int signo)
65{
66 signal(signo, sighndl);
67 sigtermed = signo;
68 if (redirected) {
69 endwin();
70 ExitProgram(EXIT_FAILURE);
71 }
72}
73
74static void
75drawbox(bool scrolling)
76{
77 chtype bottom[XLENGTH + 1];
78 int n;
79
80 if (hascolor)
81 attrset(COLOR_PAIR(PAIR_FRAMES));
82
83 mvaddch(YBASE - 1, XBASE - 1, ACS_ULCORNER);
84 hline(ACS_HLINE, XLENGTH);
85 mvaddch(YBASE - 1, XBASE + XLENGTH, ACS_URCORNER);
86
87 mvaddch(YBASE + YDEPTH, XBASE - 1, ACS_LLCORNER);
88 if ((mvinchnstr(YBASE + YDEPTH, XBASE, bottom, XLENGTH)) != ERR) {
89 for (n = 0; n < XLENGTH; n++) {
90 if (!scrolling)
91 bottom[n] &= ~A_COLOR;
92 bottom[n] = ACS_HLINE | (bottom[n] & (A_ATTRIBUTES | A_COLOR));
93 }
94 mvaddchnstr(YBASE + YDEPTH, XBASE, bottom, XLENGTH);
95 }
96 mvaddch(YBASE + YDEPTH, XBASE + XLENGTH, ACS_LRCORNER);
97
98 move(YBASE, XBASE - 1);
99 vline(ACS_VLINE, YDEPTH);
100
101 move(YBASE, XBASE + XLENGTH);
102 vline(ACS_VLINE, YDEPTH);
103
104 if (hascolor)
105 attrset(COLOR_PAIR(PAIR_OTHERS));
106}
107
108static void
109standt(int on)
110{
111 if (on) {
112 if (hascolor) {
113 attron(COLOR_PAIR(PAIR_DIGITS));
114 } else {
115 attron(A_STANDOUT);
116 }
117 } else {
118 if (hascolor) {
119 attron(COLOR_PAIR(PAIR_OTHERS));
120 } else {
121 attroff(A_STANDOUT);
122 }
123 }
124}
125
126static void
127set(int t, int n)
128{
129 int i, m;
130
131 m = 7 << n;
132 for (i = 0; i < 5; i++) {
133 next[i] |= ((disp[t] >> ((4 - i) * 3)) & 07) << n;
134 mask |= (next[i] ^ older[i]) & m;
135 }
136 if (mask & m)
137 mask |= m;
138}
139
140static void
141usage(void)
142{
143 static const char *msg[] =
144 {
145 "Usage: gdc [options] [count]"
146 ,""
147 ,"Options:"
148 ," -n redirect input to /dev/null"
149 ," -s scroll each number into place, rather than flipping"
150 ,""
151 ,"If you specify a count, gdc runs for that number of seconds"
152 };
153 unsigned j;
154 for (j = 0; j < SIZEOF(msg); j++)
155 fprintf(stderr, "%s\n", msg[j]);
156 ExitProgram(EXIT_FAILURE);
157}
158
159int
160main(int argc, char *argv[])
161{
162 time_t now;
163 struct tm *tm;
164 long t, a;
165 int i, j, s, k;
166 int count = 0;
167 FILE *ofp = stdout;
168 FILE *ifp = stdin;
169 bool scrol = FALSE;
170
171 setlocale(LC_ALL, "");
172
173 CATCHALL(sighndl);
174
175 while ((k = getopt(argc, argv, "sn")) != -1) {
176 switch (k) {
177 case 's':
178 scrol = TRUE;
179 break;
180 case 'n':
181 ifp = fopen("/dev/null", "r");
182 redirected = TRUE;
183 break;
184 default:
185 usage();
186 }
187 }
188 if (optind < argc) {
189 count = atoi(argv[optind++]);
190 assert(count >= 0);
191 }
192 if (optind < argc)
193 usage();
194
195 if (redirected) {
196 char *name = getenv("TERM");
197 if (name == 0
198 || newterm(name, ofp, ifp) == 0) {
199 fprintf(stderr, "cannot open terminal\n");
200 ExitProgram(EXIT_FAILURE);
201 }
202
203 } else {
204 initscr();
205 }
206 cbreak();
207 noecho();
208 nodelay(stdscr, 1);
209 curs_set(0);
210
211 hascolor = has_colors();
212
213 if (hascolor) {
214 int bg = COLOR_BLACK;
215 start_color();
216#if HAVE_USE_DEFAULT_COLORS
217 if (use_default_colors() == OK)
218 bg = -1;
219#endif
220 init_pair(PAIR_DIGITS, COLOR_BLACK, COLOR_RED);
221 init_pair(PAIR_OTHERS, COLOR_RED, bg);
222 init_pair(PAIR_FRAMES, COLOR_WHITE, bg);
223 attrset(COLOR_PAIR(PAIR_OTHERS));
224 }
225
226 restart:
227 for (j = 0; j < 5; j++)
228 older[j] = newer[j] = next[j] = 0;
229
230 clear();
231 drawbox(FALSE);
232
233 do {
234 char buf[30];
235
236 time(&now);
237 tm = localtime(&now);
238
239 mask = 0;
240 set(tm->tm_sec % 10, 0);
241 set(tm->tm_sec / 10, 4);
242 set(tm->tm_min % 10, 10);
243 set(tm->tm_min / 10, 14);
244 set(tm->tm_hour % 10, 20);
245 set(tm->tm_hour / 10, 24);
246 set(10, 7);
247 set(10, 17);
248
249 for (k = 0; k < 6; k++) {
250 if (scrol) {
251 for (i = 0; i < 5; i++)
252 newer[i] = (newer[i] & ~mask) | (newer[i + 1] & mask);
253 newer[5] = (newer[5] & ~mask) | (next[k] & mask);
254 } else
255 newer[k] = (newer[k] & ~mask) | (next[k] & mask);
256 next[k] = 0;
257 for (s = 1; s >= 0; s--) {
258 standt(s);
259 for (i = 0; i < 6; i++) {
260 if ((a = (newer[i] ^ older[i]) & (s ? newer : older)[i])
261 != 0) {
262 for (j = 0, t = 1 << 26; t; t >>= 1, j++) {
263 if (a & t) {
264 if (!(a & (t << 1))) {
265 move(YBASE + i, XBASE + 2 * j);
266 }
267 addstr(" ");
268 }
269 }
270 }
271 if (!s) {
272 older[i] = newer[i];
273 }
274 }
275 if (!s) {
276 if (scrol)
277 drawbox(TRUE);
278 refresh();
279 /*
280 * If we're scrolling, space out the refreshes to fake
281 * movement. That's 7 frames, or 6 intervals, which would
282 * be 166 msec if we spread it out over a second. It looks
283 * better (but will work on a slow terminal, e.g., less
284 * than 9600bd) to squeeze that into a half-second, and use
285 * half of 170 msec to ensure that the program doesn't eat
286 * a lot of time when asking what time it is, at the top of
287 * this loop -T.Dickey
288 */
289 if (scrol)
290 napms(85);
291 }
292 }
293 }
294
295 /* this depends on the detailed format of ctime(3) */
296 (void) strcpy(buf, ctime(&now));
297 (void) strcpy(buf + 10, buf + 19);
298 mvaddstr(16, 30, buf);
299
300 move(6, 0);
301 drawbox(FALSE);
302 refresh();
303
304 /*
305 * If we're not scrolling, wait 1000 msec (1 sec). Use napms() rather
306 * than sleep() because the latter does odd things on some systems,
307 * e.g., suspending output as well.
308 */
309 if (scrol)
310 napms(500);
311 else
312 napms(1000);
313
314 /*
315 * This is a safe way to check if we're interrupted - making the signal
316 * handler set a flag that we can check. Since we're running
317 * nodelay(), the wgetch() call returns immediately, and in particular
318 * will return an error if interrupted. This works only if we can
319 * read from the input, of course.
320 */
321 switch (wgetch(stdscr)) {
322 case 'q':
323 count = 1;
324 break;
325 case 's':
326 nodelay(stdscr, FALSE);
327 break;
328 case ' ':
329 nodelay(stdscr, TRUE);
330 break;
331#ifdef KEY_RESIZE
332 case KEY_RESIZE:
333#endif
334 case '?':
335 goto restart;
336 case ERR:
337 if (sigtermed) {
338 standend();
339 endwin();
340 fprintf(stderr, "gdc terminated by signal %d\n", sigtermed);
341 ExitProgram(EXIT_FAILURE);
342 }
343 /* FALLTHRU */
344 default:
345 continue;
346 }
347 } while (--count);
348 standend();
349 endwin();
350 ExitProgram(EXIT_SUCCESS);
351}