sbase

suckless unix tools
git clone git://git.2f30.org/sbase.git
Log | Files | Refs | README | LICENSE

commit 6e0f5c14093c7edadb556f1862dab432ad4826c2
parent c018f86fc752e1f1743985852993bfa755c637bd
Author: Connor Lane Smith <cls@lubutu.com>
Date:   Thu May 10 19:20:16 +0100

seq: some cleanup
Diffstat:
seq.1 | 18++++++++++--------
seq.c | 245+++++++++++++++++++++++++++++++++++--------------------------------------------
util.h | 3+++
util/estrtol.c | 4++--
4 files changed, 122 insertions(+), 148 deletions(-)
diff --git a/seq.1 b/seq.1 @@ -9,20 +9,22 @@ seq \- print a sequence of numbers .RB [ \-s .IR separator ] .RI [ start -.RI [step] ] +.RI [ step ]] .RI end .SH DESCRIPTION .B seq -will print numbers from -.I START -to -.I END, -in steps of -.I STEP. +will print a sequence of numbers from +.I start +(default 1) to +.IR end , +in +.IR step +intervals (default 1). .SH OPTIONS .TP .BI \-f " format" -specifies the printf style for the output lines +specifies the format used for output lines, as per +.IR printf (3). .TP .BI \-s " separator" specifies the separator to print between output lines diff --git a/seq.c b/seq.c @@ -1,113 +1,29 @@ /* See LICENSE file for copyright and license details. */ +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> -#include <stdbool.h> -#include <libgen.h> - #include "util.h" -#define MAX(a, b) (((a) > (b))? (a):(b)) - -int -validfloat(char *fmt) -{ - char *end; - - fmt += strspn(fmt, " "); - strtod(fmt, &end); - if (fmt == end || end != fmt + strlen(fmt)) - return 0; - - return 1; -} - -int -digitsleft(char *d) -{ - char *exp; - int shift; - - if (d[0] == '+') - d++; - exp = strpbrk(d, "eE"); - shift = exp? atoi(exp+1) : 0; - - return MAX(0, strspn(d, "-0123456789")+shift); -} - -int -digitsright(char *d) -{ - char *exp; - int shift, after; - - exp = strpbrk(d, "eE"); - shift = exp ? atoi(exp+1) : 0; - after = (d = strchr(d, '.'))? strspn(d+1, "0123456789") : 0; - - return MAX(0, after-shift); -} - -int -validfmt(char *fmt) -{ - int occur; - - occur = 0; - -NonFormat: - while(*fmt) { - if (*fmt++ == '%') - goto Format; - } - return (occur == 1); -Format: - if (*fmt == '%') { - fmt++; - goto NonFormat; - } - fmt += strspn(fmt, "-+#0 '"); - fmt += strspn(fmt, "0123456789"); - if (*fmt == '.') { - fmt ++; - fmt += strspn(fmt, "0123456789"); - } - if (*fmt == 'L') - fmt++; - if (*fmt == '\0') - return 0; - if (strchr("fFgGeEaA", *fmt)) { - occur++; - goto NonFormat; - } - return 0; -} +static int digitsleft(const char *); +static int digitsright(const char *); +static double estrtod(const char *); +static bool validfmt(const char *); int main(int argc, char *argv[]) { - char c, *fmt, ftmp[4096], *sep, *starts, *steps, *ends; - bool wflag, fflag; + const char *starts = "1", *steps = "1", *ends = "1", *sep = "\n"; + bool fflag = false, wflag = false; + char c, ftmp[BUFSIZ], *fmt = ftmp; double start, step, end, out, dir; - int left, right; - - sep = "\n"; - fmt = ftmp; - - wflag = false; - fflag = false; - starts = "1"; - steps = "1"; - ends = "1"; - - while((c = getopt(argc, argv, "f:s:w")) != -1) { + while((c = getopt(argc, argv, "f:s:w")) != -1) switch(c) { case 'f': - if (!validfmt(optarg)) - eprintf("invalid format.\n"); + if(!validfmt(optarg)) + eprintf("%s: invalid format\n", optarg); fmt = optarg; fflag = true; break; @@ -118,10 +34,6 @@ main(int argc, char *argv[]) wflag = true; break; } - } - - if (wflag && fflag) - eprintf("-f and -w cannot be combined.\n"); switch(argc-optind) { case 3: @@ -131,59 +43,116 @@ main(int argc, char *argv[]) break; case 2: starts = argv[optind++]; - ends = argv[optind++]; - break; + /* fallthrough */ case 1: ends = argv[optind++]; break; default: - eprintf("usage: %s [-w] [-f fmt] [-s separator] " - "[start [step]] end\n", - basename(argv[0])); + eprintf("usage: %s [-w] [-f fmt] [-s separator] [start [step]] end\n", argv[0]); } + start = estrtod(starts); + step = estrtod(steps); + end = estrtod(ends); - if (!validfloat(starts)) - eprintf("start is not a valid float.\n"); - if (!validfloat(steps)) - eprintf("step is not a valid float.\n"); - if (!validfloat(ends)) - eprintf("end is not a valid float.\n"); - - start = atof(starts); - step = atof(steps); - end = atof(ends); - dir = (step > 0)? 1.0 : -1.0; - - if (step == 0) - return EXIT_FAILURE; - if (start * dir > end * dir) + dir = (step > 0) ? 1.0 : -1.0; + if(step == 0 || start * dir > end * dir) return EXIT_FAILURE; - 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 if (fmt == ftmp) { - snprintf(ftmp, sizeof(ftmp), "%%.%df", right); - } + if(fmt == ftmp) { + int right = MAX(digitsright(starts), + MAX(digitsright(ends), + digitsright(steps))); - for (out = start;;) { - printf(fmt, out); + if(wflag) { + int left = MAX(digitsleft(starts), digitsleft(ends)); - out += step; - if (out * dir <= end * dir) { - printf("%s", sep); - } else { - break; + 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); } printf("\n"); return EXIT_SUCCESS; } +int +digitsleft(const char *d) +{ + char *exp; + int shift; + + if(*d == '+') + d++; + exp = strpbrk(d, "eE"); + shift = exp ? atoi(&exp[1]) : 0; + + return MAX(0, strspn(d, "-0123456789")+shift); +} + +int +digitsright(const char *d) +{ + char *exp; + int shift, after; + + exp = strpbrk(d, "eE"); + shift = exp ? atoi(&exp[1]) : 0; + after = (d = strchr(d, '.')) ? strspn(&d[1], "0123456789") : 0; + + return MAX(0, after-shift); +} + +double +estrtod(const char *s) +{ + char *end; + double d; + + d = strtod(s, &end); + if(end == s || *end != '\0') + eprintf("%s: not a real number\n", s); + return d; +} + +bool +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 false; + } +} diff --git a/util.h b/util.h @@ -2,6 +2,9 @@ #define UTF8_POINT(c) (((c) & 0xc0) != 0x80) +#define MIN(x,y) ((x) < (y) ? (x) : (y)) +#define MAX(x,y) ((x) > (y) ? (x) : (y)) + char *agetcwd(void); void apathmax(char **, long *); void enmasse(int, char **, int (*)(const char *, const char *)); diff --git a/util/estrtol.c b/util/estrtol.c @@ -12,9 +12,9 @@ estrtol(const char *s, int base) n = strtol(s, &end, base); if(*end != '\0') { if(base == 0) - eprintf("%s: not a number\n", s); + eprintf("%s: not an integer\n", s); else - eprintf("%s: not a base %d number\n", s, base); + eprintf("%s: not a base %d integer\n", s, base); } return n; }