diff options
Diffstat (limited to 'src/usr.bin/jot/jot.c')
-rw-r--r-- | src/usr.bin/jot/jot.c | 278 |
1 files changed, 124 insertions, 154 deletions
diff --git a/src/usr.bin/jot/jot.c b/src/usr.bin/jot/jot.c index 08da69f..0de3a51 100644 --- a/src/usr.bin/jot/jot.c +++ b/src/usr.bin/jot/jot.c @@ -1,4 +1,4 @@ -/* $OpenBSD: jot.c,v 1.28 2016/07/17 04:04:46 tb Exp $ */ +/* $OpenBSD: jot.c,v 1.36 2016/09/02 14:23:09 tb Exp $ */ /* $NetBSD: jot.c,v 1.3 1994/12/02 20:29:43 pk Exp $ */ /*- @@ -36,44 +36,45 @@ * Author: John Kunze, Office of Comp. Affairs, UCB */ -#include <err.h> -#include <stdbool.h> #include <ctype.h> +#include <err.h> #include <limits.h> #include <math.h> +#include <stdbool.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> -#define REPS_DEF 100 -#define BEGIN_DEF 1 -#define ENDER_DEF 100 -#define STEP_DEF 1 +#define REPS 1 +#define BEGIN 2 +#define ENDER 4 +#define STEP 8 #define is_default(s) (strcmp((s), "-") == 0) -static double begin; -static double ender; -static double s; -static long reps; -static bool randomize; -static bool infinity; -static bool boring; +static long reps = 100; +static double begin = 1; +static double ender = 100; +static double step = 1; + +static char format[BUFSIZ]; +static char sepstring[BUFSIZ] = "\n"; static int prec = -1; +static bool boring; +static bool chardata; +static bool finalnl = true; +static bool infinity; static bool intdata; static bool longdata; -static bool chardata; static bool nosign; -static bool finalnl = true; -static char sepstring[BUFSIZ] = "\n"; -static char format[BUFSIZ]; +static bool randomize; static void getformat(void); static int getprec(char *); static int putdata(double, bool); -static void usage(void); +static void __dead usage(void); int main(int argc, char *argv[]) @@ -89,10 +90,13 @@ main(int argc, char *argv[]) if (pledge("stdio", NULL) == -1) err(1, "pledge"); - while ((ch = getopt(argc, argv, "rb:w:cs:np:")) != -1) + while ((ch = getopt(argc, argv, "b:cnp:rs:w:")) != -1) { switch (ch) { - case 'r': - randomize = true; + case 'b': + boring = true; + if (strlcpy(format, optarg, sizeof(format)) >= + sizeof(format)) + errx(1, "-b word too long"); break; case 'c': chardata = true; @@ -100,40 +104,38 @@ main(int argc, char *argv[]) case 'n': finalnl = false; break; - case 'b': - boring = true; - if (strlcpy(format, optarg, sizeof(format)) >= - sizeof(format)) - errx(1, "-b word too long"); + case 'p': + prec = strtonum(optarg, 0, INT_MAX, &errstr); + if (errstr != NULL) + errx(1, "bad precision value, %s: %s", errstr, + optarg); break; - case 'w': - if (strlcpy(format, optarg, sizeof(format)) >= - sizeof(format)) - errx(1, "-w word too long"); + case 'r': + randomize = true; break; case 's': if (strlcpy(sepstring, optarg, sizeof(sepstring)) >= sizeof(sepstring)) errx(1, "-s string too long"); break; - case 'p': - prec = strtonum(optarg, 0, INT_MAX, &errstr); - if (errstr != NULL) - errx(1, "bad precision value, %s: %s", errstr, - optarg); + case 'w': + if (strlcpy(format, optarg, sizeof(format)) >= + sizeof(format)) + errx(1, "-w word too long"); break; default: usage(); } + } argc -= optind; argv += optind; switch (argc) { /* examine args right to left, falling thru cases */ case 4: if (!is_default(argv[3])) { - if (!sscanf(argv[3], "%lf", &s)) + if (!sscanf(argv[3], "%lf", &step)) errx(1, "Bad s value: %s", argv[3]); - mask |= 01; + mask |= STEP; if (randomize) warnx("random seeding not supported"); } @@ -141,7 +143,7 @@ main(int argc, char *argv[]) if (!is_default(argv[2])) { if (!sscanf(argv[2], "%lf", &ender)) ender = argv[2][strlen(argv[2])-1]; - mask |= 02; + mask |= ENDER; if (prec == -1) n = getprec(argv[2]); } @@ -149,7 +151,7 @@ main(int argc, char *argv[]) if (!is_default(argv[1])) { if (!sscanf(argv[1], "%lf", &begin)) begin = argv[1][strlen(argv[1])-1]; - mask |= 04; + mask |= BEGIN; if (prec == -1) prec = getprec(argv[1]); if (n > prec) /* maximum precision */ @@ -159,7 +161,9 @@ main(int argc, char *argv[]) if (!is_default(argv[0])) { if (!sscanf(argv[0], "%ld", &reps)) errx(1, "Bad reps value: %s", argv[0]); - mask |= 010; + mask |= REPS; + if (reps == 0) + infinity = true; if (prec == -1) prec = 0; } @@ -171,105 +175,80 @@ main(int argc, char *argv[]) errx(1, "Too many arguments. What do you mean by %s?", argv[4]); } + getformat(); - while (mask) /* 4 bit mask has 1's where last 4 args were given */ - switch (mask) { /* fill in the 0's by default or computation */ - case 001: - reps = REPS_DEF; - mask = 011; - break; - case 002: - reps = REPS_DEF; - mask = 012; - break; - case 003: - reps = REPS_DEF; - mask = 013; - break; - case 004: - reps = REPS_DEF; - mask = 014; - break; - case 005: - reps = REPS_DEF; - mask = 015; + + if (!randomize) { + /* + * Consolidate the values of reps, begin, ender, step: + * The formula ender - begin == (reps - 1) * step shows that any + * three determine the fourth (unless reps == 1 or step == 0). + * The manual states the following rules: + * 1. If four are specified, compare the given and the computed + * value of reps and take the smaller of the two. + * 2. If steps was omitted, it takes the default, unless both + * begin and ender were specified. + * 3. Assign defaults to omitted values for reps, begin, ender, + * from left to right. + */ + switch (mask) { /* Four cases involve both begin and ender. */ + case REPS | BEGIN | ENDER | STEP: + if (infinity) + errx(1, + "Can't specify end of infinite sequence"); + if (step != 0.0) { + long t = (ender - begin + step) / step; + if (t <= 0) + errx(1, "Impossible stepsize"); + if (t < reps) + reps = t; + } break; - case 006: - reps = REPS_DEF; - mask = 016; + case REPS | BEGIN | ENDER: + if (infinity) + errx(1, + "Can't specify end of infinite sequence"); + if (reps == 1) + step = 0.0; + else + step = (ender - begin) / (reps - 1); break; - case 007: - if (randomize) { - reps = REPS_DEF; - mask = 0; - break; - } - if (s == 0.0) { + case BEGIN | ENDER: + step = ender > begin ? 1 : -1; /* FreeBSD's behavior. */ + /* FALLTHROUGH */ + case BEGIN | ENDER | STEP: + if (step == 0.0) { reps = 0; - mask = 0; + infinity = true; break; } - reps = (ender - begin + s) / s; + reps = (ender - begin + step) / step; if (reps <= 0) errx(1, "Impossible stepsize"); - mask = 0; - break; - case 010: - begin = BEGIN_DEF; - mask = 014; - break; - case 011: - begin = BEGIN_DEF; - mask = 015; break; - case 012: - s = STEP_DEF; - mask = 013; - break; - case 013: - if (randomize) - begin = BEGIN_DEF; - else if (reps == 0) - errx(1, "Must specify begin if reps == 0"); - begin = ender - reps * s + s; - mask = 0; - break; - case 014: - s = STEP_DEF; - mask = 015; - break; - case 015: - if (randomize) - ender = ENDER_DEF; - else - ender = begin + reps * s - s; - mask = 0; - break; - case 016: - if (reps == 0) - errx(1, "Infinite sequences cannot be bounded"); - else if (reps == 1) - s = 0.0; - else - s = (ender - begin) / (reps - 1); - mask = 0; - break; - case 017: /* if reps given and implied, */ - if (!randomize && s != 0.0) { - long t = (ender - begin + s) / s; - if (t <= 0) - errx(1, "Impossible stepsize"); - if (t < reps) /* take lesser */ - reps = t; - } - mask = 0; + case ENDER: /* Four cases involve only ender. */ + case ENDER | STEP: + case REPS | ENDER: + case REPS | ENDER | STEP: + if (infinity) + errx(1, + "Must specify start of infinite sequence"); + begin = ender - reps * step + step; break; default: - errx(1, "bad mask"); + /* + * The remaining eight cases omit ender. We don't need + * to compute anything because only reps, begin, step + * are used for producing output below. Rules 2. and 3. + * together imply that ender will be set last. + */ + break; } - if (reps == 0) - infinity = true; - if (randomize) { + + for (i = 1, x = begin; i <= reps || infinity; i++, x += step) + if (putdata(x, reps == i && !infinity)) + errx(1, "range error in conversion: %f", x); + } else { /* Random output: use defaults for omitted values. */ bool use_unif; uint32_t pow10 = 1; uint32_t uintx = 0; /* Initialized to make gcc happy. */ @@ -316,13 +295,11 @@ main(int argc, char *argv[]) errx(1, "range error in conversion: %f", v); } } - else - for (i = 1, x = begin; i <= reps || infinity; i++, x += s) - if (putdata(x, reps == i && !infinity)) - errx(1, "range error in conversion: %f", x); + if (finalnl) putchar('\n'); - exit(0); + + return 0; } static int @@ -334,31 +311,31 @@ putdata(double x, bool last) if (x <= (double)ULONG_MAX && x >= 0.0) printf(format, (unsigned long)x); else - return (1); + return 1; } else if (longdata) { if (x <= (double)LONG_MAX && x >= (double)LONG_MIN) printf(format, (long)x); else - return (1); + return 1; } else if (chardata || (intdata && !nosign)) { if (x <= (double)INT_MAX && x >= (double)INT_MIN) printf(format, (int)x); else - return (1); + return 1; } else if (intdata) { if (x <= (double)UINT_MAX && x >= 0.0) printf(format, (unsigned int)x); else - return (1); + return 1; } else printf(format, x); if (!last) fputs(sepstring, stdout); - return (0); + return 0; } -static void +static void __dead usage(void) { (void)fprintf(stderr, "usage: jot [-cnr] [-b word] [-p precision] " @@ -370,18 +347,9 @@ usage(void) static int getprec(char *s) { - char *p; - char *q; - - for (p = s; *p != '\0'; p++) - if (*p == '.') - break; - if (*p == '\0') - return (0); - for (q = ++p; *p != '\0'; p++) - if (!isdigit((unsigned char)*p)) - break; - return (p - q); + if ((s = strchr(s, '.')) == NULL) + return 0; + return strspn(s + 1, "0123456789"); } static void @@ -394,8 +362,11 @@ getformat(void) if (boring) /* no need to bother */ return; for (p = format; *p != '\0'; p++) /* look for '%' */ - if (*p == '%' && *(p+1) != '%') /* leave %% alone */ - break; + if (*p == '%') { + if (*(p+1) != '%') + break; + p++; /* leave %% alone */ + } sz = sizeof(format) - strlen(format) - 1; if (*p == '\0' && !chardata) { int n; @@ -474,7 +445,6 @@ getformat(void) fmt_broken: *++p = '\0'; errx(1, "illegal or unsupported format '%s'", p2); - /* NOTREACHED */ } while (*++p != '\0') if (*p == '%' && *(p+1) != '\0' && *(p+1) != '%') |