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