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 }