morpheus-base

morpheus base system
git clone git://git.2f30.org/morpheus-base
Log | Files | Refs

seq.c (2666B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include <stdio.h>
      3 #include <stdlib.h>
      4 #include <string.h>
      5 #include <unistd.h>
      6 
      7 #include "util.h"
      8 
      9 static int digitsleft(const char *);
     10 static int digitsright(const char *);
     11 static int validfmt(const char *);
     12 
     13 static void
     14 usage(void)
     15 {
     16 	eprintf("usage: %s [-f fmt] [-s separator] [-w width] [start"
     17 		       " [step]] end\n", argv0);
     18 }
     19 
     20 int
     21 main(int argc, char *argv[])
     22 {
     23 	const char *starts = "1", *steps = "1", *ends = "1", *sep = "\n";
     24 	int wflag = 0;
     25 	char *tmp, ftmp[BUFSIZ], *fmt = ftmp;
     26 	double start, step, end, out, dir;
     27 	int left, right;
     28 
     29 	ARGBEGIN {
     30 	case 'f':
     31 		if(!validfmt(tmp=EARGF(usage())))
     32 			eprintf("%s: invalid format\n", tmp);
     33 		fmt = tmp;
     34 		break;
     35 	case 's':
     36 		sep = EARGF(usage());
     37 		break;
     38 	case 'w':
     39 		wflag = 1;
     40 		break;
     41 	default:
     42 		usage();
     43 	} ARGEND;
     44 
     45 	switch (argc) {
     46 	case 3:
     47 		steps = argv[1];
     48 		argv[1] = argv[2];
     49 		/* fallthrough */
     50 	case 2:
     51 		starts = argv[0];
     52 		argv++;
     53 		/* fallthrough */
     54 	case 1:
     55 		ends = argv[0];
     56 		break;
     57 	default:
     58 		usage();
     59 	}
     60 	start = estrtod(starts);
     61 	step  = estrtod(steps);
     62 	end   = estrtod(ends);
     63 
     64 	dir = (step > 0) ? 1.0 : -1.0;
     65 	if (step == 0 || start * dir > end * dir)
     66 		return 1;
     67 
     68 	if (fmt == ftmp) {
     69 		right = MAX(digitsright(starts),
     70 		            MAX(digitsright(ends),
     71 		                digitsright(steps)));
     72 
     73 		if (wflag) {
     74 			left = MAX(digitsleft(starts), digitsleft(ends));
     75 
     76 			snprintf(ftmp, sizeof ftmp, "%%0%d.%df",
     77 					right + left + (right != 0), right);
     78 		} else
     79 			snprintf(ftmp, sizeof ftmp, "%%.%df", right);
     80 	}
     81 	for (out = start; out * dir <= end * dir; out += step) {
     82 		if (out != start)
     83 			fputs(sep, stdout);
     84 		printf(fmt, out);
     85 	}
     86 	printf("\n");
     87 
     88 	return 0;
     89 }
     90 
     91 static int
     92 digitsleft(const char *d)
     93 {
     94 	char *exp;
     95 	int shift;
     96 
     97 	if (*d == '+')
     98 		d++;
     99 	exp = strpbrk(d, "eE");
    100 	shift = exp ? estrtol(&exp[1], 10) : 0;
    101 
    102 	return MAX(0, strspn(d, "-0123456789") + shift);
    103 }
    104 
    105 static int
    106 digitsright(const char *d)
    107 {
    108 	char *exp;
    109 	int shift, after;
    110 
    111 	exp = strpbrk(d, "eE");
    112 	shift = exp ? estrtol(&exp[1], 10) : 0;
    113 	after = (d = strchr(d, '.')) ? strspn(&d[1], "0123456789") : 0;
    114 
    115 	return MAX(0, after - shift);
    116 }
    117 
    118 static int
    119 validfmt(const char *fmt)
    120 {
    121 	int occur = 0;
    122 
    123 literal:
    124 	while (*fmt)
    125 		if (*fmt++ == '%')
    126 			goto format;
    127 	return occur == 1;
    128 
    129 format:
    130 	if (*fmt == '%') {
    131 		fmt++;
    132 		goto literal;
    133 	}
    134 	fmt += strspn(fmt, "-+#0 '");
    135 	fmt += strspn(fmt, "0123456789");
    136 	if (*fmt == '.') {
    137 		fmt++;
    138 		fmt += strspn(fmt, "0123456789");
    139 	}
    140 	if (*fmt == 'L')
    141 		fmt++;
    142 
    143 	switch (*fmt) {
    144 	case 'f': case 'F':
    145 	case 'g': case 'G':
    146 	case 'e': case 'E':
    147 	case 'a': case 'A':
    148 		occur++;
    149 		goto literal;
    150 	default:
    151 		return 0;
    152 	}
    153 }