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