6 |
* |
* |
7 |
* Licensed under the GPL v2, see the file LICENSE in this tarball. |
* Licensed under the GPL v2, see the file LICENSE in this tarball. |
8 |
*/ |
*/ |
|
|
|
9 |
#include "libbb.h" |
#include "libbb.h" |
10 |
|
|
11 |
/* This is a NOFORK applet. Be very careful! */ |
/* This is a NOFORK applet. Be very careful! */ |
12 |
|
|
|
|
|
13 |
int seq_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
int seq_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
14 |
int seq_main(int argc, char **argv) |
int seq_main(int argc, char **argv) |
15 |
{ |
{ |
16 |
double last, increment, i; |
enum { |
17 |
|
OPT_w = (1 << 0), |
18 |
i = increment = 1; |
OPT_s = (1 << 1), |
19 |
|
}; |
20 |
|
double first, last, increment, v; |
21 |
|
unsigned n; |
22 |
|
unsigned width; |
23 |
|
unsigned frac_part; |
24 |
|
const char *sep, *opt_s = "\n"; |
25 |
|
unsigned opt; |
26 |
|
|
27 |
|
#if ENABLE_LOCALE_SUPPORT |
28 |
|
/* Undo busybox.c: on input, we want to use dot |
29 |
|
* as fractional separator, regardless of current locale */ |
30 |
|
setlocale(LC_NUMERIC, "C"); |
31 |
|
#endif |
32 |
|
|
33 |
|
opt = getopt32(argv, "+ws:", &opt_s); |
34 |
|
argc -= optind; |
35 |
|
argv += optind; |
36 |
|
first = increment = 1; |
37 |
|
errno = 0; |
38 |
switch (argc) { |
switch (argc) { |
39 |
case 4: |
char *pp; |
|
increment = atof(argv[2]); |
|
40 |
case 3: |
case 3: |
41 |
i = atof(argv[1]); |
increment = strtod(argv[1], &pp); |
42 |
|
errno |= *pp; |
43 |
case 2: |
case 2: |
44 |
last = atof(argv[argc-1]); |
first = strtod(argv[0], &pp); |
45 |
break; |
errno |= *pp; |
46 |
|
case 1: |
47 |
|
last = strtod(argv[argc-1], &pp); |
48 |
|
if (!errno && *pp == '\0') |
49 |
|
break; |
50 |
default: |
default: |
51 |
bb_show_usage(); |
bb_show_usage(); |
52 |
} |
} |
53 |
|
|
54 |
/* You should note that this is pos-5.0.91 semantics, -- FK. */ |
#if ENABLE_LOCALE_SUPPORT |
55 |
while ((increment > 0 && i <= last) || (increment < 0 && i >= last)) { |
setlocale(LC_NUMERIC, ""); |
56 |
printf("%g\n", i); |
#endif |
57 |
i += increment; |
|
58 |
|
/* Last checked to be compatible with: coreutils-6.10 */ |
59 |
|
width = 0; |
60 |
|
frac_part = 0; |
61 |
|
while (1) { |
62 |
|
char *dot = strchrnul(*argv, '.'); |
63 |
|
int w = (dot - *argv); |
64 |
|
int f = strlen(dot); |
65 |
|
if (width < w) |
66 |
|
width = w; |
67 |
|
argv++; |
68 |
|
if (!*argv) |
69 |
|
break; |
70 |
|
/* Why do the above _before_ frac check below? |
71 |
|
* Try "seq 1 2.0" and "seq 1.0 2.0": |
72 |
|
* coreutils never pay attention to the number |
73 |
|
* of fractional digits in last arg. */ |
74 |
|
if (frac_part < f) |
75 |
|
frac_part = f; |
76 |
|
} |
77 |
|
if (frac_part) { |
78 |
|
frac_part--; |
79 |
|
if (frac_part) |
80 |
|
width += frac_part + 1; |
81 |
|
} |
82 |
|
if (!(opt & OPT_w)) |
83 |
|
width = 0; |
84 |
|
|
85 |
|
sep = ""; |
86 |
|
v = first; |
87 |
|
n = 0; |
88 |
|
while (increment >= 0 ? v <= last : v >= last) { |
89 |
|
printf("%s%0*.*f", sep, width, frac_part, v); |
90 |
|
sep = opt_s; |
91 |
|
/* v += increment; - would accumulate floating point errors */ |
92 |
|
n++; |
93 |
|
v = first + n * increment; |
94 |
} |
} |
95 |
|
if (n) /* if while loop executed at least once */ |
96 |
|
bb_putchar('\n'); |
97 |
|
|
98 |
return fflush(stdout); |
return fflush_all(); |
99 |
} |
} |