From 6fda8b0f5c508efb346e839dd598880940315198 Mon Sep 17 00:00:00 2001 From: tb Date: Fri, 12 Aug 2016 21:17:41 +0000 Subject: [PATCH] The last four argumens of jot (reps, begin, end, step) can all be specified or omitted, yielding 16 possible combinations, plus a few special cases. Instead of hardcoded values, use names to make the bit patterns that indicate which values were specified human readable. Decide once and for all what to do in a single switch statement. Don't enter said switch when random output is requested since that simply makes no sense at all. While there, make the error messages a bit more meaningful and fix a bogus value assigned to begin for jot -r x - y z that has been there since -r1.1. All regression tests now pass. Inspired by David Laight (dsl)'s r1.21 of NetBSD's jot. "move fast and break stuff" tedu agreement from deraadt --- usr.bin/jot/jot.c | 164 ++++++++++++++++++++-------------------------- 1 file changed, 71 insertions(+), 93 deletions(-) diff --git a/usr.bin/jot/jot.c b/usr.bin/jot/jot.c index f03ccb1dbbf..160059c8b1e 100644 --- a/usr.bin/jot/jot.c +++ b/usr.bin/jot/jot.c @@ -1,4 +1,4 @@ -/* $OpenBSD: jot.c,v 1.31 2016/08/05 13:43:38 tb Exp $ */ +/* $OpenBSD: jot.c,v 1.32 2016/08/12 21:17:41 tb Exp $ */ /* $NetBSD: jot.c,v 1.3 1994/12/02 20:29:43 pk Exp $ */ /*- @@ -52,11 +52,16 @@ #define ENDER_DEF 100 #define STEP_DEF 1 +#define STEP 1 +#define ENDER 2 +#define BEGIN 4 +#define REPS 8 + #define is_default(s) (strcmp((s), "-") == 0) static double begin = BEGIN_DEF; static double ender = ENDER_DEF; -static double s = STEP_DEF; +static double step = STEP_DEF; static long reps = REPS_DEF; static bool randomize; static bool infinity; @@ -131,9 +136,9 @@ main(int argc, char *argv[]) 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 +146,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 +154,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 +164,7 @@ 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 (prec == -1) prec = 0; } @@ -172,101 +177,74 @@ main(int argc, char *argv[]) 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; + /* If random output is requested, use defaults for omitted values. */ + 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. + * 4. reps == 0 means infinite output + */ + switch (mask) { /* Four cases involve both begin and ender. */ + case REPS | BEGIN | ENDER | STEP: + if (reps == 0) + 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 005: - reps = REPS_DEF; - mask = 015; + case REPS | BEGIN | ENDER: + if (reps == 0) + errx(1, + "Can't specify end of infinite sequence"); + if (reps == 1) + step = 0.0; + else + step = (ender - begin) / (reps - 1); break; - case 006: - s = ender > begin ? 1 : -1; - mask = 007; + case BEGIN | ENDER: + step = ender > begin ? 1 : -1; /* FreeBSD's behavior. */ /* FALLTHROUGH */ - case 007: - if (randomize) { - reps = REPS_DEF; - mask = 0; - break; - } - if (s == 0.0) { + case BEGIN | ENDER | STEP: + if (step == 0.0) { reps = 0; - mask = 0; 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: + case ENDER: /* Four cases involve only ender. */ + case ENDER | STEP: + case REPS | ENDER: + case REPS | ENDER | STEP: 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; + 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) { @@ -315,14 +293,14 @@ main(int argc, char *argv[]) if (putdata(v, reps == i && !infinity)) errx(1, "range error in conversion: %f", v); } - } - else - for (i = 1, x = begin; i <= reps || infinity; i++, x += s) + } else { + 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); + } if (finalnl) putchar('\n'); - exit(0); + return (0); } static int -- 2.20.1