#include #include #include #include #include #include #include "util.h" #define MAX(a, b) (((a)>(b))?(a):(b)) static void validatefloat(char *fmt) { char*end; fmt+=strspn(fmt, " "); strtod(fmt, &end); if(fmt==end || end!=fmt+strlen(fmt)) eprintf("invalid float: %s\n", fmt); } static int digsbefore(char* d) { validatefloat(d); if(d[0] == '-') d++; char *exp = strpbrk(d, "eE"); int shift = exp?atoi(exp+1):0; return MAX(0, strspn(d, "0123456789")+shift); } static int digsafter(char *d) { validatefloat(d); char *exp = strpbrk(d, "eE"); int shift = exp?atoi(exp+1):0; int after = (d=strchr(d, '.'))?strspn(d+1, "0123456789"):0; return MAX(0, after-shift); } 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 = NULL; char *sep = "\n"; bool wflag = false; char* end = "1"; char* start = "1"; char* step = "1"; double out; while((c = getopt(argc, argv, "f:s:w")) != -1) switch(c) { case 'f': if(!fmtvalid(optarg)) eprintf("invalid format.\n"); fmt = optarg; break; case 's': sep = optarg; break; case 'w': wflag = true; break; } switch(argc-optind) { case 3: start=argv[optind++]; step=argv[optind++]; end=argv[optind]; break; case 2: start=argv[optind++]; end=argv[optind]; break; case 1: end=argv[optind]; break; default: eprintf("usage: seq [-f'fmt'] [-s'separator'] [-w] [start [step]] end\n"); } int before = MAX(digsbefore(start), digsbefore(end)); int after = MAX(digsafter(start), digsafter(step)); if (wflag){ sprintf(fmtbuf, "%%0%d.%df", after+before+(after!=0), after); fmt = fmtbuf; } else if(fmt == NULL){ sprintf(fmtbuf, "%%.%df", after); fmt = fmtbuf; } double dstart = atof(start), dend=atof(end),dstep=atof(step); for (out = dstart; out <= dend; out += dstep) { printf(fmt, out); printf("%s", sep); } return EXIT_SUCCESS; }