From 07a3b9192001369c7bf74cd4f096dc49703b24e9 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sun, 21 Oct 2018 21:36:51 -0500 Subject: Add % to lib/args.c (long time in milliseconds), add xmillitime(), redo xparsetime() not to need floating point, adjust callers. --- lib/args.c | 21 +++++++++++---------- lib/lib.h | 1 + lib/xwrap.c | 47 ++++++++++++++++++++++++++++------------------- scripts/mkflags.c | 22 +++++++++++++--------- toys/net/ping.c | 23 ++++++----------------- toys/other/timeout.c | 2 +- toys/posix/ps.c | 21 +++++---------------- toys/posix/sleep.c | 2 +- 8 files changed, 66 insertions(+), 73 deletions(-) diff --git a/lib/args.c b/lib/args.c index 5267ebe2..1927a930 100644 --- a/lib/args.c +++ b/lib/args.c @@ -53,17 +53,18 @@ // // Suffixes specify that this option takes an argument (stored in GLOBALS): // Note that pointer and long are always the same size, even on 64 bit. -// : plus a string argument, keep most recent if more than one -// * plus a string argument, appended to a list -// # plus a signed long argument +// : string argument, keep most recent if more than one +// * string argument, appended to a struct arg_list linked list. +// # signed long argument // HIGH - die if greater than HIGH // =DEFAULT - value if not specified -// - plus a signed long argument defaulting to negative (say + for positive) -// . plus a double precision floating point argument (with CFG_TOYBOX_FLOAT) +// - signed long argument defaulting to negative (say + for positive) +// . double precision floating point argument (with CFG_TOYBOX_FLOAT) // Chop this option out with USE_TOYBOX_FLOAT() in option string // Same HIGH=DEFAULT as # -// @ plus an occurrence counter (which is a long) +// @ occurrence counter (which is a long) +// % time offset in milliseconds with optional s/m/h/d suffix // (longopt) // | this is required. If more than one marked, only one required. // ; long option's argument is optional (can only be supplied with --opt=) @@ -215,7 +216,7 @@ static int gotflag(struct getoptflagstate *gof, struct opts *opt) help_exit("-%c < %lf", opt->c, (double)opt->val[0].f); if (opt->val[1].l != LONG_MAX && *f > opt->val[1].f) help_exit("-%c > %lf", opt->c, (double)opt->val[1].f); - } + } else if (type=='%') *(opt->arg) = xparsemillitime(arg); if (!gof->nodash_now) gof->arg = ""; } @@ -291,20 +292,20 @@ void parse_optflaglist(struct getoptflagstate *gof) // If this is the start of a new option that wasn't a longopt, - } else if (strchr(":*#@.-", *options)) { + } else if (strchr(":*#@.-%", *options)) { if (CFG_TOYBOX_DEBUG && new->type) error_exit("multiple types %c:%c%c", new->c, new->type, *options); new->type = *options; } else if (-1 != (idx = stridx("|^ ;", *options))) new->flags |= 1<=", *options))) { - if (new->type == '#') { + if (new->type == '#' || new->type == '%') { long l = strtol(++options, &temp, 10); if (temp != options) new->val[idx].l = l; } else if (CFG_TOYBOX_FLOAT && new->type == '.') { FLOAT f = strtod(++options, &temp); if (temp != options) new->val[idx].f = f; - } else error_exit("<>= only after .#"); + } else error_exit("<>= only after .#%%"); options = --temp; // At this point, we've hit the end of the previous option. The diff --git a/lib/lib.h b/lib/lib.h index 98c042c7..e630bbc9 100644 --- a/lib/lib.h +++ b/lib/lib.h @@ -172,6 +172,7 @@ void xsetuser(struct passwd *pwd); char *xreadlink(char *name); double xstrtod(char *s); long xparsetime(char *arg, long units, long *fraction); +long long xparsemillitime(char *arg); void xpidfile(char *name); void xregcomp(regex_t *preg, char *rexec, int cflags); char *xtzset(char *new); diff --git a/lib/xwrap.c b/lib/xwrap.c index 2c3b6041..fba262b9 100644 --- a/lib/xwrap.c +++ b/lib/xwrap.c @@ -789,36 +789,45 @@ double xstrtod(char *s) } // parse fractional seconds with optional s/m/h/d suffix -long xparsetime(char *arg, long units, long *fraction) +long xparsetime(char *arg, long zeroes, long *fraction) { - double d; - long l; + long l, fr; char *end; - if (*arg != '.' && !isdigit(*arg)) error_exit("bad %s", arg); - if (CFG_TOYBOX_FLOAT) d = strtod(arg, &end); - else l = strtoul(arg, &end, 10); - - if (end == arg) error_exit("Not a number '%s'", arg); - arg = end; + if (*arg != '.' && !isdigit(*arg)) error_exit("Not a number '%s'", arg); + l = strtoul(arg, &end, 10); + fr = 0; + if (*end == '.') { + end++; + while (zeroes--) { + fr *= 10; + if (isdigit(*end)) fr += *end++-'0'; + } + } + if (fraction) *fraction = fr; // Parse suffix - if (*arg) { - int ismhd[]={1,60,3600,86400}, i = stridx("smhd", *arg); + if (*end) { + int ismhd[]={1,60,3600,86400}, i = stridx("smhd", *end); - if (i == -1 || *(arg+1)) error_exit("Unknown suffix '%s'", arg); - if (CFG_TOYBOX_FLOAT) d *= ismhd[i]; - else l *= ismhd[i]; + if (i == -1 || *(end+1)) error_exit("Unknown suffix '%s'", end); + l *= ismhd[i]; } - if (CFG_TOYBOX_FLOAT) { - l = (long)d; - if (fraction) *fraction = units*(d-l); - } else if (fraction) *fraction = 0; - return l; } +long long xparsemillitime(char *arg) +{ + long l, ll; + + l = xparsetime(arg, 3, &ll); + + return (l*1000LL)+ll; +} + + + // Compile a regular expression into a regex_t void xregcomp(regex_t *preg, char *regex, int cflags) { diff --git a/scripts/mkflags.c b/scripts/mkflags.c index c96f7f55..6b4a527e 100644 --- a/scripts/mkflags.c +++ b/scripts/mkflags.c @@ -1,7 +1,7 @@ -// Take three word input lines on stdin (the three space separated words are -// command name, option string with current config, option string from -// allyesconfig; space separated, the last two are and double quotes) -// and produce flag #defines to stdout. +// Take three word input lines on stdin and produce flag #defines to stdout. +// The three words on each input lnie are command name, option string with +// current config, option string from allyesconfig. The three are space +// separated and the last two are in double quotes. // This is intentionally crappy code because we control the inputs. It leaks // memory like a sieve and segfaults if malloc returns null, but does the job. @@ -21,7 +21,10 @@ struct flag { int chrtype(char c) { - if (strchr("?&^-:#|@*; ", c)) return 1; + // Does this populate a GLOBALS() variable? + if (strchr("?&^-:#|@*; %", c)) return 1; + + // Is this followed by a numeric argument in optstr? if (strchr("=<>", c)) return 2; return 0; @@ -74,12 +77,12 @@ char *mark_gaps(char *flags, char *all) return n; } -// Break down a command string into struct flag list. +// Break down a command string into linked list of "struct flag". struct flag *digest(char *string) { struct flag *list = NULL; - char *err = string; + char *err = string, c; while (*string) { // Groups must be at end. @@ -108,8 +111,9 @@ struct flag *digest(char *string) continue; } - if (strchr("?&^-:#|@*; ", *string)) string++; - else if (strchr("=<>", *string)) { + c = chrtype(*string); + if (c == 1) string++; + else if (c == 2) { if (string[1]=='-') string++; if (!isdigit(string[1])) { fprintf(stderr, "%c without number in '%s'", *string, err); diff --git a/toys/net/ping.c b/toys/net/ping.c index 752879a2..ad7679fd 100644 --- a/toys/net/ping.c +++ b/toys/net/ping.c @@ -11,7 +11,7 @@ * Yes, I wimped out and capped -s at sizeof(toybuf), waiting for a complaint... // -s > 4088 = sizeof(toybuf)-sizeof(struct icmphdr), then kernel adds 20 bytes -USE_PING(NEWTOY(ping, "<1>1m#t#<0>255=64c#<0=3s#<0>4088=56I:i:W#<0=3w#<0qf46[-46]", TOYFLAG_USR|TOYFLAG_BIN)) +USE_PING(NEWTOY(ping, "<1>1m#t#<0>255=64c#<0=3s#<0>4088=56I:i%W#<0=3w#<0qf46[-46]", TOYFLAG_USR|TOYFLAG_BIN)) USE_PING(OLDTOY(ping6, ping, TOYFLAG_USR|TOYFLAG_BIN)) config PING @@ -47,18 +47,12 @@ config PING #include GLOBALS( - long w; - long W; - char *i; + long w, W, i; char *I; - long s; - long c; - long t; - long m; + long s, c, t, m; struct sockaddr *sa; int sock; - long i_ms; unsigned long sent, recv, fugit, min, max; ) @@ -115,13 +109,8 @@ void ping_main(void) struct icmphdr *ih = (void *)toybuf; // Interval - if (TT.i) { - long frac; - - TT.i_ms = xparsetime(TT.i, 1000, &frac) * 1000; - TT.i_ms += frac; - if (TT.i_ms<200 && getuid()) error_exit("need root for -i <200"); - } else TT.i_ms = (toys.optflags&FLAG_f) ? 200 : 1000; + if (!(toys.optflags&FLAG_i)) TT.i = (toys.optflags&FLAG_f) ? 200 : 1000; + else if (TT.i<200 && getuid()) error_exit("need root for -i <200"); if (!(toys.optflags&FLAG_s)) TT.s = 56; // 64-PHDR_LEN if ((toys.optflags&(FLAG_f|FLAG_c)) == FLAG_f) TT.c = 15; @@ -230,7 +219,7 @@ void ping_main(void) // Time to send the next packet? if (!tW && tnext-tnow <= 0) { - tnext += TT.i_ms; + tnext += TT.i; memset(ih, 0, sizeof(*ih)); ih->type = (ai->ai_family == AF_INET) ? 8 : 128; diff --git a/toys/other/timeout.c b/toys/other/timeout.c index b62d696e..b903c3ec 100644 --- a/toys/other/timeout.c +++ b/toys/other/timeout.c @@ -58,7 +58,7 @@ void xparsetimeval(char *s, struct timeval *tv) { long ll; - tv->tv_sec = xparsetime(s, 1000000, &ll); + tv->tv_sec = xparsetime(s, 6, &ll); tv->tv_usec = ll; } diff --git a/toys/posix/ps.c b/toys/posix/ps.c index d8f54862..833ecabe 100644 --- a/toys/posix/ps.c +++ b/toys/posix/ps.c @@ -48,8 +48,8 @@ USE_PS(NEWTOY(ps, "k(sort)*P(ppid)*aAdeflMno*O*p(pid)*s*t*Tu*U*g*G*wZ[!ol][+Ae][ // stayroot because iotop needs root to read other process' proc/$$/io // TOP and IOTOP have a large common option block used for common processing, // the default values are different but the flags are in the same order. -USE_TOP(NEWTOY(top, ">0O*" "Hk*o*p*u*s#<1d:m#n#<1bq[!oO]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE)) -USE_IOTOP(NEWTOY(iotop, ">0AaKO" "Hk*o*p*u*s#<1=7d:m#n#<1bq", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT|TOYFLAG_LOCALE)) +USE_TOP(NEWTOY(top, ">0O*" "Hk*o*p*u*s#<1d%<100=3000m#n#<1bq[!oO]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE)) +USE_IOTOP(NEWTOY(iotop, ">0AaKO" "Hk*o*p*u*s#<1=7d%<100=3000m#n#<1bq", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT|TOYFLAG_LOCALE)) USE_PGREP(NEWTOY(pgrep, "?cld:u*U*t*s*P*g*G*fnovxL:[-no]", TOYFLAG_USR|TOYFLAG_BIN)) USE_PKILL(NEWTOY(pkill, "?Vu*U*t*s*P*g*G*fnovxl:[-no]", TOYFLAG_USR|TOYFLAG_BIN)) @@ -193,12 +193,8 @@ GLOBALS( struct arg_list *G, *g, *U, *u, *t, *s, *p, *O, *o, *P, *k; } ps; struct { - long n, m; - char *d; - long s; + long n, m, d, s; struct arg_list *u, *p, *o, *k, *O; - - long d_ms; } top; struct { char *L; @@ -1638,8 +1634,8 @@ static void top_common( } now = millitime(); - if (timeout<=now) timeout = new.whence+TT.top.d_ms; - if (timeout<=now || timeout>now+TT.top.d_ms) timeout = now+TT.top.d_ms; + if (timeout<=now) timeout = new.whence+TT.top.d; + if (timeout<=now || timeout>now+TT.top.d) timeout = now+TT.top.d; // In batch mode, we ignore the keyboard. if (toys.optflags&FLAG_b) { @@ -1693,13 +1689,6 @@ static void top_common( static void top_setup(char *defo, char *defk) { - if (TT.top.d) { - long frac; - - TT.top.d_ms = xparsetime(TT.top.d, 1000, &frac) * 1000; - TT.top.d_ms += frac; - } else TT.top.d_ms = 3000; - TT.ticks = sysconf(_SC_CLK_TCK); // units for starttime/uptime TT.tty = tty_fd() != -1; diff --git a/toys/posix/sleep.c b/toys/posix/sleep.c index c7b8bbf1..0381c107 100644 --- a/toys/posix/sleep.c +++ b/toys/posix/sleep.c @@ -31,6 +31,6 @@ void sleep_main(void) { struct timespec tv; - tv.tv_sec = xparsetime(*toys.optargs, 1000000000, &tv.tv_nsec); + tv.tv_sec = xparsetime(*toys.optargs, 9, &tv.tv_nsec); toys.exitval = !!nanosleep(&tv, NULL); } -- cgit v1.2.3