/* See LICENSE file for copyright and license details. */ #include #include #include #include "util.h" static int digitsleft(const char *d) { int shift; char *exp; if (*d == '+') d++; exp = strpbrk(d, "eE"); shift = exp ? estrtonum(exp + 1, INT_MIN, INT_MAX) : 0; return MAX(0, strspn(d, "-0123456789") + shift); } static int digitsright(const char *d) { int shift, after; char *exp; exp = strpbrk(d, "eE"); shift = exp ? estrtonum(&exp[1], INT_MIN, INT_MAX) : 0; after = (d = strchr(d, '.')) ? strspn(&d[1], "0123456789") : 0; return MAX(0, after - shift); } static int validfmt(const char *fmt) { int occur = 0; literal: while (*fmt) if (*fmt++ == '%') goto format; return occur == 1; format: if (*fmt == '%') { fmt++; goto literal; } fmt += strspn(fmt, "-+#0 '"); fmt += strspn(fmt, "0123456789"); if (*fmt == '.') { fmt++; fmt += strspn(fmt, "0123456789"); } if (*fmt == 'L') fmt++; switch (*fmt) { case 'f': case 'F': case 'g': case 'G': case 'e': case 'E': case 'a': case 'A': occur++; goto literal; default: return 0; } } static void usage(void) { eprintf("usage: %s [-f fmt] [-s sep] [-w] " "[startnum [step]] endnum\n", argv0); } int main(int argc, char *argv[]) { double start, step, end, out, dir; int wflag = 0, left, right; char *tmp, ftmp[BUFSIZ], *fmt = ftmp; const char *starts = "1", *steps = "1", *ends = "1", *sep = "\n"; ARGBEGIN { case 'f': if (!validfmt(tmp=EARGF(usage()))) eprintf("%s: invalid format\n", tmp); fmt = tmp; break; case 's': sep = EARGF(usage()); break; case 'w': wflag = 1; break; default: usage(); } ARGEND switch (argc) { case 3: steps = argv[1]; argv[1] = argv[2]; /* fallthrough */ case 2: starts = argv[0]; argv++; /* fallthrough */ case 1: ends = argv[0]; break; default: usage(); } start = estrtod(starts); step = estrtod(steps); end = estrtod(ends); dir = (step > 0) ? 1.0 : -1.0; if (step == 0 || start * dir > end * dir) return 1; if (fmt == ftmp) { right = MAX(digitsright(starts), MAX(digitsright(ends), digitsright(steps))); if (wflag) { left = MAX(digitsleft(starts), digitsleft(ends)); snprintf(ftmp, sizeof ftmp, "%%0%d.%df", right + left + (right != 0), right); } else snprintf(ftmp, sizeof ftmp, "%%.%df", right); } for (out = start; out * dir <= end * dir; out += step) { if (out != start) fputs(sep, stdout); printf(fmt, out); } putchar('\n'); return fshut(stdout, ""); }