diff options
-rw-r--r-- | miscutils/bc.c | 198 |
1 files changed, 94 insertions, 104 deletions
diff --git a/miscutils/bc.c b/miscutils/bc.c index 0908d7cb9..ef21ab063 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c | |||
@@ -217,14 +217,6 @@ typedef struct BcNum { | |||
217 | typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t); | 217 | typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t); |
218 | typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t); | 218 | typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t); |
219 | 219 | ||
220 | static void bc_num_init(BcNum *n, size_t req); | ||
221 | static void bc_num_expand(BcNum *n, size_t req); | ||
222 | static void bc_num_copy(BcNum *d, BcNum *s); | ||
223 | static void bc_num_free(void *num); | ||
224 | |||
225 | static BcStatus bc_num_ulong(BcNum *n, unsigned long *result); | ||
226 | static void bc_num_ulong2num(BcNum *n, unsigned long val); | ||
227 | |||
228 | static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale); | 220 | static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale); |
229 | static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale); | 221 | static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale); |
230 | static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale); | 222 | static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale); |
@@ -387,7 +379,6 @@ typedef struct BcInstPtr { | |||
387 | size_t len; | 379 | size_t len; |
388 | } BcInstPtr; | 380 | } BcInstPtr; |
389 | 381 | ||
390 | static void bc_array_expand(BcVec *a, size_t len); | ||
391 | static int bc_id_cmp(const void *e1, const void *e2); | 382 | static int bc_id_cmp(const void *e1, const void *e2); |
392 | 383 | ||
393 | // BC_LEX_NEG is not used in lexing; it is only for parsing. | 384 | // BC_LEX_NEG is not used in lexing; it is only for parsing. |
@@ -798,11 +789,8 @@ struct globals { | |||
798 | #define G_exreg (ENABLE_DC && (option_mask32 & BC_FLAG_X)) | 789 | #define G_exreg (ENABLE_DC && (option_mask32 & BC_FLAG_X)) |
799 | #define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0) | 790 | #define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0) |
800 | 791 | ||
801 | |||
802 | #define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b')) | 792 | #define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b')) |
803 | 793 | ||
804 | static void bc_vm_info(void); | ||
805 | |||
806 | #if ENABLE_BC | 794 | #if ENABLE_BC |
807 | 795 | ||
808 | // This is a bit array that corresponds to token types. An entry is | 796 | // This is a bit array that corresponds to token types. An entry is |
@@ -1046,6 +1034,15 @@ static int bc_error_nested_read_call(void) | |||
1046 | return bc_error("read() call inside of a read() call"); | 1034 | return bc_error("read() call inside of a read() call"); |
1047 | } | 1035 | } |
1048 | 1036 | ||
1037 | static void bc_vm_info(void) | ||
1038 | { | ||
1039 | printf("%s "BB_VER"\n" | ||
1040 | "Copyright (c) 2018 Gavin D. Howard and contributors\n" | ||
1041 | "Report bugs at: https://github.com/gavinhoward/bc\n" | ||
1042 | "This is free software with ABSOLUTELY NO WARRANTY\n" | ||
1043 | , applet_name); | ||
1044 | } | ||
1045 | |||
1049 | static void bc_vec_grow(BcVec *v, size_t n) | 1046 | static void bc_vec_grow(BcVec *v, size_t n) |
1050 | { | 1047 | { |
1051 | size_t cap = v->cap * 2; | 1048 | size_t cap = v->cap * 2; |
@@ -1351,6 +1348,74 @@ static void bc_num_ten(BcNum *n) | |||
1351 | n->num[1] = 1; | 1348 | n->num[1] = 1; |
1352 | } | 1349 | } |
1353 | 1350 | ||
1351 | static void bc_num_init(BcNum *n, size_t req) | ||
1352 | { | ||
1353 | req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE; | ||
1354 | memset(n, 0, sizeof(BcNum)); | ||
1355 | n->num = xmalloc(req); | ||
1356 | n->cap = req; | ||
1357 | } | ||
1358 | |||
1359 | static void bc_num_expand(BcNum *n, size_t req) | ||
1360 | { | ||
1361 | req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE; | ||
1362 | if (req > n->cap) { | ||
1363 | n->num = xrealloc(n->num, req); | ||
1364 | n->cap = req; | ||
1365 | } | ||
1366 | } | ||
1367 | |||
1368 | static void bc_num_free(void *num) | ||
1369 | { | ||
1370 | free(((BcNum *) num)->num); | ||
1371 | } | ||
1372 | |||
1373 | static void bc_num_copy(BcNum *d, BcNum *s) | ||
1374 | { | ||
1375 | if (d != s) { | ||
1376 | bc_num_expand(d, s->cap); | ||
1377 | d->len = s->len; | ||
1378 | d->neg = s->neg; | ||
1379 | d->rdx = s->rdx; | ||
1380 | memcpy(d->num, s->num, sizeof(BcDig) * d->len); | ||
1381 | } | ||
1382 | } | ||
1383 | |||
1384 | static BcStatus bc_num_ulong(BcNum *n, unsigned long *result) | ||
1385 | { | ||
1386 | size_t i; | ||
1387 | unsigned long pow; | ||
1388 | |||
1389 | if (n->neg) return bc_error("negative number"); | ||
1390 | |||
1391 | for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) { | ||
1392 | |||
1393 | unsigned long prev = *result, powprev = pow; | ||
1394 | |||
1395 | *result += ((unsigned long) n->num[i]) * pow; | ||
1396 | pow *= 10; | ||
1397 | |||
1398 | if (*result < prev || pow < powprev) | ||
1399 | return bc_error("overflow"); | ||
1400 | } | ||
1401 | |||
1402 | return BC_STATUS_SUCCESS; | ||
1403 | } | ||
1404 | |||
1405 | static void bc_num_ulong2num(BcNum *n, unsigned long val) | ||
1406 | { | ||
1407 | size_t len; | ||
1408 | BcDig *ptr; | ||
1409 | unsigned long i; | ||
1410 | |||
1411 | bc_num_zero(n); | ||
1412 | |||
1413 | if (val == 0) return; | ||
1414 | |||
1415 | for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len); | ||
1416 | for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10; | ||
1417 | } | ||
1418 | |||
1354 | static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b, | 1419 | static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b, |
1355 | size_t len) | 1420 | size_t len) |
1356 | { | 1421 | { |
@@ -2343,39 +2408,6 @@ static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len) | |||
2343 | } | 2408 | } |
2344 | #endif | 2409 | #endif |
2345 | 2410 | ||
2346 | static void bc_num_init(BcNum *n, size_t req) | ||
2347 | { | ||
2348 | req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE; | ||
2349 | memset(n, 0, sizeof(BcNum)); | ||
2350 | n->num = xmalloc(req); | ||
2351 | n->cap = req; | ||
2352 | } | ||
2353 | |||
2354 | static void bc_num_expand(BcNum *n, size_t req) | ||
2355 | { | ||
2356 | req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE; | ||
2357 | if (req > n->cap) { | ||
2358 | n->num = xrealloc(n->num, req); | ||
2359 | n->cap = req; | ||
2360 | } | ||
2361 | } | ||
2362 | |||
2363 | static void bc_num_free(void *num) | ||
2364 | { | ||
2365 | free(((BcNum *) num)->num); | ||
2366 | } | ||
2367 | |||
2368 | static void bc_num_copy(BcNum *d, BcNum *s) | ||
2369 | { | ||
2370 | if (d != s) { | ||
2371 | bc_num_expand(d, s->cap); | ||
2372 | d->len = s->len; | ||
2373 | d->neg = s->neg; | ||
2374 | d->rdx = s->rdx; | ||
2375 | memcpy(d->num, s->num, sizeof(BcDig) * d->len); | ||
2376 | } | ||
2377 | } | ||
2378 | |||
2379 | static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base, | 2411 | static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base, |
2380 | size_t base_t) | 2412 | size_t base_t) |
2381 | { | 2413 | { |
@@ -2414,41 +2446,6 @@ static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline, | |||
2414 | return s; | 2446 | return s; |
2415 | } | 2447 | } |
2416 | 2448 | ||
2417 | static BcStatus bc_num_ulong(BcNum *n, unsigned long *result) | ||
2418 | { | ||
2419 | size_t i; | ||
2420 | unsigned long pow; | ||
2421 | |||
2422 | if (n->neg) return bc_error("negative number"); | ||
2423 | |||
2424 | for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) { | ||
2425 | |||
2426 | unsigned long prev = *result, powprev = pow; | ||
2427 | |||
2428 | *result += ((unsigned long) n->num[i]) * pow; | ||
2429 | pow *= 10; | ||
2430 | |||
2431 | if (*result < prev || pow < powprev) | ||
2432 | return bc_error("overflow"); | ||
2433 | } | ||
2434 | |||
2435 | return BC_STATUS_SUCCESS; | ||
2436 | } | ||
2437 | |||
2438 | static void bc_num_ulong2num(BcNum *n, unsigned long val) | ||
2439 | { | ||
2440 | size_t len; | ||
2441 | BcDig *ptr; | ||
2442 | unsigned long i; | ||
2443 | |||
2444 | bc_num_zero(n); | ||
2445 | |||
2446 | if (val == 0) return; | ||
2447 | |||
2448 | for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len); | ||
2449 | for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10; | ||
2450 | } | ||
2451 | |||
2452 | static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale) | 2449 | static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale) |
2453 | { | 2450 | { |
2454 | BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s; | 2451 | BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s; |
@@ -2712,6 +2709,8 @@ static void bc_func_free(void *func) | |||
2712 | bc_vec_free(&f->labels); | 2709 | bc_vec_free(&f->labels); |
2713 | } | 2710 | } |
2714 | 2711 | ||
2712 | static void bc_array_expand(BcVec *a, size_t len); | ||
2713 | |||
2715 | static void bc_array_init(BcVec *a, bool nums) | 2714 | static void bc_array_init(BcVec *a, bool nums) |
2716 | { | 2715 | { |
2717 | if (nums) | 2716 | if (nums) |
@@ -2721,21 +2720,6 @@ static void bc_array_init(BcVec *a, bool nums) | |||
2721 | bc_array_expand(a, 1); | 2720 | bc_array_expand(a, 1); |
2722 | } | 2721 | } |
2723 | 2722 | ||
2724 | static void bc_array_copy(BcVec *d, const BcVec *s) | ||
2725 | { | ||
2726 | size_t i; | ||
2727 | |||
2728 | bc_vec_pop_all(d); | ||
2729 | bc_vec_expand(d, s->cap); | ||
2730 | d->len = s->len; | ||
2731 | |||
2732 | for (i = 0; i < s->len; ++i) { | ||
2733 | BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i); | ||
2734 | bc_num_init(dnum, snum->len); | ||
2735 | bc_num_copy(dnum, snum); | ||
2736 | } | ||
2737 | } | ||
2738 | |||
2739 | static void bc_array_expand(BcVec *a, size_t len) | 2723 | static void bc_array_expand(BcVec *a, size_t len) |
2740 | { | 2724 | { |
2741 | BcResultData data; | 2725 | BcResultData data; |
@@ -2754,6 +2738,21 @@ static void bc_array_expand(BcVec *a, size_t len) | |||
2754 | } | 2738 | } |
2755 | } | 2739 | } |
2756 | 2740 | ||
2741 | static void bc_array_copy(BcVec *d, const BcVec *s) | ||
2742 | { | ||
2743 | size_t i; | ||
2744 | |||
2745 | bc_vec_pop_all(d); | ||
2746 | bc_vec_expand(d, s->cap); | ||
2747 | d->len = s->len; | ||
2748 | |||
2749 | for (i = 0; i < s->len; ++i) { | ||
2750 | BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i); | ||
2751 | bc_num_init(dnum, snum->len); | ||
2752 | bc_num_copy(dnum, snum); | ||
2753 | } | ||
2754 | } | ||
2755 | |||
2757 | static void bc_string_free(void *string) | 2756 | static void bc_string_free(void *string) |
2758 | { | 2757 | { |
2759 | free(*((char **) string)); | 2758 | free(*((char **) string)); |
@@ -6854,15 +6853,6 @@ static BcStatus bc_program_exec(void) | |||
6854 | return s; | 6853 | return s; |
6855 | } | 6854 | } |
6856 | 6855 | ||
6857 | static void bc_vm_info(void) | ||
6858 | { | ||
6859 | printf("%s "BB_VER"\n" | ||
6860 | "Copyright (c) 2018 Gavin D. Howard and contributors\n" | ||
6861 | "Report bugs at: https://github.com/gavinhoward/bc\n" | ||
6862 | "This is free software with ABSOLUTELY NO WARRANTY\n" | ||
6863 | , applet_name); | ||
6864 | } | ||
6865 | |||
6866 | #if ENABLE_BC | 6856 | #if ENABLE_BC |
6867 | static void bc_vm_envArgs(void) | 6857 | static void bc_vm_envArgs(void) |
6868 | { | 6858 | { |