> 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(&reg, "\([^%]|%%\)*%[0-9]*\.[0-9]*[fFgG]\([^%]|%%\)*", REG_NOSUB);
	int ret = regexec(&reg, fmt, 0, NULL, 0);
	regfree(&reg);
	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;
}
    

Reply via email to