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