1 /****************************************************************************
2 * Copyright (c) 1998-2014,2015 Free Software Foundation, Inc. *
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: *
12 * The above copyright notice and this permission notice shall be included *
13 * in all copies or substantial portions of the Software. *
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. *
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 *
27 ****************************************************************************/
29 * Grand digital clock for curses compatible terminals
30 * Usage: gdc [-s] [-t hh:mm:ss] [n] -- run for n seconds (default infinity)
33 * modified 10-18-89 for curses (jrl)
34 * 10-18-89 added signal handling
36 * $Id: gdc.c,v 1.44 2015/07/04 21:28:28 tom Exp $
39 #include <test.priv.h>
52 static short disp
[11] =
54 075557, 011111, 071747, 071717, 055711,
55 074717, 074757, 071111, 075757, 075717, 002020
57 static long older
[6], next
[6], newer
[6], mask
;
59 static int sigtermed
= 0;
60 static bool redirected
= FALSE
;
61 static bool hascolor
= FALSE
;
66 signal(signo
, sighndl
);
70 ExitProgram(EXIT_FAILURE
);
80 fprintf(stderr
, "gdc terminated by signal %d\n", sigtermed
);
81 ExitProgram(EXIT_FAILURE
);
86 drawbox(bool scrolling
)
88 chtype bottom
[XLENGTH
+ 1];
92 (void) attrset(AttrArg(COLOR_PAIR(PAIR_FRAMES
), 0));
94 MvAddCh(YBASE
- 1, XBASE
- 1, ACS_ULCORNER
);
95 hline(ACS_HLINE
, XLENGTH
);
96 MvAddCh(YBASE
- 1, XBASE
+ XLENGTH
, ACS_URCORNER
);
98 MvAddCh(YBASE
+ YDEPTH
, XBASE
- 1, ACS_LLCORNER
);
99 if ((mvinchnstr(YBASE
+ YDEPTH
, XBASE
, bottom
, XLENGTH
)) != ERR
) {
100 for (n
= 0; n
< XLENGTH
; n
++) {
102 bottom
[n
] &= ~A_COLOR
;
103 bottom
[n
] = ACS_HLINE
| (bottom
[n
] & (A_ATTRIBUTES
| A_COLOR
));
105 (void) mvaddchnstr(YBASE
+ YDEPTH
, XBASE
, bottom
, XLENGTH
);
107 MvAddCh(YBASE
+ YDEPTH
, XBASE
+ XLENGTH
, ACS_LRCORNER
);
109 move(YBASE
, XBASE
- 1);
110 vline(ACS_VLINE
, YDEPTH
);
112 move(YBASE
, XBASE
+ XLENGTH
);
113 vline(ACS_VLINE
, YDEPTH
);
116 (void) attrset(AttrArg(COLOR_PAIR(PAIR_OTHERS
), 0));
124 attron(COLOR_PAIR(PAIR_DIGITS
));
130 attron(COLOR_PAIR(PAIR_OTHERS
));
143 for (i
= 0; i
< 5; i
++) {
144 next
[i
] |= ((disp
[t
] >> ((4 - i
) * 3)) & 07) << n
;
145 mask
|= (next
[i
] ^ older
[i
]) & m
;
154 static const char *msg
[] =
156 "Usage: gdc [options] [count]"
159 ," -n redirect input to /dev/null"
160 ," -s scroll each number into place, rather than flipping"
161 ," -t hh:mm:ss specify starting time (default is ``now'')"
163 ,"If you specify a count, gdc runs for that number of seconds"
166 for (j
= 0; j
< SIZEOF(msg
); j
++)
167 fprintf(stderr
, "%s\n", msg
[j
]);
168 ExitProgram(EXIT_FAILURE
);
172 parse_time(const char *value
)
180 if (sscanf(value
, "%d:%d:%d%c", &hh
, &mm
, &ss
, &c
) != 3) {
181 if (sscanf(value
, "%02d%02d%02d%c", &hh
, &mm
, &ss
, &c
) != 3) {
186 if ((hh
< 0) || (hh
>= 24) ||
187 (mm
< 0) || (mm
>= 60) ||
188 (ss
< 0) || (ss
>= 60)) {
192 /* adjust so that the localtime in the main loop will give usable time */
193 result
= (hh
* 3600) + ((mm
* 60) + ss
);
194 for (check
= 0; check
< 24; ++check
) {
195 tm
= localtime(&result
);
196 if (tm
->tm_hour
== hh
)
201 if (tm
->tm_hour
!= hh
) {
202 fprintf(stderr
, "Cannot find local time for %s!\n", value
);
209 main(int argc
, char *argv
[])
222 setlocale(LC_ALL
, "");
226 while ((k
= getopt(argc
, argv
, "nst:")) != -1) {
229 ifp
= fopen("/dev/null", "r");
236 starts
= parse_time(optarg
);
243 count
= atoi(argv
[optind
++]);
250 char *name
= getenv("TERM");
252 || newterm(name
, ofp
, ifp
) == 0) {
253 fprintf(stderr
, "cannot open terminal\n");
254 ExitProgram(EXIT_FAILURE
);
265 hascolor
= has_colors();
268 short bg
= COLOR_BLACK
;
270 #if HAVE_USE_DEFAULT_COLORS
271 if (use_default_colors() == OK
)
274 init_pair(PAIR_DIGITS
, COLOR_BLACK
, COLOR_RED
);
275 init_pair(PAIR_OTHERS
, COLOR_RED
, bg
);
276 init_pair(PAIR_FRAMES
, COLOR_WHITE
, bg
);
277 (void) attrset(AttrArg(COLOR_PAIR(PAIR_OTHERS
), 0));
281 for (j
= 0; j
< 5; j
++)
282 older
[j
] = newer
[j
] = next
[j
] = 0;
295 tm
= localtime(&now
);
298 set(tm
->tm_sec
% 10, 0);
299 set(tm
->tm_sec
/ 10, 4);
300 set(tm
->tm_min
% 10, 10);
301 set(tm
->tm_min
/ 10, 14);
302 set(tm
->tm_hour
% 10, 20);
303 set(tm
->tm_hour
/ 10, 24);
307 for (k
= 0; k
< 6; k
++) {
309 for (i
= 0; i
< 5; i
++)
310 newer
[i
] = (newer
[i
] & ~mask
) | (newer
[i
+ 1] & mask
);
311 newer
[5] = (newer
[5] & ~mask
) | (next
[k
] & mask
);
313 newer
[k
] = (newer
[k
] & ~mask
) | (next
[k
] & mask
);
316 for (s
= 1; s
>= 0; s
--) {
318 for (i
= 0; i
< 6; i
++) {
319 if ((a
= (newer
[i
] ^ older
[i
]) & (s
? newer
: older
)[i
])
321 for (j
= 0, t
= 1 << 26; t
; t
>>= 1, j
++) {
323 if (!(a
& (t
<< 1))) {
324 move(YBASE
+ i
, XBASE
+ 2 * j
);
339 * If we're scrolling, space out the refreshes to fake
340 * movement. That's 7 frames, or 6 intervals, which would
341 * be 166 msec if we spread it out over a second. It looks
342 * better (but will work on a slow terminal, e.g., less
343 * than 9600bd) to squeeze that into a half-second, and use
344 * half of 170 msec to ensure that the program doesn't eat
345 * a lot of time when asking what time it is, at the top of
346 * this loop -T.Dickey
352 switch (wgetch(stdscr
)) {
360 nodelay(stdscr
, FALSE
);
363 nodelay(stdscr
, TRUE
);
381 /* this depends on the detailed format of ctime(3) */
382 (void) strncpy(buf
, ctime(&now
), (size_t) 30);
386 while ((*d2
++ = *s2
++) != '\0') ;
388 MvAddStr(16, 30, buf
);
395 * If we're not smooth-scrolling, wait 1000 msec (1 sec). Use napms()
396 * rather than sleep() because the latter does odd things on some
397 * systems, e.g., suspending output as well.
405 * This is a safe way to check if we're interrupted - making the signal
406 * handler set a flag that we can check. Since we're running
407 * nodelay(), the wgetch() call returns immediately, and in particular
408 * will return an error if interrupted. This works only if we can
409 * read from the input, of course.
412 switch (wgetch(stdscr
)) {
420 nodelay(stdscr
, FALSE
);
423 nodelay(stdscr
, TRUE
);
439 ExitProgram(EXIT_SUCCESS
);