1*cf5a6c84SAndroid Build Coastguard Worker /* seq.c - Count from first to last, by increment.
2*cf5a6c84SAndroid Build Coastguard Worker *
3*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2006 Rob Landley <[email protected]>
4*cf5a6c84SAndroid Build Coastguard Worker *
5*cf5a6c84SAndroid Build Coastguard Worker * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/seq.html
6*cf5a6c84SAndroid Build Coastguard Worker
7*cf5a6c84SAndroid Build Coastguard Worker USE_SEQ(NEWTOY(seq, "<1>3?f:s:w[!fw]", TOYFLAG_USR|TOYFLAG_BIN))
8*cf5a6c84SAndroid Build Coastguard Worker
9*cf5a6c84SAndroid Build Coastguard Worker config SEQ
10*cf5a6c84SAndroid Build Coastguard Worker bool "seq"
11*cf5a6c84SAndroid Build Coastguard Worker depends on TOYBOX_FLOAT
12*cf5a6c84SAndroid Build Coastguard Worker default y
13*cf5a6c84SAndroid Build Coastguard Worker help
14*cf5a6c84SAndroid Build Coastguard Worker usage: seq [-w|-f fmt_str] [-s sep_str] [first] [increment] last
15*cf5a6c84SAndroid Build Coastguard Worker
16*cf5a6c84SAndroid Build Coastguard Worker Count from first to last, by increment. Omitted arguments default
17*cf5a6c84SAndroid Build Coastguard Worker to 1. Two arguments are used as first and last. Arguments can be
18*cf5a6c84SAndroid Build Coastguard Worker negative or floating point.
19*cf5a6c84SAndroid Build Coastguard Worker
20*cf5a6c84SAndroid Build Coastguard Worker -f Use fmt_str as a printf-style floating point format string
21*cf5a6c84SAndroid Build Coastguard Worker -s Use sep_str as separator, default is a newline character
22*cf5a6c84SAndroid Build Coastguard Worker -w Pad to equal width with leading zeroes
23*cf5a6c84SAndroid Build Coastguard Worker */
24*cf5a6c84SAndroid Build Coastguard Worker
25*cf5a6c84SAndroid Build Coastguard Worker #define FOR_seq
26*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
27*cf5a6c84SAndroid Build Coastguard Worker
28*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
29*cf5a6c84SAndroid Build Coastguard Worker char *s, *f;
30*cf5a6c84SAndroid Build Coastguard Worker
31*cf5a6c84SAndroid Build Coastguard Worker int precision, buflen;
32*cf5a6c84SAndroid Build Coastguard Worker )
33*cf5a6c84SAndroid Build Coastguard Worker
34*cf5a6c84SAndroid Build Coastguard Worker // Ensure there's one %f escape with correct attributes
insanitize(char * f)35*cf5a6c84SAndroid Build Coastguard Worker static void insanitize(char *f)
36*cf5a6c84SAndroid Build Coastguard Worker {
37*cf5a6c84SAndroid Build Coastguard Worker char *s = next_printf(f, 0);
38*cf5a6c84SAndroid Build Coastguard Worker
39*cf5a6c84SAndroid Build Coastguard Worker if (!s) error_exit("bad -f no %%f");
40*cf5a6c84SAndroid Build Coastguard Worker if (-1 == stridx("aAeEfFgG", *s) || (s = next_printf(s, 0)))
41*cf5a6c84SAndroid Build Coastguard Worker error_exit("bad -f '%s'@%d", f, (int)(s-f+1));
42*cf5a6c84SAndroid Build Coastguard Worker }
43*cf5a6c84SAndroid Build Coastguard Worker
44*cf5a6c84SAndroid Build Coastguard Worker // Parse a numeric argument setting *prec to the precision of this argument.
45*cf5a6c84SAndroid Build Coastguard Worker // This reproduces the "1.234e5" precision bug from upstream.
parsef(char * s)46*cf5a6c84SAndroid Build Coastguard Worker static double parsef(char *s)
47*cf5a6c84SAndroid Build Coastguard Worker {
48*cf5a6c84SAndroid Build Coastguard Worker char *dp = strchr(s, '.');
49*cf5a6c84SAndroid Build Coastguard Worker
50*cf5a6c84SAndroid Build Coastguard Worker if (dp++) TT.precision = maxof(TT.precision, strcspn(dp, "eE"));
51*cf5a6c84SAndroid Build Coastguard Worker
52*cf5a6c84SAndroid Build Coastguard Worker return xstrtod(s);
53*cf5a6c84SAndroid Build Coastguard Worker }
54*cf5a6c84SAndroid Build Coastguard Worker
flush_toybuf(char * ss)55*cf5a6c84SAndroid Build Coastguard Worker static char *flush_toybuf(char *ss)
56*cf5a6c84SAndroid Build Coastguard Worker {
57*cf5a6c84SAndroid Build Coastguard Worker if (ss-toybuf<TT.buflen) return ss;
58*cf5a6c84SAndroid Build Coastguard Worker xwrite(1, toybuf, ss-toybuf);
59*cf5a6c84SAndroid Build Coastguard Worker
60*cf5a6c84SAndroid Build Coastguard Worker return toybuf;
61*cf5a6c84SAndroid Build Coastguard Worker }
62*cf5a6c84SAndroid Build Coastguard Worker
seq_main(void)63*cf5a6c84SAndroid Build Coastguard Worker void seq_main(void)
64*cf5a6c84SAndroid Build Coastguard Worker {
65*cf5a6c84SAndroid Build Coastguard Worker char fbuf[64], *ss;
66*cf5a6c84SAndroid Build Coastguard Worker double first = 1, increment = 1, last, dd;
67*cf5a6c84SAndroid Build Coastguard Worker long ii, inc = 1, len, slen;
68*cf5a6c84SAndroid Build Coastguard Worker
69*cf5a6c84SAndroid Build Coastguard Worker // parse arguments
70*cf5a6c84SAndroid Build Coastguard Worker if (!TT.s) TT.s = "\n";
71*cf5a6c84SAndroid Build Coastguard Worker switch (toys.optc) {
72*cf5a6c84SAndroid Build Coastguard Worker case 3: increment = parsef(toys.optargs[1]);
73*cf5a6c84SAndroid Build Coastguard Worker case 2: first = parsef(*toys.optargs);
74*cf5a6c84SAndroid Build Coastguard Worker default: last = parsef(toys.optargs[toys.optc-1]);
75*cf5a6c84SAndroid Build Coastguard Worker }
76*cf5a6c84SAndroid Build Coastguard Worker
77*cf5a6c84SAndroid Build Coastguard Worker // measure arguments
78*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(f)) insanitize(TT.f);
79*cf5a6c84SAndroid Build Coastguard Worker for (ii = len = 0; ii<3; ii++) {
80*cf5a6c84SAndroid Build Coastguard Worker dd = (double []){first, increment, last}[ii];
81*cf5a6c84SAndroid Build Coastguard Worker len = maxof(len, snprintf(0, 0, "%.*f", TT.precision, fabs(dd)));
82*cf5a6c84SAndroid Build Coastguard Worker if (ii == 2) dd += increment;
83*cf5a6c84SAndroid Build Coastguard Worker slen = dd;
84*cf5a6c84SAndroid Build Coastguard Worker if (dd != slen) inc = 0;
85*cf5a6c84SAndroid Build Coastguard Worker }
86*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(f)) sprintf(TT.f = fbuf, "%%0%ld.%df", len, TT.precision);
87*cf5a6c84SAndroid Build Coastguard Worker TT.buflen = sizeof(toybuf)-sizeof(fbuf)-len-TT.precision-strlen(TT.s);
88*cf5a6c84SAndroid Build Coastguard Worker if (TT.buflen<0) error_exit("bad -s");
89*cf5a6c84SAndroid Build Coastguard Worker
90*cf5a6c84SAndroid Build Coastguard Worker // fast path: when everything fits in a long with no flags.
91*cf5a6c84SAndroid Build Coastguard Worker if (!toys.optflags && inc) {
92*cf5a6c84SAndroid Build Coastguard Worker ii = first;
93*cf5a6c84SAndroid Build Coastguard Worker len = last;
94*cf5a6c84SAndroid Build Coastguard Worker inc = increment;
95*cf5a6c84SAndroid Build Coastguard Worker ss = toybuf;
96*cf5a6c84SAndroid Build Coastguard Worker if (inc>0) for (; ii<=len; ii += inc)
97*cf5a6c84SAndroid Build Coastguard Worker ss = flush_toybuf(ss+sprintf(ss, "%ld\n", ii));
98*cf5a6c84SAndroid Build Coastguard Worker else if (inc<0) for (; ii>=len; ii += inc)
99*cf5a6c84SAndroid Build Coastguard Worker ss = flush_toybuf(ss+sprintf(ss, "%ld\n", ii));
100*cf5a6c84SAndroid Build Coastguard Worker if (ss != toybuf) xwrite(1, toybuf, ss-toybuf);
101*cf5a6c84SAndroid Build Coastguard Worker
102*cf5a6c84SAndroid Build Coastguard Worker return;
103*cf5a6c84SAndroid Build Coastguard Worker }
104*cf5a6c84SAndroid Build Coastguard Worker
105*cf5a6c84SAndroid Build Coastguard Worker // Other implementations output nothing if increment is 0 and first > last,
106*cf5a6c84SAndroid Build Coastguard Worker // but loop forever if first < last or even first == last. We output
107*cf5a6c84SAndroid Build Coastguard Worker // nothing for all three, if you want endless output use "yes".
108*cf5a6c84SAndroid Build Coastguard Worker if (!increment) return;
109*cf5a6c84SAndroid Build Coastguard Worker
110*cf5a6c84SAndroid Build Coastguard Worker // Slow path, floating point and fancy sprintf() patterns
111*cf5a6c84SAndroid Build Coastguard Worker for (ii = 0, ss = toybuf;; ii++) {
112*cf5a6c84SAndroid Build Coastguard Worker // Multiply to avoid accumulating rounding errors from increment.
113*cf5a6c84SAndroid Build Coastguard Worker dd = first+ii*increment;
114*cf5a6c84SAndroid Build Coastguard Worker if ((increment<0 && dd<last) || (increment>0 && dd>last)) break;
115*cf5a6c84SAndroid Build Coastguard Worker if (ii) ss = flush_toybuf(stpcpy(ss, TT.s));
116*cf5a6c84SAndroid Build Coastguard Worker ss += sprintf(ss, TT.f, dd);
117*cf5a6c84SAndroid Build Coastguard Worker }
118*cf5a6c84SAndroid Build Coastguard Worker *ss++ = '\n';
119*cf5a6c84SAndroid Build Coastguard Worker xwrite(1, toybuf, ss-toybuf);
120*cf5a6c84SAndroid Build Coastguard Worker }
121