aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-12-24 05:00:36 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2018-12-24 05:00:36 +0100
commit2097ac8d9e07320ff0f087bd6b3f6987aa02eb69 (patch)
treef3ceccdc48fff7ea71263d0e05c060e2f126749e
parenta7732d11204d04f14ec69103128a3a6bec7d525d (diff)
downloadbusybox-w32-2097ac8d9e07320ff0f087bd6b3f6987aa02eb69.tar.gz
busybox-w32-2097ac8d9e07320ff0f087bd6b3f6987aa02eb69.tar.bz2
busybox-w32-2097ac8d9e07320ff0f087bd6b3f6987aa02eb69.zip
bc: move functions/macros around, no code changes
Order now is: enums/structures/defines, utility/common functions, parsing, execution, main loop, main() Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--miscutils/bc.c776
1 files changed, 392 insertions, 384 deletions
diff --git a/miscutils/bc.c b/miscutils/bc.c
index 7d3b6b7ed..7a69a0816 100644
--- a/miscutils/bc.c
+++ b/miscutils/bc.c
@@ -877,82 +877,9 @@ struct globals {
877# define COMMA_SUCCESS ,BC_STATUS_SUCCESS 877# define COMMA_SUCCESS ,BC_STATUS_SUCCESS
878#endif 878#endif
879 879
880#define STACK_HAS_MORE_THAN(s, n) ((s)->len > ((size_t)(n))) 880//
881#define STACK_HAS_EQUAL_OR_MORE_THAN(s, n) ((s)->len >= ((size_t)(n))) 881// Utility routines
882 882//
883#define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
884#define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
885#define BC_NUM_INT(n) ((n)->len - (n)->rdx)
886//#define BC_NUM_AREQ(a, b) (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
887static /*ALWAYS_INLINE*/ size_t BC_NUM_AREQ(BcNum *a, BcNum *b)
888{
889 return BC_MAX(a->rdx, b->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1;
890}
891//#define BC_NUM_MREQ(a, b, scale) (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
892static /*ALWAYS_INLINE*/ size_t BC_NUM_MREQ(BcNum *a, BcNum *b, size_t scale)
893{
894 return BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX(scale, a->rdx + b->rdx) + 1;
895}
896
897typedef void (*BcNumDigitOp)(size_t, size_t, bool) FAST_FUNC;
898
899typedef BC_STATUS (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t) FAST_FUNC;
900
901static BC_STATUS zbc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
902 BcNumBinaryOp op, size_t req);
903static FAST_FUNC BC_STATUS zbc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
904static FAST_FUNC BC_STATUS zbc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
905static FAST_FUNC BC_STATUS zbc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
906static FAST_FUNC BC_STATUS zbc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
907static FAST_FUNC BC_STATUS zbc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
908static FAST_FUNC BC_STATUS zbc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
909
910static FAST_FUNC BC_STATUS zbc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
911{
912 BcNumBinaryOp op = (!a->neg == !b->neg) ? zbc_num_a : zbc_num_s;
913 (void) scale;
914 RETURN_STATUS(zbc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b)));
915}
916
917static FAST_FUNC BC_STATUS zbc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
918{
919 BcNumBinaryOp op = (!a->neg == !b->neg) ? zbc_num_s : zbc_num_a;
920 (void) scale;
921 RETURN_STATUS(zbc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b)));
922}
923
924static FAST_FUNC BC_STATUS zbc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
925{
926 size_t req = BC_NUM_MREQ(a, b, scale);
927 RETURN_STATUS(zbc_num_binary(a, b, c, scale, zbc_num_m, req));
928}
929
930static FAST_FUNC BC_STATUS zbc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
931{
932 size_t req = BC_NUM_MREQ(a, b, scale);
933 RETURN_STATUS(zbc_num_binary(a, b, c, scale, zbc_num_d, req));
934}
935
936static FAST_FUNC BC_STATUS zbc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
937{
938 size_t req = BC_NUM_MREQ(a, b, scale);
939 RETURN_STATUS(zbc_num_binary(a, b, c, scale, zbc_num_rem, req));
940}
941
942static FAST_FUNC BC_STATUS zbc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
943{
944 RETURN_STATUS(zbc_num_binary(a, b, c, scale, zbc_num_p, a->len * b->len + 1));
945}
946
947static const BcNumBinaryOp zbc_program_ops[] = {
948 zbc_num_pow, zbc_num_mul, zbc_num_div, zbc_num_mod, zbc_num_add, zbc_num_sub,
949};
950#define zbc_num_add(...) (zbc_num_add(__VA_ARGS__) COMMA_SUCCESS)
951#define zbc_num_sub(...) (zbc_num_sub(__VA_ARGS__) COMMA_SUCCESS)
952#define zbc_num_mul(...) (zbc_num_mul(__VA_ARGS__) COMMA_SUCCESS)
953#define zbc_num_div(...) (zbc_num_div(__VA_ARGS__) COMMA_SUCCESS)
954#define zbc_num_mod(...) (zbc_num_mod(__VA_ARGS__) COMMA_SUCCESS)
955#define zbc_num_pow(...) (zbc_num_pow(__VA_ARGS__) COMMA_SUCCESS)
956 883
957static void fflush_and_check(void) 884static void fflush_and_check(void)
958{ 885{
@@ -1324,102 +1251,6 @@ static size_t bc_map_find_exact(const BcVec *v, const void *ptr)
1324} 1251}
1325#endif 1252#endif
1326 1253
1327static int bad_input_byte(char c)
1328{
1329 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1330 || c > 0x7e
1331 ) {
1332 bc_error_fmt("illegal character 0x%02x", c);
1333 return 1;
1334 }
1335 return 0;
1336}
1337
1338// Note: it _appends_ data from fp to vec.
1339static void bc_read_line(BcVec *vec, FILE *fp)
1340{
1341 again:
1342 fflush_and_check();
1343
1344#if ENABLE_FEATURE_BC_SIGNALS
1345 if (G_interrupt) { // ^C was pressed
1346 intr:
1347 if (fp != stdin) {
1348 // ^C while running a script (bc SCRIPT): die.
1349 // We do not return to interactive prompt:
1350 // user might be running us from a shell,
1351 // and SCRIPT might be intended to terminate
1352 // (e.g. contain a "halt" stmt).
1353 // ^C dropping user into a bc prompt instead of
1354 // the shell would be unexpected.
1355 xfunc_die();
1356 }
1357 // ^C while interactive input
1358 G_interrupt = 0;
1359 // GNU bc says "interrupted execution."
1360 // GNU dc says "Interrupt!"
1361 fputs("\ninterrupted execution\n", stderr);
1362 }
1363
1364# if ENABLE_FEATURE_EDITING
1365 if (G_ttyin && fp == stdin) {
1366 int n, i;
1367# define line_buf bb_common_bufsiz1
1368 n = read_line_input(G.line_input_state, "", line_buf, COMMON_BUFSIZE);
1369 if (n <= 0) { // read errors or EOF, or ^D, or ^C
1370 if (n == 0) // ^C
1371 goto intr;
1372 bc_vec_pushZeroByte(vec); // ^D or EOF (or error)
1373 return;
1374 }
1375 i = 0;
1376 for (;;) {
1377 char c = line_buf[i++];
1378 if (!c) break;
1379 if (bad_input_byte(c)) goto again;
1380 }
1381 bc_vec_concat(vec, line_buf);
1382# undef line_buf
1383 } else
1384# endif
1385#endif
1386 {
1387 int c;
1388 bool bad_chars = 0;
1389 size_t len = vec->len;
1390
1391 do {
1392#if ENABLE_FEATURE_BC_SIGNALS
1393 if (G_interrupt) {
1394 // ^C was pressed: ignore entire line, get another one
1395 vec->len = len;
1396 goto intr;
1397 }
1398#endif
1399 do c = fgetc(fp); while (c == '\0');
1400 if (c == EOF) {
1401 if (ferror(fp))
1402 bb_perror_msg_and_die("input error");
1403 // Note: EOF does not append '\n'
1404 break;
1405 }
1406 bad_chars |= bad_input_byte(c);
1407 bc_vec_pushByte(vec, (char)c);
1408 } while (c != '\n');
1409
1410 if (bad_chars) {
1411 // Bad chars on this line
1412 if (!G.prog.file) { // stdin
1413 // ignore entire line, get another one
1414 vec->len = len;
1415 goto again;
1416 }
1417 bb_perror_msg_and_die("file '%s' is not text", G.prog.file);
1418 }
1419 bc_vec_pushZeroByte(vec);
1420 }
1421}
1422
1423static void bc_num_setToZero(BcNum *n, size_t scale) 1254static void bc_num_setToZero(BcNum *n, size_t scale)
1424{ 1255{
1425 n->len = 0; 1256 n->len = 0;
@@ -1569,6 +1400,20 @@ static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1569 } 1400 }
1570} 1401}
1571 1402
1403#define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
1404#define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
1405#define BC_NUM_INT(n) ((n)->len - (n)->rdx)
1406//#define BC_NUM_AREQ(a, b) (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
1407static /*ALWAYS_INLINE*/ size_t BC_NUM_AREQ(BcNum *a, BcNum *b)
1408{
1409 return BC_MAX(a->rdx, b->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1;
1410}
1411//#define BC_NUM_MREQ(a, b, scale) (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
1412static /*ALWAYS_INLINE*/ size_t BC_NUM_MREQ(BcNum *a, BcNum *b, size_t scale)
1413{
1414 return BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX(scale, a->rdx + b->rdx) + 1;
1415}
1416
1572static ssize_t bc_num_cmp(BcNum *a, BcNum *b) 1417static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1573{ 1418{
1574 size_t i, min, a_int, b_int, diff; 1419 size_t i, min, a_int, b_int, diff;
@@ -1705,6 +1550,99 @@ static BC_STATUS zbc_num_shift(BcNum *n, size_t places)
1705} 1550}
1706#define zbc_num_shift(...) (zbc_num_shift(__VA_ARGS__) COMMA_SUCCESS) 1551#define zbc_num_shift(...) (zbc_num_shift(__VA_ARGS__) COMMA_SUCCESS)
1707 1552
1553typedef BC_STATUS (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t) FAST_FUNC;
1554
1555static BC_STATUS zbc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
1556 BcNumBinaryOp op, size_t req)
1557{
1558 BcStatus s;
1559 BcNum num2, *ptr_a, *ptr_b;
1560 bool init = false;
1561
1562 if (c == a) {
1563 ptr_a = &num2;
1564 memcpy(ptr_a, c, sizeof(BcNum));
1565 init = true;
1566 } else
1567 ptr_a = a;
1568
1569 if (c == b) {
1570 ptr_b = &num2;
1571 if (c != a) {
1572 memcpy(ptr_b, c, sizeof(BcNum));
1573 init = true;
1574 }
1575 } else
1576 ptr_b = b;
1577
1578 if (init)
1579 bc_num_init(c, req);
1580 else
1581 bc_num_expand(c, req);
1582
1583 s = BC_STATUS_SUCCESS;
1584 IF_ERROR_RETURN_POSSIBLE(s =) op(ptr_a, ptr_b, c, scale);
1585
1586 if (init) bc_num_free(&num2);
1587
1588 RETURN_STATUS(s);
1589}
1590#define zbc_num_binary(...) (zbc_num_binary(__VA_ARGS__) COMMA_SUCCESS)
1591
1592static FAST_FUNC BC_STATUS zbc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
1593static FAST_FUNC BC_STATUS zbc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
1594static FAST_FUNC BC_STATUS zbc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
1595static FAST_FUNC BC_STATUS zbc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
1596static FAST_FUNC BC_STATUS zbc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
1597static FAST_FUNC BC_STATUS zbc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
1598
1599static FAST_FUNC BC_STATUS zbc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
1600{
1601 BcNumBinaryOp op = (!a->neg == !b->neg) ? zbc_num_a : zbc_num_s;
1602 (void) scale;
1603 RETURN_STATUS(zbc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b)));
1604}
1605
1606static FAST_FUNC BC_STATUS zbc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
1607{
1608 BcNumBinaryOp op = (!a->neg == !b->neg) ? zbc_num_s : zbc_num_a;
1609 (void) scale;
1610 RETURN_STATUS(zbc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b)));
1611}
1612
1613static FAST_FUNC BC_STATUS zbc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
1614{
1615 size_t req = BC_NUM_MREQ(a, b, scale);
1616 RETURN_STATUS(zbc_num_binary(a, b, c, scale, zbc_num_m, req));
1617}
1618
1619static FAST_FUNC BC_STATUS zbc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
1620{
1621 size_t req = BC_NUM_MREQ(a, b, scale);
1622 RETURN_STATUS(zbc_num_binary(a, b, c, scale, zbc_num_d, req));
1623}
1624
1625static FAST_FUNC BC_STATUS zbc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
1626{
1627 size_t req = BC_NUM_MREQ(a, b, scale);
1628 RETURN_STATUS(zbc_num_binary(a, b, c, scale, zbc_num_rem, req));
1629}
1630
1631static FAST_FUNC BC_STATUS zbc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
1632{
1633 RETURN_STATUS(zbc_num_binary(a, b, c, scale, zbc_num_p, a->len * b->len + 1));
1634}
1635
1636static const BcNumBinaryOp zbc_program_ops[] = {
1637 zbc_num_pow, zbc_num_mul, zbc_num_div, zbc_num_mod, zbc_num_add, zbc_num_sub,
1638};
1639#define zbc_num_add(...) (zbc_num_add(__VA_ARGS__) COMMA_SUCCESS)
1640#define zbc_num_sub(...) (zbc_num_sub(__VA_ARGS__) COMMA_SUCCESS)
1641#define zbc_num_mul(...) (zbc_num_mul(__VA_ARGS__) COMMA_SUCCESS)
1642#define zbc_num_div(...) (zbc_num_div(__VA_ARGS__) COMMA_SUCCESS)
1643#define zbc_num_mod(...) (zbc_num_mod(__VA_ARGS__) COMMA_SUCCESS)
1644#define zbc_num_pow(...) (zbc_num_pow(__VA_ARGS__) COMMA_SUCCESS)
1645
1708static BC_STATUS zbc_num_inv(BcNum *a, BcNum *b, size_t scale) 1646static BC_STATUS zbc_num_inv(BcNum *a, BcNum *b, size_t scale)
1709{ 1647{
1710 BcNum one; 1648 BcNum one;
@@ -2224,195 +2162,6 @@ static FAST_FUNC BC_STATUS zbc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size
2224} 2162}
2225#define zbc_num_p(...) (zbc_num_p(__VA_ARGS__) COMMA_SUCCESS) 2163#define zbc_num_p(...) (zbc_num_p(__VA_ARGS__) COMMA_SUCCESS)
2226 2164
2227static BC_STATUS zbc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
2228 BcNumBinaryOp op, size_t req)
2229{
2230 BcStatus s;
2231 BcNum num2, *ptr_a, *ptr_b;
2232 bool init = false;
2233
2234 if (c == a) {
2235 ptr_a = &num2;
2236 memcpy(ptr_a, c, sizeof(BcNum));
2237 init = true;
2238 } else
2239 ptr_a = a;
2240
2241 if (c == b) {
2242 ptr_b = &num2;
2243 if (c != a) {
2244 memcpy(ptr_b, c, sizeof(BcNum));
2245 init = true;
2246 }
2247 } else
2248 ptr_b = b;
2249
2250 if (init)
2251 bc_num_init(c, req);
2252 else
2253 bc_num_expand(c, req);
2254
2255 s = BC_STATUS_SUCCESS;
2256 IF_ERROR_RETURN_POSSIBLE(s =) op(ptr_a, ptr_b, c, scale);
2257
2258 if (init) bc_num_free(&num2);
2259
2260 RETURN_STATUS(s);
2261}
2262#define zbc_num_binary(...) (zbc_num_binary(__VA_ARGS__) COMMA_SUCCESS)
2263
2264static bool bc_num_strValid(const char *val, size_t base)
2265{
2266 BcDig b;
2267 bool radix;
2268
2269 b = (BcDig)(base <= 10 ? base + '0' : base - 10 + 'A');
2270 radix = false;
2271 for (;;) {
2272 BcDig c = *val++;
2273 if (c == '\0')
2274 break;
2275 if (c == '.') {
2276 if (radix) return false;
2277 radix = true;
2278 continue;
2279 }
2280 if (c < '0' || c >= b || (c > '9' && c < 'A'))
2281 return false;
2282 }
2283 return true;
2284}
2285
2286// Note: n is already "bc_num_zero()"ed,
2287// leading zeroes in "val" are removed
2288static void bc_num_parseDecimal(BcNum *n, const char *val)
2289{
2290 size_t len, i;
2291 const char *ptr;
2292
2293 len = strlen(val);
2294 if (len == 0)
2295 return;
2296
2297 bc_num_expand(n, len);
2298
2299 ptr = strchr(val, '.');
2300
2301 n->rdx = 0;
2302 if (ptr != NULL)
2303 n->rdx = (size_t)((val + len) - (ptr + 1));
2304
2305 for (i = 0; val[i]; ++i) {
2306 if (val[i] != '0' && val[i] != '.') {
2307 // Not entirely zero value - convert it, and exit
2308 i = len - 1;
2309 for (;;) {
2310 n->num[n->len] = val[i] - '0';
2311 ++n->len;
2312 skip_dot:
2313 if (i == 0) break;
2314 if (val[--i] == '.') goto skip_dot;
2315 }
2316 break;
2317 }
2318 }
2319 // if for() exits without hitting if(), the value is entirely zero
2320}
2321
2322// Note: n is already "bc_num_zero()"ed,
2323// leading zeroes in "val" are removed
2324static void bc_num_parseBase(BcNum *n, const char *val, unsigned base_t)
2325{
2326 BcStatus s;
2327 BcNum temp, mult, result;
2328 BcNum base;
2329 BcDig base_digs[ULONG_NUM_BUFSIZE];
2330 BcDig c = '\0';
2331 unsigned long v;
2332 size_t i, digits;
2333
2334 for (i = 0; ; ++i) {
2335 if (val[i] == '\0')
2336 return;
2337 if (val[i] != '.' && val[i] != '0')
2338 break;
2339 }
2340
2341 bc_num_init_DEF_SIZE(&temp);
2342 bc_num_init_DEF_SIZE(&mult);
2343 base.cap = ARRAY_SIZE(base_digs);
2344 base.num = base_digs;
2345 bc_num_ulong2num(&base, base_t);
2346
2347 for (;;) {
2348 c = *val++;
2349 if (c == '\0') goto int_err;
2350 if (c == '.') break;
2351
2352 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2353
2354 s = zbc_num_mul(n, &base, &mult, 0);
2355 if (s) goto int_err;
2356 bc_num_ulong2num(&temp, v);
2357 s = zbc_num_add(&mult, &temp, n, 0);
2358 if (s) goto int_err;
2359 }
2360
2361 bc_num_init(&result, base.len);
2362 //bc_num_zero(&result); - already is
2363 bc_num_one(&mult);
2364
2365 digits = 0;
2366 for (;;) {
2367 c = *val++;
2368 if (c == '\0') break;
2369 digits++;
2370
2371 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2372
2373 s = zbc_num_mul(&result, &base, &result, 0);
2374 if (s) goto err;
2375 bc_num_ulong2num(&temp, v);
2376 s = zbc_num_add(&result, &temp, &result, 0);
2377 if (s) goto err;
2378 s = zbc_num_mul(&mult, &base, &mult, 0);
2379 if (s) goto err;
2380 }
2381
2382 s = zbc_num_div(&result, &mult, &result, digits);
2383 if (s) goto err;
2384 s = zbc_num_add(n, &result, n, digits);
2385 if (s) goto err;
2386
2387 if (n->len != 0) {
2388 if (n->rdx < digits)
2389 bc_num_extend(n, digits - n->rdx);
2390 } else
2391 bc_num_zero(n);
2392 err:
2393 bc_num_free(&result);
2394 int_err:
2395 bc_num_free(&mult);
2396 bc_num_free(&temp);
2397}
2398
2399static BC_STATUS zbc_num_parse(BcNum *n, const char *val, unsigned base_t)
2400{
2401 if (!bc_num_strValid(val, base_t))
2402 RETURN_STATUS(bc_error("bad number string"));
2403
2404 bc_num_zero(n);
2405 while (*val == '0') val++;
2406
2407 if (base_t == 10)
2408 bc_num_parseDecimal(n, val);
2409 else
2410 bc_num_parseBase(n, val, base_t);
2411
2412 RETURN_STATUS(BC_STATUS_SUCCESS);
2413}
2414#define zbc_num_parse(...) (zbc_num_parse(__VA_ARGS__) COMMA_SUCCESS)
2415
2416static BC_STATUS zbc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale) 2165static BC_STATUS zbc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2417{ 2166{
2418 BcStatus s; 2167 BcStatus s;
@@ -2595,29 +2344,6 @@ static BC_STATUS zdc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2595#define zdc_num_modexp(...) (zdc_num_modexp(__VA_ARGS__) COMMA_SUCCESS) 2344#define zdc_num_modexp(...) (zdc_num_modexp(__VA_ARGS__) COMMA_SUCCESS)
2596#endif // ENABLE_DC 2345#endif // ENABLE_DC
2597 2346
2598#if ENABLE_BC
2599static BC_STATUS zbc_func_insert(BcFunc *f, char *name, bool var)
2600{
2601 BcId *autoid;
2602 BcId a;
2603 size_t i;
2604
2605 autoid = (void*)f->autos.v;
2606 for (i = 0; i < f->autos.len; i++, autoid++) {
2607 if (strcmp(name, autoid->name) == 0)
2608 RETURN_STATUS(bc_error("function parameter or auto var has the same name as another"));
2609 }
2610
2611 a.idx = var;
2612 a.name = name;
2613
2614 bc_vec_push(&f->autos, &a);
2615
2616 RETURN_STATUS(BC_STATUS_SUCCESS);
2617}
2618#define zbc_func_insert(...) (zbc_func_insert(__VA_ARGS__) COMMA_SUCCESS)
2619#endif
2620
2621static FAST_FUNC void bc_string_free(void *string) 2347static FAST_FUNC void bc_string_free(void *string)
2622{ 2348{
2623 free(*(char**)string); 2349 free(*(char**)string);
@@ -2740,6 +2466,258 @@ static FAST_FUNC void bc_result_free(void *result)
2740 } 2466 }
2741} 2467}
2742 2468
2469static int bad_input_byte(char c)
2470{
2471 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
2472 || c > 0x7e
2473 ) {
2474 bc_error_fmt("illegal character 0x%02x", c);
2475 return 1;
2476 }
2477 return 0;
2478}
2479
2480// Note: it _appends_ data from fp to vec.
2481static void bc_read_line(BcVec *vec, FILE *fp)
2482{
2483 again:
2484 fflush_and_check();
2485
2486#if ENABLE_FEATURE_BC_SIGNALS
2487 if (G_interrupt) { // ^C was pressed
2488 intr:
2489 if (fp != stdin) {
2490 // ^C while running a script (bc SCRIPT): die.
2491 // We do not return to interactive prompt:
2492 // user might be running us from a shell,
2493 // and SCRIPT might be intended to terminate
2494 // (e.g. contain a "halt" stmt).
2495 // ^C dropping user into a bc prompt instead of
2496 // the shell would be unexpected.
2497 xfunc_die();
2498 }
2499 // ^C while interactive input
2500 G_interrupt = 0;
2501 // GNU bc says "interrupted execution."
2502 // GNU dc says "Interrupt!"
2503 fputs("\ninterrupted execution\n", stderr);
2504 }
2505
2506# if ENABLE_FEATURE_EDITING
2507 if (G_ttyin && fp == stdin) {
2508 int n, i;
2509# define line_buf bb_common_bufsiz1
2510 n = read_line_input(G.line_input_state, "", line_buf, COMMON_BUFSIZE);
2511 if (n <= 0) { // read errors or EOF, or ^D, or ^C
2512 if (n == 0) // ^C
2513 goto intr;
2514 bc_vec_pushZeroByte(vec); // ^D or EOF (or error)
2515 return;
2516 }
2517 i = 0;
2518 for (;;) {
2519 char c = line_buf[i++];
2520 if (!c) break;
2521 if (bad_input_byte(c)) goto again;
2522 }
2523 bc_vec_concat(vec, line_buf);
2524# undef line_buf
2525 } else
2526# endif
2527#endif
2528 {
2529 int c;
2530 bool bad_chars = 0;
2531 size_t len = vec->len;
2532
2533 do {
2534#if ENABLE_FEATURE_BC_SIGNALS
2535 if (G_interrupt) {
2536 // ^C was pressed: ignore entire line, get another one
2537 vec->len = len;
2538 goto intr;
2539 }
2540#endif
2541 do c = fgetc(fp); while (c == '\0');
2542 if (c == EOF) {
2543 if (ferror(fp))
2544 bb_perror_msg_and_die("input error");
2545 // Note: EOF does not append '\n'
2546 break;
2547 }
2548 bad_chars |= bad_input_byte(c);
2549 bc_vec_pushByte(vec, (char)c);
2550 } while (c != '\n');
2551
2552 if (bad_chars) {
2553 // Bad chars on this line
2554 if (!G.prog.file) { // stdin
2555 // ignore entire line, get another one
2556 vec->len = len;
2557 goto again;
2558 }
2559 bb_perror_msg_and_die("file '%s' is not text", G.prog.file);
2560 }
2561 bc_vec_pushZeroByte(vec);
2562 }
2563}
2564
2565//
2566// Parsing routines
2567//
2568
2569static bool bc_num_strValid(const char *val, size_t base)
2570{
2571 BcDig b;
2572 bool radix;
2573
2574 b = (BcDig)(base <= 10 ? base + '0' : base - 10 + 'A');
2575 radix = false;
2576 for (;;) {
2577 BcDig c = *val++;
2578 if (c == '\0')
2579 break;
2580 if (c == '.') {
2581 if (radix) return false;
2582 radix = true;
2583 continue;
2584 }
2585 if (c < '0' || c >= b || (c > '9' && c < 'A'))
2586 return false;
2587 }
2588 return true;
2589}
2590
2591// Note: n is already "bc_num_zero()"ed,
2592// leading zeroes in "val" are removed
2593static void bc_num_parseDecimal(BcNum *n, const char *val)
2594{
2595 size_t len, i;
2596 const char *ptr;
2597
2598 len = strlen(val);
2599 if (len == 0)
2600 return;
2601
2602 bc_num_expand(n, len);
2603
2604 ptr = strchr(val, '.');
2605
2606 n->rdx = 0;
2607 if (ptr != NULL)
2608 n->rdx = (size_t)((val + len) - (ptr + 1));
2609
2610 for (i = 0; val[i]; ++i) {
2611 if (val[i] != '0' && val[i] != '.') {
2612 // Not entirely zero value - convert it, and exit
2613 i = len - 1;
2614 for (;;) {
2615 n->num[n->len] = val[i] - '0';
2616 ++n->len;
2617 skip_dot:
2618 if (i == 0) break;
2619 if (val[--i] == '.') goto skip_dot;
2620 }
2621 break;
2622 }
2623 }
2624 // if for() exits without hitting if(), the value is entirely zero
2625}
2626
2627// Note: n is already "bc_num_zero()"ed,
2628// leading zeroes in "val" are removed
2629static void bc_num_parseBase(BcNum *n, const char *val, unsigned base_t)
2630{
2631 BcStatus s;
2632 BcNum temp, mult, result;
2633 BcNum base;
2634 BcDig base_digs[ULONG_NUM_BUFSIZE];
2635 BcDig c = '\0';
2636 unsigned long v;
2637 size_t i, digits;
2638
2639 for (i = 0; ; ++i) {
2640 if (val[i] == '\0')
2641 return;
2642 if (val[i] != '.' && val[i] != '0')
2643 break;
2644 }
2645
2646 bc_num_init_DEF_SIZE(&temp);
2647 bc_num_init_DEF_SIZE(&mult);
2648 base.cap = ARRAY_SIZE(base_digs);
2649 base.num = base_digs;
2650 bc_num_ulong2num(&base, base_t);
2651
2652 for (;;) {
2653 c = *val++;
2654 if (c == '\0') goto int_err;
2655 if (c == '.') break;
2656
2657 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2658
2659 s = zbc_num_mul(n, &base, &mult, 0);
2660 if (s) goto int_err;
2661 bc_num_ulong2num(&temp, v);
2662 s = zbc_num_add(&mult, &temp, n, 0);
2663 if (s) goto int_err;
2664 }
2665
2666 bc_num_init(&result, base.len);
2667 //bc_num_zero(&result); - already is
2668 bc_num_one(&mult);
2669
2670 digits = 0;
2671 for (;;) {
2672 c = *val++;
2673 if (c == '\0') break;
2674 digits++;
2675
2676 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2677
2678 s = zbc_num_mul(&result, &base, &result, 0);
2679 if (s) goto err;
2680 bc_num_ulong2num(&temp, v);
2681 s = zbc_num_add(&result, &temp, &result, 0);
2682 if (s) goto err;
2683 s = zbc_num_mul(&mult, &base, &mult, 0);
2684 if (s) goto err;
2685 }
2686
2687 s = zbc_num_div(&result, &mult, &result, digits);
2688 if (s) goto err;
2689 s = zbc_num_add(n, &result, n, digits);
2690 if (s) goto err;
2691
2692 if (n->len != 0) {
2693 if (n->rdx < digits)
2694 bc_num_extend(n, digits - n->rdx);
2695 } else
2696 bc_num_zero(n);
2697 err:
2698 bc_num_free(&result);
2699 int_err:
2700 bc_num_free(&mult);
2701 bc_num_free(&temp);
2702}
2703
2704static BC_STATUS zbc_num_parse(BcNum *n, const char *val, unsigned base_t)
2705{
2706 if (!bc_num_strValid(val, base_t))
2707 RETURN_STATUS(bc_error("bad number string"));
2708
2709 bc_num_zero(n);
2710 while (*val == '0') val++;
2711
2712 if (base_t == 10)
2713 bc_num_parseDecimal(n, val);
2714 else
2715 bc_num_parseBase(n, val, base_t);
2716
2717 RETURN_STATUS(BC_STATUS_SUCCESS);
2718}
2719#define zbc_num_parse(...) (zbc_num_parse(__VA_ARGS__) COMMA_SUCCESS)
2720
2743static void bc_lex_lineComment(BcLex *l) 2721static void bc_lex_lineComment(BcLex *l)
2744{ 2722{
2745 // Try: echo -n '#foo' | bc 2723 // Try: echo -n '#foo' | bc
@@ -4333,6 +4311,27 @@ static BC_STATUS zbc_parse_break_or_continue(BcParse *p, BcLexType type)
4333} 4311}
4334#define zbc_parse_break_or_continue(...) (zbc_parse_break_or_continue(__VA_ARGS__) COMMA_SUCCESS) 4312#define zbc_parse_break_or_continue(...) (zbc_parse_break_or_continue(__VA_ARGS__) COMMA_SUCCESS)
4335 4313
4314static BC_STATUS zbc_func_insert(BcFunc *f, char *name, bool var)
4315{
4316 BcId *autoid;
4317 BcId a;
4318 size_t i;
4319
4320 autoid = (void*)f->autos.v;
4321 for (i = 0; i < f->autos.len; i++, autoid++) {
4322 if (strcmp(name, autoid->name) == 0)
4323 RETURN_STATUS(bc_error("function parameter or auto var has the same name as another"));
4324 }
4325
4326 a.idx = var;
4327 a.name = name;
4328
4329 bc_vec_push(&f->autos, &a);
4330
4331 RETURN_STATUS(BC_STATUS_SUCCESS);
4332}
4333#define zbc_func_insert(...) (zbc_func_insert(__VA_ARGS__) COMMA_SUCCESS)
4334
4336static BC_STATUS zbc_parse_funcdef(BcParse *p) 4335static BC_STATUS zbc_parse_funcdef(BcParse *p)
4337{ 4336{
4338 BcStatus s; 4337 BcStatus s;
@@ -5010,6 +5009,13 @@ static BC_STATUS zdc_parse_exprs_until_eof(BcParse *p)
5010 5009
5011#endif // ENABLE_DC 5010#endif // ENABLE_DC
5012 5011
5012//
5013// Execution engine
5014//
5015
5016#define STACK_HAS_MORE_THAN(s, n) ((s)->len > ((size_t)(n)))
5017#define STACK_HAS_EQUAL_OR_MORE_THAN(s, n) ((s)->len >= ((size_t)(n)))
5018
5013static BcVec* bc_program_search(char *id, bool var) 5019static BcVec* bc_program_search(char *id, bool var)
5014{ 5020{
5015 BcId e, *ptr; 5021 BcId e, *ptr;
@@ -5400,6 +5406,8 @@ static void bc_num_printDecimal(BcNum *n)
5400 bc_num_printHex((size_t) n->num[i], 1, i == rdx); 5406 bc_num_printHex((size_t) n->num[i], 1, i == rdx);
5401} 5407}
5402 5408
5409typedef void (*BcNumDigitOp)(size_t, size_t, bool) FAST_FUNC;
5410
5403static BC_STATUS zbc_num_printNum(BcNum *n, unsigned base_t, size_t width, BcNumDigitOp print) 5411static BC_STATUS zbc_num_printNum(BcNum *n, unsigned base_t, size_t width, BcNumDigitOp print)
5404{ 5412{
5405 BcStatus s; 5413 BcStatus s;