Browse Source

Implement command-line args to set the four builtin variables

This was requested a long time ago, and I rejected it. I see differently
now because the vast majority of my -e invocations are to set these.

Signed-off-by: Gavin Howard <gavin@yzena.com>
master
Gavin Howard 2 months ago
parent
commit
488d48c87c
Signed by: gavin
GPG Key ID: C08038BDF280D33E
  1. 3
      include/args.h
  2. 4
      include/num.h
  3. 19
      include/program.h
  4. 94
      src/args.c
  5. 6
      src/data.c
  6. 3
      src/num.c
  7. 112
      src/program.c
  8. 5
      src/vm.c

3
include/args.h

@ -46,9 +46,10 @@
* @param argv The array of arguments.
* @param exit_exprs True if bc/dc should exit when there are expressions,
* false otherwise.
* @param scale The current scale.
*/
void
bc_args(int argc, char* argv[], bool exit_exprs);
bc_args(int argc, char* argv[], bool exit_exprs, BcBigDig scale);
// A reference to the list of long options.
extern const BcOptLong bc_args_lopt[];

4
include/num.h

@ -799,8 +799,6 @@ bc_num_one(BcNum* restrict n);
ssize_t
bc_num_cmpZero(const BcNum* n);
#if !defined(NDEBUG) || BC_ENABLE_LIBRARY
/**
* Check a number string for validity and return true if it is, false otherwise.
* The library needs this to check user-supplied strings, but in bc and dc, this
@ -812,8 +810,6 @@ bc_num_cmpZero(const BcNum* n);
bool
bc_num_strValid(const char* restrict val);
#endif // !defined(NDEBUG) || BC_ENABLE_LIBRARY
/**
* Parses a number string into the number @a n according to @a base.
* @param n The number to set to the parsed value.

19
include/program.h

@ -384,8 +384,27 @@ bc_program_not(BcResult* r, BcNum* n);
void
bc_program_trunc(BcResult* r, BcNum* n);
/**
* Assigns a value to the seed builtin variable.
* @param p The program.
* @param val The value to assign to the seed.
*/
void
bc_program_assignSeed(BcProgram* p, BcNum* val);
#endif // BC_ENABLE_EXTRA_MATH
/**
* Assigns a value to a builtin value that is not seed.
* @param p The program.
* @param scale True if the builtin is scale.
* @param obase True if the builtin is obase. This cannot be true at the same
* time @a scale is.
* @param val The value to assign to the builtin.
*/
void
bc_program_assignBuiltin(BcProgram* p, bool scale, bool obase, BcBigDig val);
/// A reference to an array of binary operator functions.
extern const BcNumBinaryOp bc_program_ops[];

94
src/args.c

@ -47,6 +47,7 @@
#include <read.h>
#include <args.h>
#include <opt.h>
#include <num.h>
/**
* Adds @a str to the list of expressions to execute later.
@ -83,6 +84,32 @@ bc_args_file(const char* file)
free(buf);
}
static BcBigDig
bc_args_builtin(const char* arg)
{
bool strvalid;
BcVec v;
BcNum n;
BcBigDig res;
strvalid = bc_num_strValid(arg);
if (BC_ERR(!strvalid))
{
bc_verr(BC_ERR_FATAL_ARG, arg);
}
bc_num_init(&n, 0);
bc_num_parse(&n, arg, 10);
res = bc_num_bigdig(&n);
bc_num_free(&n);
return res;
}
#if BC_ENABLED
/**
@ -117,12 +144,14 @@ bc_args_redefine(const char* keyword)
#endif // BC_ENABLED
void
bc_args(int argc, char* argv[], bool exit_exprs)
bc_args(int argc, char* argv[], bool exit_exprs, BcBigDig scale)
{
int c;
size_t i;
bool do_exit = false, version = false;
BcOpt opts;
BcBigDig newscale = scale, ibase = BC_BASE, obase = BC_BASE;
char* seed = NULL;
BC_SIG_ASSERT_LOCKED;
@ -182,6 +211,12 @@ bc_args(int argc, char* argv[], bool exit_exprs)
break;
}
case 'I':
{
ibase = bc_args_builtin(opts.optarg);
break;
}
case 'z':
{
vm.flags |= BC_FLAG_Z;
@ -194,6 +229,12 @@ bc_args(int argc, char* argv[], bool exit_exprs)
break;
}
case 'O':
{
obase = bc_args_builtin(opts.optarg);
break;
}
case 'P':
{
vm.flags &= ~(BC_FLAG_P);
@ -206,6 +247,26 @@ bc_args(int argc, char* argv[], bool exit_exprs)
break;
}
case 'S':
{
newscale = bc_args_builtin(opts.optarg);
break;
}
#if BC_ENABLE_EXTRA_MATH
case 'E':
{
if (BC_ERR(!bc_num_strValid(opts.optarg)))
{
bc_verr(BC_ERR_FATAL_ARG, opts.optarg);
}
seed = opts.optarg;
break;
}
#endif // BC_ENABLE_EXTRA_MATH
#if BC_ENABLED
case 'g':
{
@ -301,4 +362,35 @@ bc_args(int argc, char* argv[], bool exit_exprs)
{
bc_vec_push(&vm.files, argv + i);
}
#if BC_ENABLE_EXTRA_MATH
if (seed != NULL)
{
BcNum n;
bc_num_init(&n, strlen(seed));
bc_num_parse(&n, seed, BC_BASE);
bc_program_assignSeed(&vm.prog, &n);
bc_num_free(&n);
}
#endif // BC_ENABLE_EXTRA_MATH
if (newscale != scale)
{
bc_program_assignBuiltin(&vm.prog, true, false, newscale);
}
if (obase != BC_BASE)
{
bc_program_assignBuiltin(&vm.prog, false, true, obase);
}
// This is last to avoid it affecting the value of the others.
if (ibase != BC_BASE)
{
bc_program_assignBuiltin(&vm.prog, false, false, ibase);
}
}

6
src/data.c

@ -145,10 +145,16 @@ const BcOptLong bc_args_lopt[] = {
{ "file", BC_OPT_REQUIRED, 'f' },
{ "help", BC_OPT_NONE, 'h' },
{ "interactive", BC_OPT_NONE, 'i' },
{ "ibase", BC_OPT_REQUIRED, 'I' },
{ "leading-zeroes", BC_OPT_NONE, 'z' },
{ "no-line-length", BC_OPT_NONE, 'L' },
{ "obase", BC_OPT_REQUIRED, 'O' },
{ "no-prompt", BC_OPT_NONE, 'P' },
{ "no-read-prompt", BC_OPT_NONE, 'R' },
{ "scale", BC_OPT_REQUIRED, 'S' },
#if BC_ENABLE_EXTRA_MATH
{ "seed", BC_OPT_REQUIRED, 'E' },
#endif // BC_ENABLE_EXTRA_MATH
#if BC_ENABLED
{ "global-stacks", BC_OPT_BC_ONLY, 'g' },
{ "mathlib", BC_OPT_BC_ONLY, 'l' },

3
src/num.c

@ -2248,8 +2248,6 @@ err:
}
}
#if !defined(NDEBUG) || BC_ENABLE_LIBRARY
/**
* Tests a number string for validity. This function has a history; I originally
* wrote it because I did not trust my parser. Over time, however, I came to
@ -2293,7 +2291,6 @@ bc_num_strValid(const char* restrict val)
return true;
}
#endif // !defined(NDEBUG) || BC_ENABLE_LIBRARY
/**
* Parses one character and returns the digit that corresponds to that

112
src/program.c

@ -1336,6 +1336,69 @@ bc_program_copyToVar(BcProgram* p, size_t idx, BcType t, bool last)
BC_SIG_UNLOCK;
}
void
bc_program_assignBuiltin(BcProgram* p, bool scale, bool obase, BcBigDig val)
{
BcVec* v;
BcBigDig* ptr;
BcBigDig* ptr_t;
BcBigDig max, min;
assert(!scale || !obase);
// Scale needs handling separate from ibase and obase.
if (scale)
{
// Set the min and max.
min = 0;
max = vm.maxes[BC_PROG_GLOBALS_SCALE];
// Get a pointer to the stack and to the current value.
v = p->globals_v + BC_PROG_GLOBALS_SCALE;
ptr_t = p->globals + BC_PROG_GLOBALS_SCALE;
}
else
{
// Set the min and max.
min = BC_NUM_MIN_BASE;
if (BC_ENABLE_EXTRA_MATH && obase && (BC_IS_DC || !BC_IS_POSIX))
{
min = 0;
}
max = vm.maxes[obase + BC_PROG_GLOBALS_IBASE];
// Get a pointer to the stack and to the current value.
v = p->globals_v + BC_PROG_GLOBALS_IBASE + obase;
ptr_t = p->globals + BC_PROG_GLOBALS_IBASE + obase;
}
// Check for error.
if (BC_ERR(val > max || val < min))
{
BcErr e;
// This grabs the right error.
if (scale) e = BC_ERR_EXEC_SCALE;
else if (obase) e = BC_ERR_EXEC_OBASE;
else e = BC_ERR_EXEC_IBASE;
bc_verr(e, min, max);
}
// Set the top of the stack and the actual global value.
ptr = bc_vec_top(v);
*ptr = val;
*ptr_t = val;
}
#if BC_ENABLE_EXTRA_MATH
void
bc_program_assignSeed(BcProgram* p, BcNum* val)
{
bc_num_rng(val, &p->rng);
}
#endif // BC_ENABLE_EXTRA_MATH
/**
* Executes an assignment operator.
* @param p The program.
@ -1472,57 +1535,14 @@ bc_program_assign(BcProgram* p, uchar inst)
// first part of the if statement handles them.
if (ob || sc || left->t == BC_RESULT_IBASE)
{
BcVec* v;
BcBigDig* ptr;
BcBigDig* ptr_t;
BcBigDig val, max, min;
// Get the actual value.
val = bc_num_bigdig(l);
// Scale needs handling separate from ibase and obase.
if (sc)
{
// Set the min and max.
min = 0;
max = vm.maxes[BC_PROG_GLOBALS_SCALE];
// Get a pointer to the stack and to the current value.
v = p->globals_v + BC_PROG_GLOBALS_SCALE;
ptr_t = p->globals + BC_PROG_GLOBALS_SCALE;
}
else
{
// Set the min and max.
min = BC_NUM_MIN_BASE;
if (BC_ENABLE_EXTRA_MATH && ob && (BC_IS_DC || !BC_IS_POSIX))
{
min = 0;
}
max = vm.maxes[ob + BC_PROG_GLOBALS_IBASE];
// Get a pointer to the stack and to the current value.
v = p->globals_v + BC_PROG_GLOBALS_IBASE + ob;
ptr_t = p->globals + BC_PROG_GLOBALS_IBASE + ob;
}
// Check for error.
if (BC_ERR(val > max || val < min))
{
// This grabs the right error.
BcErr e = left->t - BC_RESULT_IBASE + BC_ERR_EXEC_IBASE;
bc_verr(e, min, max);
}
BcBigDig val = bc_num_bigdig(l);
// Set the top of the stack and the actual global value.
ptr = bc_vec_top(v);
*ptr = val;
*ptr_t = val;
bc_program_assignBuiltin(p, sc, ob, val);
}
#if BC_ENABLE_EXTRA_MATH
// To assign to steed, let bc_num_rng() do its magic.
else if (left->t == BC_RESULT_SEED) bc_num_rng(l, &p->rng);
else if (left->t == BC_RESULT_SEED) bc_program_assignSeed(p, l);
#endif // BC_ENABLE_EXTRA_MATH
BC_SIG_LOCK;

5
src/vm.c

@ -537,7 +537,8 @@ bc_vm_envArgs(const char* const env_args_name)
bc_vec_push(&vm.env_args, &buf);
// Parse the arguments.
bc_args((int) vm.env_args.len - 1, bc_vec_item(&vm.env_args, 0), false);
bc_args((int) vm.env_args.len - 1, bc_vec_item(&vm.env_args, 0), false,
BC_PROG_SCALE(&vm.prog));
}
/**
@ -1535,7 +1536,7 @@ bc_vm_boot(int argc, char* argv[])
// Process environment and command-line arguments.
bc_vm_envArgs(env_args);
bc_args(argc, argv, true);
bc_args(argc, argv, true, BC_PROG_SCALE(&vm.prog));
// If we are in interactive mode...
if (BC_I)

Loading…
Cancel
Save