Simplify argument parser by using sscanf(); simplify usage() by not
refusing to use stdio. Reduce nesting level in the sleep loop by returning earlier for negative timeouts. Limit the maximum timeout to INT_MAX seconds. Submitted by: bde MFC after: 3 weeks
This commit is contained in:
parent
a80f05bb73
commit
f6e6dc63ab
@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void usage(void);
|
||||
|
||||
@ -65,91 +64,39 @@ int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct timespec time_to_sleep;
|
||||
long l, original;
|
||||
int neg;
|
||||
char *p;
|
||||
double d;
|
||||
time_t original;
|
||||
char buf[2];
|
||||
|
||||
if (argc != 2)
|
||||
usage();
|
||||
|
||||
p = argv[1];
|
||||
|
||||
/* Skip over leading whitespaces. */
|
||||
while (isspace((unsigned char)*p))
|
||||
++p;
|
||||
|
||||
/* Check for optional `+' or `-' sign. */
|
||||
neg = 0;
|
||||
if (*p == '-') {
|
||||
neg = 1;
|
||||
++p;
|
||||
if (!isdigit((unsigned char)*p) && *p != '.')
|
||||
usage();
|
||||
}
|
||||
else if (*p == '+')
|
||||
++p;
|
||||
|
||||
/* Calculate seconds. */
|
||||
if (isdigit((unsigned char)*p)) {
|
||||
l = strtol(p, &p, 10);
|
||||
|
||||
/*
|
||||
* Avoid overflow when `seconds' is huge. This assumes
|
||||
* that the maximum value for a time_t is <= INT_MAX.
|
||||
*/
|
||||
if (l > INT_MAX)
|
||||
l = INT_MAX;
|
||||
} else
|
||||
l = 0;
|
||||
time_to_sleep.tv_sec = (time_t)l;
|
||||
|
||||
/* Calculate nanoseconds. */
|
||||
time_to_sleep.tv_nsec = 0;
|
||||
|
||||
if (*p == '.') { /* Decimal point. */
|
||||
l = 100000000L;
|
||||
do {
|
||||
if (isdigit((unsigned char)*++p))
|
||||
time_to_sleep.tv_nsec += (*p - '0') * l;
|
||||
else
|
||||
break;
|
||||
l /= 10;
|
||||
} while (l);
|
||||
}
|
||||
|
||||
/* Skip over the trailing whitespace. */
|
||||
while (isspace((unsigned char)*p))
|
||||
++p;
|
||||
if (*p != '\0')
|
||||
if (sscanf(argv[1], "%lf%1s", &d, buf) != 1)
|
||||
usage();
|
||||
if (d > INT_MAX)
|
||||
usage();
|
||||
if (d <= 0)
|
||||
return (0);
|
||||
original = time_to_sleep.tv_sec = (time_t)d;
|
||||
time_to_sleep.tv_nsec = 1e9 * (d - time_to_sleep.tv_sec);
|
||||
|
||||
signal(SIGINFO, report_request);
|
||||
if (!neg && (time_to_sleep.tv_sec > 0 || time_to_sleep.tv_nsec > 0)) {
|
||||
original = time_to_sleep.tv_sec;
|
||||
while (nanosleep(&time_to_sleep, &time_to_sleep) != 0) {
|
||||
if (report_requested) {
|
||||
/*
|
||||
* Reporting does not bother with
|
||||
* fractions of a second...
|
||||
*/
|
||||
warnx("about %jd second(s) left"
|
||||
" out of the original %jd",
|
||||
(intmax_t)time_to_sleep.tv_sec,
|
||||
(intmax_t)original);
|
||||
report_requested = 0;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
while (nanosleep(&time_to_sleep, &time_to_sleep) != 0) {
|
||||
if (report_requested) {
|
||||
/* Reporting does not bother with nanoseconds. */
|
||||
warnx("about %d second(s) left out of the original %d",
|
||||
(int)time_to_sleep.tv_sec, (int)original);
|
||||
report_requested = 0;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
static const char msg[] = "usage: sleep seconds\n";
|
||||
|
||||
write(STDERR_FILENO, msg, sizeof(msg) - 1);
|
||||
fprintf(stderr, "usage: sleep seconds\n");
|
||||
exit(1);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user