Fixes and checks for seq. Thanks David Galos!

This commit is contained in:
Christoph Lohmann 2012-04-16 21:46:59 +02:00
parent d512d7938e
commit 29ce2560a7
3 changed files with 152 additions and 131 deletions

View File

@ -10,6 +10,7 @@ MIT/X Consortium License
© 2012 William Haddon <william@haddonthethird.net> © 2012 William Haddon <william@haddonthethird.net>
© 2012 Kurt H. Maier <khm@intma.in> © 2012 Kurt H. Maier <khm@intma.in>
© 2012 Christoph Lohmann <20h@r-36.net> © 2012 Christoph Lohmann <20h@r-36.net>
© 2012 David Galos <galosd83@students.rowan.edu>
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),

View File

@ -52,6 +52,7 @@ SRC = \
tty.c \ tty.c \
uname.c \ uname.c \
seq.c \ seq.c \
seq-test.c \
wc.c wc.c
OBJ = $(SRC:.c=.o) $(LIB) OBJ = $(SRC:.c=.o) $(LIB)

147
seq.c
View File

@ -5,85 +5,81 @@
#include <unistd.h> #include <unistd.h>
#include <stdbool.h> #include <stdbool.h>
#include <libgen.h> #include <libgen.h>
#include <regex.h>
#include "util.h" #include "util.h"
char afmt[4096]; #define MAX(a, b) (((a) > (b))? (a):(b))
char * int
getalignedwidthfmt(char *fmt, char *starts, char *steps, char *ends) validfloat(char *fmt)
{ {
char starttmp[4096], steptmp[4096], endtmp[4096]; char *end;
char *startdelim, *stepdelim, *enddelim;
int startl, startr, stepr, endl, endr;
int maxl, maxr;
/* fmt += strspn(fmt, " ");
* 1.) Get a temp buffer we can work in. strtod(fmt, &end);
* 2.) Calculate the *r(ight) and *l(eft) size. if (fmt == end || end != fmt + strlen(fmt))
*/ return 0;
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--;
memmove(endtmp, ends, strlen(ends)+1); return 1;
enddelim = strchr(endtmp, '.');
if (enddelim != NULL) {
enddelim[0] = '\0';
endr = strlen(enddelim+1);
} else {
endr = 0;
}
endl = strlen(endtmp);
if (endtmp[0] == '+')
endl--;
/*
* 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;
} }
maxl = (startl > endl)? startl : endl; int
maxr = (startl > endr)? startr : endr; digitsleft(char *d)
if (stepr > maxr) {
maxr = stepr; char *exp;
int shift;
if (maxl <= 1) { if (d[0] == '-' || d[0] == '+')
snprintf(afmt, sizeof(afmt), "%%.%df", maxr); d++;
} else if (maxr == 0) { exp = strpbrk(d, "eE");
snprintf(afmt, sizeof(afmt), "%%0%d.f", maxl); shift = exp? atoi(exp+1) : 0;
} 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(&reg, "\\([^%]|%%\\)*%[0-9]*\\.[0-9]*[fFgG]"
"\\([^%]|%%\\)*", REG_NOSUB);
ret = regexec(&reg, fmt, 0, NULL, 0);
regfree(&reg);
return (ret == 0);
} }
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
char c, *fmt, *sep, *starts, *steps, *ends; char c, *fmt, ftmp[4096], *sep, *starts, *steps, *ends;
bool wflag = false; bool wflag, fflag;
double start, step, end, out; double start, step, end, out;
int left, right;
sep = "\n"; sep = "\n";
fmt = "%G"; fmt = ftmp;
wflag = false;
fflag = false;
starts = "1"; starts = "1";
steps = "1"; steps = "1";
@ -92,7 +88,10 @@ main(int argc, char *argv[])
while((c = getopt(argc, argv, "f:s:w")) != -1) { while((c = getopt(argc, argv, "f:s:w")) != -1) {
switch(c) { switch(c) {
case 'f': case 'f':
if (!validfmt(optarg))
eprintf("invalid format.\n");
fmt = optarg; fmt = optarg;
fflag = true;
break; break;
case 's': case 's':
sep = optarg; sep = optarg;
@ -103,6 +102,9 @@ main(int argc, char *argv[])
} }
} }
if (wflag && fflag)
eprintf("-f and -w cannot be combined.\n");
switch(argc-optind) { switch(argc-optind) {
case 3: case 3:
starts = argv[optind++]; starts = argv[optind++];
@ -117,10 +119,18 @@ main(int argc, char *argv[])
ends = argv[optind++]; ends = argv[optind++];
break; break;
default: default:
eprintf("usage: %s [-w] [-f fmt] [-s separator] [start [step]]" eprintf("usage: %s [-w] [-f fmt] [-s separator] "
" end\n", basename(argv[0])); "[start [step]] end\n",
basename(argv[0]));
} }
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); start = atof(starts);
step = atof(steps); step = atof(steps);
end = atof(ends); end = atof(ends);
@ -136,9 +146,18 @@ main(int argc, char *argv[])
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (wflag) right = MAX(digitsright(starts),
fmt = getalignedwidthfmt(fmt, starts, steps, ends); MAX(digitsright(ends),
printf("%s\n", fmt); 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;;) { for (out = start;;) {
printf(fmt, out); printf(fmt, out);