Here's a full patch including two small manpage tweaks. It contains the three hunks that fix FreeBSD's regress tests from my previous mail:
* initialize begin, ender, step, reps (from attila) * set steps to -1 if ender < begin (adapted from FreeBSD) * properly skip "%%" in the format string (from OpenBSD r1.8, pjanzen) In addition, get rid of the nasty mask loop and just compute whatever we need to compute in the most sensible order. This simplifies the code quite a bit and is inspired by dsl@NetBSD's r1.21. Note that the output loop only depends on reps, begin and step, so we never need to compute ender and we only need to compute something else if ender was specified. We now only produce infinite output if it was explicitly requested by setting reps or steps to zero on the command line. Also note that if randomized output is requested, there's never the need to compute anything, so just skip that piece of code in that case. I will import a tweaked and expanded version of the regress tests when the tree is fully unlocked. Index: jot.1 =================================================================== RCS file: /var/cvs/src/usr.bin/jot/jot.1,v retrieving revision 1.21 diff -u -p -r1.21 jot.1 --- jot.1 17 Jul 2016 04:15:25 -0000 1.21 +++ jot.1 27 Jul 2016 19:27:38 -0000 @@ -104,11 +104,10 @@ in which case the data is inserted rathe The last four arguments indicate, respectively, the maximum number of data, the lower bound, the upper bound, and the step size. -While at least one of them must appear, -any of the other three may be omitted, and +Any of these may be omitted, and will be considered as such if given as .Ql - . -Any three of these arguments determines the fourth. +Any three of these arguments determine the fourth. If four are specified and the given and computed values of .Ar reps conflict, the lower value is used. Index: jot.c =================================================================== RCS file: /var/cvs/src/usr.bin/jot/jot.c,v retrieving revision 1.28 diff -u -p -r1.28 jot.c --- jot.c 17 Jul 2016 04:04:46 -0000 1.28 +++ jot.c 28 Jul 2016 11:26:16 -0000 @@ -52,12 +52,17 @@ #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; -static double ender; -static double s; -static long reps; +static double begin = BEGIN_DEF; +static double ender = ENDER_DEF; +static double step = STEP_DEF; +static long reps = REPS_DEF; static bool randomize; static bool infinity; static bool boring; @@ -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,114 +164,65 @@ 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; } break; case 0: - usage(); + /* Use defaults. */ break; default: 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; - break; - case 006: - reps = REPS_DEF; - mask = 016; - break; - case 007: - if (randomize) { - reps = REPS_DEF; - mask = 0; - break; - } - if (s == 0.0) { + if (!randomize) { + switch (mask) { + case BEGIN | ENDER: + step = ender < begin ? -1 : 1; + /* FALLTHROUGH */ + case BEGIN | ENDER | STEP: + if (step == 0.0) reps = 0; - mask = 0; - break; + else { + reps = (ender - begin + step) / step; + if (reps <= 0) + errx(1, "Impossible stepsize"); } - reps = (ender - begin + s) / s; - 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) + case ENDER: + case ENDER | STEP: + case REPS | ENDER: + case REPS | ENDER | STEP: + 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; + begin = ender - reps * step + step; break; - case 016: + case REPS | BEGIN | ENDER: if (reps == 0) - errx(1, "Infinite sequences cannot be bounded"); + errx(1, "Cannot specify end if reps == 0"); else if (reps == 1) - s = 0.0; + step = 0.0; else - s = (ender - begin) / (reps - 1); - mask = 0; + step = (ender - begin) / (reps - 1); break; - case 017: /* if reps given and implied, */ - if (!randomize && s != 0.0) { - long t = (ender - begin + s) / s; + case REPS | BEGIN | ENDER | STEP: + if (reps == 0) + errx(1, "Cannot specify end if reps == 0"); + if (step != 0.0) { + long t = (ender - begin + step) / step; if (t <= 0) errx(1, "Impossible stepsize"); if (t < reps) /* take lesser */ reps = t; } - mask = 0; break; default: - errx(1, "bad mask"); + /* Use defaults. */ + break; } + } if (reps == 0) infinity = true; if (randomize) { @@ -315,14 +271,13 @@ 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 @@ -394,8 +349,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;