xref: /aosp_15_r20/external/toybox/toys/lsb/seq.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
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