// // alarm.exe - countdown timer version of sleep. // #include #include #include #include char Usage[] = "Usage: alarm [seconds] [align]\n" "\n" " The ALARM command is just a countdown timer version of the SLEEP\n" " command. It displays remaining time each second and exits at zero.\n" "\n" " Try: ALARM 60 or ALARM 3661 or ALARM 86400\n" "\n" " Like SLEEP, times are given in seconds. Unlike SLEEP, times may\n" " also be given as s seconds or as m minutes or as h hours.\n" "\n" " Try: ALARM 5m or ALARM 1h to sleep for five minutes or one hour.\n" "\n" " The second parameter is optional and if given it rounds the alarm\n" " time to an aligned value. So ALARM 5m 0 would set the alarm for\n" " the nearest future time that is a 5 minute multiple. Note this\n" " will end up being a sleep duration that could be as short as a\n" " second to as long as a full 5 minutes.\n" "\n" " Try: ALARM 1h 0 which sleeps until the top of the hour.\n" "\n" " Finally, if the second parameter is present and non-zero, it is\n" " added as an offset to the aligned time.\n" "\n" " Try: ALARM 1h 10m sleeps until 10 minutes past the next hour.\n" " Try: ALARM 2h -15m means 15 minutes before the next even hour.\n" "\n" " ALARM is more desirable than SLEEP in some periodic scripts.\n" ; void main (int argc, char *argv[]) { long delay, offset; time_t now, when; char *dhms (long seconds); long parse_time_units (char *s); // Get delay argument (seconds). if (argc < 2) { fprintf(stderr, Usage); exit(1); } // Get delay value. delay = parse_time_units(argv[1]); if (delay <= 0) { delay = 1; } time(&now); when = now + delay; // Optionally align to period boundary, or boundary plus offset. if (argc > 2) { offset = parse_time_units(argv[2]); offset %= delay; when -= now % delay; when += offset; if (when <= now) { when += delay; } } printf("Start at %.24s\n", ctime(&now)); printf("Alarm at %.24s\n", ctime(&when)); // Sleep a second at a time until countdown reaches zero. while (1) { time(&now); fprintf(stderr, "%s\r", dhms(when - now)); if (now >= when) { break; } _sleep(1000); // one second } fprintf(stderr, "\n"); exit(0); } // // Convert number as time with optional second, minute, or hour units. // long parse_time_units (char *s) { long delay; char units; int value; units = 's'; sscanf(s, "%d%c", &value, &units); delay = value; switch (units) { case 'd' : delay *= 24; case 'h' : delay *= 60; case 'm' : delay *= 60; case 's' : break; default : fprintf(stderr, "Invalid delay value: %s\n", s); exit(1); } return delay; } // // Convert integer seconds to pretty day-hour-minute-second string. // char *dhms (long seconds) { static char buf[20]; // e.g., 7d 23h 59m 59s int d, h, m, s; static int len = 0; int i, n, pad; // Convert to days, hours, minutes, seconds. d = seconds / 86400; seconds %= 86400; h = seconds / 3600; seconds %= 3600; m = seconds / 60; s = seconds % 60; // Convert to string, suppressing leading zeros. if (d > 0) { sprintf(buf, "%dd %dh %dm %ds", d, h, m, s); } else if (h > 0) { sprintf(buf, "%dh %dm %ds", h, m, s); } else if (m > 0) { sprintf(buf, "%dm %ds", m, s); } else { sprintf(buf, "%ds", s); } // If necessary pad string to erase previous display width. n = strlen(buf); pad = len - n; for (i = 0; i < pad; i += 1) { strcat(buf, " "); } len = n; return buf; // STATIC }