1 /* delay - counts down a specified number of seconds.
2 Copyright (C) 1998 Tom Rothamel.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include <stdio.h>
20 #include <time.h>
21 #include <sys/time.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include "parsetime.h"
26
27 #ifdef HAVE_CURSES_H
28 #include <curses.h>
29 #endif
30
31 /* The following code implements the actual delaying. If precise is true, it
32 attempts to compensate for the time spend in calculating, printing, etc.
33 */
34
35 struct timeval tv;
36
initdelay(int precise)37 void initdelay(int precise) {
38 if (!precise) return;
39 gettimeofday(&tv, NULL);
40 }
41
delay(int secs,int precise)42 void delay(int secs, int precise) {
43 struct timeval ctv;
44 struct timeval dtv;
45
46 if (!precise) {
47 sleep(secs);
48 return;
49 }
50
51 tv.tv_sec += secs;
52
53 gettimeofday(&ctv, NULL);
54 dtv.tv_sec = tv.tv_sec - ctv.tv_sec;
55 dtv.tv_usec = tv.tv_usec - ctv.tv_usec;
56
57 if (dtv.tv_usec < 0) {
58 dtv.tv_usec += 1000000;
59 dtv.tv_sec -= 1;
60 }
61
62 select(0, NULL, NULL, NULL, &dtv);
63 }
64
65 /* These two functions handle the parsing of standard-format arguments.
66 This format allows for HH:MM:SS, DDdHHhMMmSSs, or SSSSs style inputs.
67 (Multiple arguments are added together.
68 */
69
parseonestd(char * entry)70 int parseonestd(char *entry) {
71 int commit = 0;
72 int t = 0;
73 int usfact = 1000000;
74
75 while (1) {
76 if (!*entry) return commit + t;
77
78
79 if (('0' <= *entry) && (*entry <= '9')) {
80 t *= 10;
81 t += *entry - '0';
82 } else if (*entry == '.') {
83 break;
84 } else switch(*entry) {
85 case ':':
86 commit +=t;
87 commit *= 60;
88 t = 0;
89 break;
90 case 's':
91 commit += t;
92 t = 0;
93 break;
94 case 'm':
95 commit += t * 60;
96 t = 0;
97 break;
98 case 'h':
99 commit += t * 3600;
100 t = 0;
101 break;
102 case 'd':
103 commit += t * 86400;
104 break;
105 }
106
107 entry++;
108 }
109
110 while (*++entry) {
111 usfact /= 10;
112 if (('0' <= *entry) && (*entry <= '9')) {
113 usleep((*entry - '0') * usfact);
114 }
115 }
116
117 return commit + t;
118 }
119
120
parsestandard(int argc,char ** argv)121 int parsestandard(int argc, char **argv) {
122 int i;
123 int dt = 0;
124 int tdt;
125
126 for (i = 0; i < argc; i++) {
127 tdt = parseonestd(argv[i]);
128 if (tdt == -1) return -1;
129 dt += tdt;
130 }
131
132 return dt;
133 }
134
135
136
137 /* Prints out the time, using the format code. The format is somewhat like
138 the integer codes used in printf. You have all the flags, and then
139 d for days, h for hours, m for minutes, s for seconds, and n for the
140 total number of seconds remaining.
141 */
142
printtime(char * fmt,int time)143 void printtime(char *fmt, int time) {
144 char buf[16];
145 char *c;
146 int i;
147 char b;
148
149 c = fmt;
150
151
152 while (*c) {
153 switch (*c) {
154 case '\\':
155 c++;
156
157 switch (*c) {
158 case 0:
159 return;
160 case '\\':
161 printf("\\");
162 break;
163 case 'r':
164 printf("\r");
165 break;
166 case 'n':
167 printf("\n");
168 break;
169 case 't':
170 printf("\t");
171 break;
172 case '%':
173 printf("%%");
174 break;
175 }
176
177 break;
178
179 case '%':
180 strncpy(buf, c, 15);
181 for (i = 1; i < 100; i++) {
182 if (buf[i] == 0) return;
183 if (buf[i] == 'd') break;
184 if (buf[i] == 'h') break;
185 if (buf[i] == 'm') break;
186 if (buf[i] == 's') break;
187 if (buf[i] == 'n') break;
188 }
189
190 b = buf[i];
191 buf[i] = 'd';
192 buf[i+1] = 0;
193
194 switch (b) {
195 case 'd':
196 printf(buf, time/86400);
197 break;
198 case 'h':
199 printf(buf, (time/3600) % 24);
200 break;
201 case 'm':
202 printf(buf, (time/60) % 60);
203 break;
204 case 's':
205 printf(buf, time % 60);
206 break;
207 case 'n':
208 printf(buf, time);
209 break;
210 case 0:
211 return;
212 }
213
214 c += i;
215 break;
216 default:
217 printf("%c", *c);
218 break;
219 }
220
221 c++;
222 }
223
224 }
225
226
227 /* The rest of the code is responsible for displaying the countdown,
228 parsing the arguments, and otherwise making this thing work.
229 */
230
231 char *custmessage;
232
usage(char * name)233 void usage(char *name) {
234 fprintf(stdout,
235 "Usage: %s [options] <seconds to delay> [-- command]\n"
236 " or %s [options] until <timespec> [-- command]\n", name, name);
237
238 exit(-1);
239 }
240
241 void curshowcount(int);
242
showcount(int dtime,int ctype)243 void showcount(int dtime, int ctype) {
244 switch(ctype) {
245 case 0:
246 printtime("\r% 3d %02h:%02m:%02s", dtime);
247 break;
248 case 1:
249 printtime("\rTime Remaining: %d days, %02h:%02m:%02s.", dtime);
250 break;
251 case 2:
252 printtime(custmessage, dtime);
253 break;
254 case 3:
255 printf("\r% 8d", dtime);
256 break;
257 case 4:
258 curshowcount(dtime);
259 break;
260
261 }
262
263 fflush(stdout);
264 }
265
main(int argc,char ** argv)266 int main(int argc, char **argv) {
267 int opt;
268 int dtime;
269 int ctype = 0;
270 int bell = 0;
271 int update = 1;
272 int i;
273 char **cmd = NULL;
274
275
276 if (strstr(argv[0], "sleep")) ctype = -1;
277
278 for (i = 0; i < argc; i++) {
279 if(!strcmp(argv[i], "--")) {
280 if (i == argc - 1) {
281 fprintf(stderr, "%s: with '--' you must specify a command to run.\n", argv[0]);
282 usage(argv[0]);
283 }
284
285 cmd = &argv[i+1];
286 argv[i] = NULL;
287 argc = i;
288 break;
289 }
290 }
291
292 while (1) {
293 opt = getopt(argc, argv, "qu:bhdvmc:CV");
294 if (opt == EOF) break;
295
296 switch (opt) {
297 case 'q':
298 ctype = -1;
299 break;
300 case 'u':
301 update = atoi(optarg);
302 break;
303 case 'h':
304 usage(argv[0]);
305 break;
306 case 'd':
307 ctype = 0;
308 break;
309 case 'v':
310 ctype = 1;
311 break;
312 case 'm':
313 ctype = 3;
314 break;
315 case 'c':
316 custmessage = optarg;
317 ctype=2;
318 break;
319 case 'C':
320 ctype = 4;
321 break;
322 case 'V':
323 printf("delay - Version " VERSION "\n"
324 " Copyright (c) 1998-2002 Tom Rothamel\n"
325 " This program has ABSOLUTELY NO WARRANTY. It can be distributed under\n"
326 " the terms of the GNU General Public License.\n");
327 exit(0);
328 case 'b':
329 bell = 1;
330 break;
331 }
332
333 }
334
335 if (optind >= argc) {
336 fprintf(stderr, "%s: You must supply a time to delay.\n", argv[0]);
337 usage(argv[0]);
338 }
339
340 if (update < 1) {
341 fprintf(stderr, "%s: The update rate must be a positive integer.\n", argv[0]);
342 exit(-1);
343 }
344
345 if (!strcmp(argv[optind], "until")) {
346 dtime = parsetime(argc-optind, &argv[optind+1]);
347 if (!dtime) exit(-1);
348 dtime -= time(NULL);
349 } else {
350 dtime = parsestandard(argc-optind, &argv[optind]);
351 }
352
353 if (dtime < 0) {
354 fprintf(stderr, "%s: You've specified an invalid delay time.\n", argv[0]);
355 usage(argv[0]);
356 }
357
358 initdelay(1);
359
360 if (ctype == 4) initscr();
361
362 while (dtime > 0) {
363 if (ctype >= 0) showcount(dtime, ctype);
364
365 delay((dtime < update) ? dtime : update, 1); /* always precise. */
366 dtime -= (dtime < update) ? dtime : update;
367 }
368
369 if (ctype >= 0) {
370 showcount(dtime, ctype);
371 if (ctype != 4) printf("\n");
372 }
373
374 if (ctype == 4) endwin();
375
376 if (bell) printf("\a");
377
378 if (cmd) {
379 execvp(cmd[0], cmd);
380 perror(argv[0]); /* If it worked, we won't get here. */
381 exit -1;
382 }
383
384 exit(0);
385 }
386