From 29ce2560a74273eb7cd97b227249c87256f78710 Mon Sep 17 00:00:00 2001 From: Christoph Lohmann <20h@r-36.net> Date: Mon, 16 Apr 2012 21:46:59 +0200 Subject: [PATCH] Fixes and checks for seq. Thanks David Galos! --- LICENSE | 1 + Makefile | 1 + seq.c | 281 +++++++++++++++++++++++++++++-------------------------- 3 files changed, 152 insertions(+), 131 deletions(-) diff --git a/LICENSE b/LICENSE index 4c2eae2..faa3c12 100644 --- a/LICENSE +++ b/LICENSE @@ -10,6 +10,7 @@ MIT/X Consortium License © 2012 William Haddon © 2012 Kurt H. Maier © 2012 Christoph Lohmann <20h@r-36.net> +© 2012 David Galos Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/Makefile b/Makefile index 3ec736e..950414c 100644 --- a/Makefile +++ b/Makefile @@ -52,6 +52,7 @@ SRC = \ tty.c \ uname.c \ seq.c \ + seq-test.c \ wc.c OBJ = $(SRC:.c=.o) $(LIB) diff --git a/seq.c b/seq.c index 7f83b34..2e88ed9 100644 --- a/seq.c +++ b/seq.c @@ -5,163 +5,182 @@ #include #include #include +#include #include "util.h" -char afmt[4096]; +#define MAX(a, b) (((a) > (b))? (a):(b)) -char * -getalignedwidthfmt(char *fmt, char *starts, char *steps, char *ends) +int +validfloat(char *fmt) { - char starttmp[4096], steptmp[4096], endtmp[4096]; - char *startdelim, *stepdelim, *enddelim; - int startl, startr, stepr, endl, endr; - int maxl, maxr; + char *end; - /* - * 1.) Get a temp buffer we can work in. - * 2.) Calculate the *r(ight) and *l(eft) size. - */ - memmove(starttmp, starts, strlen(starts)+1); - startdelim = strchr(starttmp, '.'); - if (startdelim != NULL) { - startdelim[0] = '\0'; - startr = strlen(startdelim+1); - } else { - startr = 0; - } - startl = strlen(starttmp); - if (starttmp[0] == '+') - startl--; + fmt += strspn(fmt, " "); + strtod(fmt, &end); + if (fmt == end || end != fmt + strlen(fmt)) + return 0; - memmove(endtmp, ends, strlen(ends)+1); - enddelim = strchr(endtmp, '.'); - if (enddelim != NULL) { - enddelim[0] = '\0'; - endr = strlen(enddelim+1); - } else { - endr = 0; - } - endl = strlen(endtmp); - if (endtmp[0] == '+') - endl--; + return 1; +} - /* - * We do not care for the left length of the step, because it - * will never be displayed. - */ - memmove(steptmp, steps, strlen(steps)+1); - stepdelim = strchr(steptmp, '.'); - if (stepdelim != NULL) { - stepdelim[0] = '\0'; - stepr = strlen(stepdelim+1); - } else { - stepr = 0; - } +int +digitsleft(char *d) +{ + char *exp; + int shift; - maxl = (startl > endl)? startl : endl; - maxr = (startl > endr)? startr : endr; - if (stepr > maxr) - maxr = stepr; + if (d[0] == '-' || d[0] == '+') + d++; + exp = strpbrk(d, "eE"); + shift = exp? atoi(exp+1) : 0; - if (maxl <= 1) { - snprintf(afmt, sizeof(afmt), "%%.%df", maxr); - } else if (maxr == 0) { - snprintf(afmt, sizeof(afmt), "%%0%d.f", maxl); - } else { - snprintf(afmt, sizeof(afmt), "%%0%d.%df", maxl+maxr+1, maxr); - } + return MAX(0, strspn(d, "0123456789")+shift); +} - return afmt; +int +digitsright(char *d) +{ + char *exp; + int shift, after; + + if (d[0] == '-' || d[0] == '+') + d++; + 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) +{ + regex_t reg; + int ret; + + regcomp(®, "\\([^%]|%%\\)*%[0-9]*\\.[0-9]*[fFgG]" + "\\([^%]|%%\\)*", REG_NOSUB); + ret = regexec(®, fmt, 0, NULL, 0); + regfree(®); + + return (ret == 0); } int main(int argc, char *argv[]) { - char c, *fmt, *sep, *starts, *steps, *ends; - bool wflag = false; - double start, step, end, out; + char c, *fmt, ftmp[4096], *sep, *starts, *steps, *ends; + bool wflag, fflag; + double start, step, end, out; + int left, right; - sep = "\n"; - fmt = "%G"; + sep = "\n"; + fmt = ftmp; - starts = "1"; - steps = "1"; - ends = "1"; + wflag = false; + fflag = false; - while((c = getopt(argc, argv, "f:s:w")) != -1) { - switch(c) { - case 'f': - fmt = optarg; - break; - case 's': - sep = optarg; - break; - case 'w': - wflag = true; - break; - } - } + starts = "1"; + steps = "1"; + ends = "1"; - switch(argc-optind) { - case 3: - starts = argv[optind++]; - steps = argv[optind++]; - ends = argv[optind++]; - break; - case 2: - starts = argv[optind++]; - ends = argv[optind++]; - break; - case 1: - ends = argv[optind++]; - break; - default: - eprintf("usage: %s [-w] [-f fmt] [-s separator] [start [step]]" - " end\n", basename(argv[0])); - } + while((c = getopt(argc, argv, "f:s:w")) != -1) { + switch(c) { + case 'f': + if (!validfmt(optarg)) + eprintf("invalid format.\n"); + fmt = optarg; + fflag = true; + break; + case 's': + sep = optarg; + break; + case 'w': + wflag = true; + break; + } + } - start = atof(starts); - step = atof(steps); - end = atof(ends); + if (wflag && fflag) + eprintf("-f and -w cannot be combined.\n"); - if (step == 0) - return EXIT_FAILURE; + switch(argc-optind) { + case 3: + starts = argv[optind++]; + steps = argv[optind++]; + ends = argv[optind++]; + break; + case 2: + starts = argv[optind++]; + ends = argv[optind++]; + break; + case 1: + ends = argv[optind++]; + break; + default: + eprintf("usage: %s [-w] [-f fmt] [-s separator] " + "[start [step]] end\n", + basename(argv[0])); + } - if (start > end) { - if (step > 0) - return EXIT_FAILURE; - } else if (start < end) { - if (step < 0) - return EXIT_FAILURE; - } + 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"); - if (wflag) - fmt = getalignedwidthfmt(fmt, starts, steps, ends); - printf("%s\n", fmt); + start = atof(starts); + step = atof(steps); + end = atof(ends); - for (out = start;;) { - printf(fmt, out); + if (step == 0) + return EXIT_FAILURE; - out += step; - if (start > end) { - if (out >= end) { - printf("%s", sep); - } else { - break; - } - } else if (start < end) { - if (out <= end) { - printf("%s", sep); - } else { - break; - } - } else { - break; - } - } - printf("\n"); + if (start > end) { + if (step > 0) + return EXIT_FAILURE; + } else if (start < end) { + if (step < 0) + return EXIT_FAILURE; + } - return EXIT_SUCCESS; + 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); + } + + for (out = start;;) { + printf(fmt, out); + + out += step; + if (start > end) { + if (out >= end) { + printf("%s", sep); + } else { + break; + } + } else if (start < end) { + if (out <= end) { + printf("%s", sep); + } else { + break; + } + } else { + break; + } + } + printf("\n"); + + return EXIT_SUCCESS; }