On 2/27/24 13:46, Oliver Webb via Toybox wrote:
> Since we build toybox with -funsigned-char, there is no reason to have a type
> for unnsigned chars in bc.c,
> since that is the default for all chars. And removing it gets rid of a typedef
Sigh, the bc in the tree is "fraught". The guy who submitted it said he was
escaping from a cloud of drama at the time (I didn't care), and then was
surrounded by a fresh cloud of drama after "escaping" and tried to suck me into
it (I declined). He wandered off to busybox and also maintaining his command as
a separate project.
According to "wc toys/*/*.c | sort -n" it is the largest command in the entire
toybox tree. Larger than the shell despite not having a dozen subcommands nor
needing to manage terminal control or child processes. It's 5 times the size or
sed or tar, and at least 3 times the size it NEEDS to be. I'd far rather clean
up xzcat or implement awk (each of which is a similar effort ballpark) than
spend months cleaning it up.
Modern users who want to do funky math pull out python or something. Modern
users who want to do non-funky math have $((math)) built into the shell, and
expr, and are as likely to use dc as bc. A simple tool that does floating point
math would be nice, and I got a submission of a tiny floating point calculator
(attached) a couple years back which I haven't checked in yet because it's not a
standard command and I don't know anybody under 50 who uses reverse polish
notation, but I have a todo item to maybe have toysh's $[] syntax (a deprecated
synonym for $(()) from before posix standardized that) do floating point math?
(I mean, since it's deprecated...) Alas there's some design work: rpn.c uses
letters for sqrt() sin() asin() cos() acos() tan() atan() and has a PI constant,
where integer $((math)) in the shell expands any leftover strings it sees to
shell environment variables. Still, pulling out function() calls before
recognizing variable names isn't that big a lift... But let's get the base shell
features all working first, then worry about extensions.
But the FACT that people tend to do complex math in perl or $HOSTCC or similar
means the only confirmed user of bc I've found is the linux kernel build, and
I've had a patch to remove "bc" from that for ten years. (Which still worked
last I checked, which was... the 6.7 release build I think?) I want to build
linux from scratch, and then try to populate a debian repository under an LFS
system (hard problem), and THEN decide whether to clean this command up or
simply remove it. Maintaining "not bc" package builds is a heck of a lot less
work than maintaining "builds against musl" package builds.
There's no strong reason _not_ to apply your patch, just...
Rob
/* rpn.c - Reverse Polish Notation floating point calculator
*
* Copyright 2022 Jeff Dionne <[email protected]>
*
* No standard. (Possibly some IEEE thing?)
USE_RPN(NEWTOY(rpn, "<2", TOYFLAG_USR|TOYFLAG_BIN))
config RPN
bool "rpn"
default n
help
usage: rpn
A hello world program.
Mostly used as a simple template for adding new commands.
Occasionally nice to smoketest kernel booting via "init=/usr/bin/hello".
*/
#define FOR_rpn
#include "toys.h"
GLOBALS(
int unused;
)
#define STACK_LEN 4
typedef struct _val {
int s;
unsigned int i;
unsigned int f;
unsigned int p;
int e;
int flags;
} fp_comp_t;
static struct _val zero_fp = { 1, 0, 0, 0, 0, 0 };
static double stack[STACK_LEN];
static int sp = STACK_LEN;
fp_comp_t decomp(double v, int eng)
{
fp_comp_t d;
unsigned int t;
unsigned int m=100000;
d.s = v>=0 ? 1 : -1;
v = v> 0 ? v : -v;
/* extract 6 significant digits */
d.e = d.p = 5;
while (v < m && v) { v *= 10; d.e--; }
while (v>= 10*m ) { v /= 10; d.e++; }
/* engineering mode exp adjust n, u, m, k, M... */
if (eng) while (d.e%3) { m /= 10; d.e--; d.p--; }
t = v+0.5;
d.i = t/m;
d.f = t - (d.i)*m;
return d;
}
double comp(fp_comp_t v)
{
double ret;
ret = v.f;
while (v.p--) { ret /= 10; }
ret += v.i;
while (v.e > 0) { ret *= 10; v.e--; }
while (v.e < 0) { ret /= 10; v.e++; }
if (v.s < 0) return -ret;
return ret;
}
void print_decomp(fp_comp_t d, int f, int e)
{
if (e) printf("%c%d.%.*de%+d\n", d.s>0 ? ' ':'-', d.i, d.p, d.f, d.e);
else if (f) printf("%c%d.%.*d\n", d.s>0 ? ' ':'-', d.i, d.p, d.f );
else printf("%c%d\n", d.s>0 ? ' ':'-', d.i );
}
fp_comp_t key_edit(fp_comp_t d, char in)
{
switch (d.flags) {
case 0:
case 10:
d = zero_fp;
d.flags++;
if (in == 'e') d.i=1;
case 1:
if (isdigit(in)) { d.i = d.i*10 + in-'0'; }
if (in == 'n') d.s = -d.s;
if (in == '.') d.flags++;
if (in == 'e') d.flags = 3;
if (in == 'b') d.i /= 10;
break;
case 2:
if (isdigit(in)) { d.f = d.f*10 + in-'0'; d.p++; }
if (in == 'n') d.s = -d.s;
if (in == 'e') d.flags++;
if (in == 'b') {
d.f /= 10;
if (!d.p) d.flags--;
else d.p--;
}
break;
case 3:
case 7:
if (isdigit(in)) { d.e = d.e*10 + in-'0'; }
if (in == 'n') {
if (!d.e) d.flags ^= 4;
d.e = -d.e;
}
if (d.e && d.flags & 4) { d.e = -d.e; d.flags &= 4; }
if (in == 'b') {
if (!d.e) d.flags = 2;
d.e /= 10;
}
break;
}
return d;
}
void push(double v)
{
if (sp) stack[--sp] = v;
}
double pop()
{
return (sp<STACK_LEN) ? stack[sp++] : 0;
}
fp_comp_t key_process(fp_comp_t d, char in)
{
double x, y;
if (strchr("+-*/wvqQsScCtT d", in)) {
if (d.flags && d.flags != 10) push(comp(d));
x = pop();
}
if (strchr("+-*/w" , in)) y = pop();
if (strchr("+-*/wvqQsScCtTD" , in)) {
d.flags = 0;
switch (in) {
case '+': x = y + x; break;
case '-': x = y - x; break;
case '*': x = y * x; break;
case '/': x = y / (x ? x : 1e-300); break; // avoid div by zero
case 'w': push(x); x = y; break;
case 'v': x = (1.0) / (x ? x : 1e-300); break; // avoid div by zero
case 'q': x = sqrt(x); break;
case 'Q': x = x*x; break;
case 's': x = sin(x); break;
case 'S': x = asin(x); break;
case 'c': x = cos(x); break;
case 'C': x = acos(x); break;
case 't': x = tan(x); break;
case 'T': x = atan(x); break;
case 'D': x = M_PI; break;
}
push(x);
} else if (in=='z') {
if (!d.flags) d=decomp(stack[sp], 1);
push(comp(d));
d.flags = 10;
} else {
d = key_edit(d, in);
}
#ifdef DEBUG
if (!d.flags ) print_decomp(decomp(stack[sp], 1), 1, 1);
if ( d.flags ) print_decomp(d, d.flags == 2, d.flags == 3 || d.flags == 7);
#endif
return d;
}
int main(int argc, char *argv[])
{
fp_comp_t d = zero_fp;
char *p;
int i;
int a = 1;
if (argc < 2) exit(0);
p = argv[a++];
while (*p) {
d = key_process(d, *p);
if (!*++p && a<argc) p = argv[a++];
}
for (i=STACK_LEN; i>sp; ) print_decomp(decomp(stack[--i], 1), 1, 1);
return 0;
}
_______________________________________________
Toybox mailing list
[email protected]
http://lists.landley.net/listinfo.cgi/toybox-landley.net