> Attached is a first shot at seq(1) for sbase. I do not like having to
> juggle data around to play games with sprintf, so if someone has a
> cleaner approach to this program, please speak up.
Unfortunately, there isn't much that can be done. User input is always
sub-par, and unless we want to account for scientific notation, or trailing
zeros, the easiest thing is to let atof parse the input, and then have
sprintf provide us a sane string.
I've cleaned up the code a bit, moved the digit-counting into separate
functions, and added simple regexp.h format string validation. I realizr
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>
#include <regexp.h>
#include "util.h"
static int
digsbefore(double d)
{
char tmp[4096];
sprintf(tmp, "%G", d);
return strcspn(tmp, ".")-(tmp[0]=='-');
}
static int
digsafter(double d)
{
char *c, tmp[4096];
sprintf(tmp, "%G", d);
if(!(c=strchr(tmp, '.')))
return 0
return strlen(c+1);
}
static int
fmtvalid(char * fmt)
{
regex_t reg;
regcomp(®, "\([^%]|%%\)*%[0-9]*\.[0-9]*[fFgG]\([^%]|%%\)*", REG_NOSUB);
int ret = regexec(®, fmt, 0, NULL, 0);
regfree(®);
return ret==0;
}
int
main(int argc, char *argv[])
{
char c;
char fmtbuf[4096];
char *fmt = "%G;
char *sep = "\n";
bool wflag = false;
double end = 1.0;
double start = 1.0;
double step = 1.0;
double out = start;
while((c = getopt(argc, argv, "f:s:w")) != -1)
switch(c) {
case 'f':
if(!fmvalid(optarg))
eprintf("invalid format.\n");
fmt = optarg;
break;
case 's':
sep = optarg;
break;
case 'w':
wflag = true;
break;
}
switch(argc-optind) {
case 3:
start=atof(argv[optind++]);
step=atof(argv[optind++]);
end=atof(argv[optind]);
break;
case 2:
start=atof(argv[optind++]);
end=atof(argv[optind]);
break;
case 1:
end=atof(argv[optind]);
break;
default:
eprintf("usage: seq [-f'fmt'] [-s'separator'] [-w] [start [step]] end\n");
}
if (wflag){
sprintf(fmtbuf, "%%0%d.%df", digsbefore(end), MAX(digsafter(begin), digsafter(step)));
fmt = fmtbuf;
}
for (out = start; out <= end; out += step) {
printf(fmt, out);
printf("%s", sep);
}
return EXIT_SUCCESS;
}