vendor/bc: import version 6.1.0

This is a production release that fixes a discrepancy from the bc
standard, a couple of memory bugs, and adds new features.

The discrepancy from the bc standard was with regards to the behavior
of the quit command. This bc used to quit whenever it encountered quit
during parsing, even if it was parsing a full file. Now, bc only quits
when encountering quit after it has executed all executable statements
up to that point.

This behavior is slightly different from GNU bc, but users will only
notice the difference if they put quit on the same line as other
statements.

The first memory bug could be reproduced by assigning a string to a
non-local variable in a function, then redefining the function with
use of the same non-local variable, which would still refer to a
string in the previous version of the function.

The second memory bug was caused by passing an array argument to the
asciify() built-in function. In certain cases, that was wrongly
allowed, and the interpreter just assumed everything was correct and
accessed memory. Now that arrays are allowed as arguments (see below),
this is not an issue.

The first feature was the addition of the is_number() built-in
function (u in dc) that returns 1 if the runtime argument is a number
and 0 otherwise.

The second feature was the addition of the is_string() built-in
function (t in dc) that returns 1 if the runtime argument is a string
and 0 otherwise.

These features were added because I realized that type-checking is
necessary now that strings can be assigned to variables in bc and
because they've always been assignable to variables in dc.

The last added feature is the ability of the asciify() built-in
function in bc to convert a full array of numbers into a string. This
means that character-by-character printing will not be necessary, and
more strings than just single-character ones will be able to be
created.
This commit is contained in:
Stefan Eßer 2023-01-28 20:59:18 +01:00
parent 9471e6a095
commit 0b671e8cf1
90 changed files with 4178 additions and 732 deletions

47
MEMORY_BUGS.md Normal file
View File

@ -0,0 +1,47 @@
# Memory Bugs
This is a list of all of the memory bugs that were found in *released* versions
of `bc`, `dc`, or `bcl`. (Non-released commits with memory bugs do not count.)
I made this list for two reasons: first, so users can know what versions of
`bc`, `dc`, and `bcl` have vulnerabilities, and two, I once had a perfect record
and then found a couple, but forgot and claimed I still had a perfect record
right after, which was embarrassing.
This list is sorted by the first version a bug exists in, not the last it
existed in.
* In versions `3.0.0` until `6.0.1` (inclusive) of `bc` and `dc`, there is a
double-free on `SIGINT` when using command-line expressions with `-e` and
`-f`. This was caused by not properly ending a jump series.
The first version without this bug is `6.0.2`.
* In versions `5.0.0` until `6.0.4` (inclusive) of `bc`, there is an
out-of-bounds access if a non-local (non-`auto`) variable is set to a string
with `asciify()`, then the function is redefined with a use of the same
non-local variable.
This happened because strings were stored per-function, and the non-local
variable now had a reference to the string in the old function, which could be
at a higher index than exists in the new function. Strings are stored globally
now, and they are *not* freed once not used.
The first version without this bug is `6.1.0`.
* In versions `5.0.0` until `6.0.4` (inclusive) of `bc`, there is another
out-of-bounds access if an array is passed to the `asciify()` built-in
function as the only argument. This happened because arrays are allowed as
function arguments, which allowed them to be used as arguments to `asciify()`,
but they should not have been allowed. However, since they were, the
`asciify()` code tried to access an argument that was not there.
The first version without this bug is `6.1.0`.
* In version `6.0.0` of `bcl`, there is several use of initialized data that
have the same root cause: I forgot to call `memset()` on the per-thread global
data. This is because the data used to be *actually* global, which meant that
it was initialized to zero by the system. This happened because I thought I
had properly hooked Valgrind into my `bcl` tests, but I had not.
The first version without this bug is `6.0.1`.

39
NEWS.md
View File

@ -1,5 +1,44 @@
# News
## 6.1.0
This is a production release that fixes a discrepancy from the `bc` standard,
a couple of memory bugs, and adds new features.
The discrepancy from the `bc` standard was with regards to the behavior of the
`quit` command. This `bc` used to quit whenever it encountered `quit` during
parsing, even if it was parsing a full file. Now, `bc` only quits when
encountering `quit` *after* it has executed all executable statements up to that
point.
This behavior is slightly different from GNU `bc`, but users will only notice
the difference if they put `quit` on the same line as other statements.
The first memory bug could be reproduced by assigning a string to a non-local
variable in a function, then redefining the function with use of the same
non-local variable, which would still refer to a string in the previous version
of the function.
The second memory bug was caused by passing an array argument to the `asciify()`
built-in function. In certain cases, that was wrongly allowed, and the
interpreter just assumed everything was correct and accessed memory. Now that
arrays are allowed as arguments (see below), this is not an issue.
The first feature was the addition of the `is_number()` built-in function (`u`
in `dc`) that returns 1 if the runtime argument is a number and 0 otherwise.
The second feature was the addition of the `is_string()` built-in function (`t`
in `dc`) that returns 1 if the runtime argument is a string and 0 otherwise.
These features were added because I realized that type-checking is necessary now
that strings can be assigned to variables in `bc` and because they've always
been assignable to variables in `dc`.
The last added feature is the ability of the `asciify()` built-in function in
`bc` to convert a full array of numbers into a string. This means that
character-by-character printing will not be necessary, and more strings than
just single-character ones will be able to be created.
## 6.0.4
This is a production release that most users will not need to upgrade to.

View File

@ -171,8 +171,8 @@ other locations, use the `PREFIX` environment variable when running
#### Library
This `bc` does provide a way to build a math library with C bindings. This is
done by the `-a` or `--library` options to `configure.sh`:
To build the math library, pass the `-a` or `--library` options to
`configure.sh`:
```
./configure.sh -a

3
TODO.md Normal file
View File

@ -0,0 +1,3 @@
# TODO
* Implement the more efficient factorial.

View File

@ -153,8 +153,9 @@ usage() {
printf ' quotes) This option *must* come before any others that might change the\n'
printf ' build options. Currently supported values for TYPE include: "BSD" (for\n'
printf ' matching the BSD bc and BSD dc), "GNU" (for matching the GNU bc and\n'
printf ' dc), and "GDH" (for the preferred build of the author, Gavin D. Howard).\n'
printf ' This will also automatically enable a release build.\n'
printf ' dc), "GDH" (for the preferred build of the author, Gavin D. Howard),\n'
printf ' and "DBG" (for the preferred debug build of the author). This will\n'
printf ' also automatically enable a release build (except for "DBG").\n'
printf ' -P, --disable-problematic-tests\n'
printf ' Disables problematic tests. These tests usually include tests that\n'
printf ' can cause a SIGKILL because of too much memory usage.\n'
@ -771,7 +772,7 @@ predefined_build() {
dc_default_digit_clamp=0;;
GDH)
CFLAGS="-flto -Weverything -Wno-padded -Wno-gnu-label-as-value -Werror -pedantic -std=c11"
CFLAGS="-flto -Weverything -Wno-padded -Werror -pedantic -std=c11"
bc_only=0
dc_only=0
coverage=0
@ -804,7 +805,41 @@ predefined_build() {
bc_default_digit_clamp=1
dc_default_digit_clamp=1;;
?|'') usage "Invalid user build: \"$_predefined_build_type\". Accepted types are BSD, GNU, and GDH.";;
DBG)
CFLAGS="-Weverything -Wno-padded -Werror -pedantic -std=c11"
bc_only=0
dc_only=0
coverage=0
debug=1
optimization="0"
hist=1
hist_impl="internal"
extra_math=1
generate_tests=1
install_manpages=1
nls=1
force=0
strip_bin=1
all_locales=0
library=0
fuzz=0
time_tests=0
vg=0
memcheck=1
clean=1
bc_default_banner=1
bc_default_sigint_reset=1
dc_default_sigint_reset=1
bc_default_tty_mode=1
dc_default_tty_mode=1
bc_default_prompt=""
dc_default_prompt=""
bc_default_expr_exit=0
dc_default_expr_exit=0
bc_default_digit_clamp=1
dc_default_digit_clamp=1;;
?|'') usage "Invalid user build: \"$_predefined_build_type\". Accepted types are BSD, GNU, GDH, DBG.";;
esac
}

View File

@ -97,13 +97,13 @@ typedef struct BcLexKeyword
/// A macro for the number of keywords bc has. This has to be updated if any are
/// added. This is for the redefined_kws field of the BcVm struct.
#define BC_LEX_NKWS (35)
#define BC_LEX_NKWS (37)
#else // BC_ENABLE_EXTRA_MATH
/// A macro for the number of keywords bc has. This has to be updated if any are
/// added. This is for the redefined_kws field of the BcVm struct.
#define BC_LEX_NKWS (31)
#define BC_LEX_NKWS (33)
#endif // BC_ENABLE_EXTRA_MATH

View File

@ -178,6 +178,8 @@ typedef enum BcInst
BC_INST_SCALE_FUNC,
BC_INST_SQRT,
BC_INST_ABS,
BC_INST_IS_NUMBER,
BC_INST_IS_STRING,
#if BC_ENABLE_EXTRA_MATH
/// Another builtin function.
@ -392,12 +394,6 @@ typedef struct BcFunc
#endif // BC_ENABLED
/// The strings encountered in the function.
BcVec strs;
/// The constants encountered in the function.
BcVec consts;
/// The function's name.
const char* name;
@ -660,17 +656,6 @@ bc_result_free(void* result);
void
bc_array_expand(BcVec* a, size_t len);
/**
* Compare two BcId's and return the result. Since they are just comparing the
* names in the BcId, I return the result from strcmp() exactly. This is used by
* maps in their binary search.
* @param e1 The first id.
* @param e2 The second id.
* @return The result of strcmp() on the BcId's names.
*/
int
bc_id_cmp(const BcId* e1, const BcId* e2);
#if BC_ENABLED
/**

View File

@ -317,6 +317,12 @@ typedef enum BcLexType
/// bc abs keyword.
BC_LEX_KW_ABS,
/// bc is_number keyword.
BC_LEX_KW_IS_NUMBER,
/// bc is_string keyword.
BC_LEX_KW_IS_STRING,
#if BC_ENABLE_EXTRA_MATH
/// bc irand keyword.
@ -494,14 +500,8 @@ typedef struct BcLex
/// string.
BcVec str;
/// If this is true, the lexer is processing stdin and can ask for more data
/// if a string or comment are not properly terminated.
bool is_stdin;
/// If this is true, the lexer is processing expressions from the
/// command-line and can ask for more data if a string or comment are not
/// properly terminated.
bool is_exprs;
/// The mode the lexer is in.
BcMode mode;
} BcLex;
@ -531,14 +531,12 @@ bc_lex_file(BcLex* l, const char* file);
/**
* Sets the text the lexer will lex.
* @param l The lexer.
* @param text The text to lex.
* @param is_stdin True if the text is from stdin, false otherwise.
* @param is_exprs True if the text is from command-line expressions, false
* otherwise.
* @param l The lexer.
* @param text The text to lex.
* @param mode The mode to lex in.
*/
void
bc_lex_text(BcLex* l, const char* text, bool is_stdin, bool is_exprs);
bc_lex_text(BcLex* l, const char* text, BcMode mode);
/**
* Generic next function for the parser to call. It takes care of calling the

View File

@ -80,18 +80,6 @@
*/
#define BC_PARSE_IS_INITED(p, prg) ((p)->prog == (prg))
#if BC_ENABLED
/**
* Returns true if the current parser state allows parsing, false otherwise.
* @param p The parser.
* @return True if parsing can proceed, false otherwise.
*/
#define BC_PARSE_CAN_PARSE(p) \
((p).l.t != BC_LEX_EOF && (p).l.t != BC_LEX_KW_DEFINE)
#else // BC_ENABLED
/**
* Returns true if the current parser state allows parsing, false otherwise.
* @param p The parser.
@ -99,8 +87,6 @@
*/
#define BC_PARSE_CAN_PARSE(p) ((p).l.t != BC_LEX_EOF)
#endif // BC_ENABLED
/**
* Pushes the instruction @a i onto the bytecode vector for the current
* function.
@ -268,14 +254,12 @@ bc_parse_pushName(const BcParse* p, char* name, bool var);
/**
* Sets the text that the parser will parse.
* @param p The parser.
* @param text The text to lex.
* @param is_stdin True if the text is from stdin, false otherwise.
* @param is_exprs True if the text is from command-line expressions, false
* otherwise.
* @param p The parser.
* @param text The text to lex.
* @param mode The mode to parse in.
*/
void
bc_parse_text(BcParse* p, const char* text, bool is_stdin, bool is_exprs);
bc_parse_text(BcParse* p, const char* text, BcMode mode);
// References to const 0 and 1 strings for special cases. bc and dc have
// specific instructions for 0 and 1 because they pop up so often and (in the

View File

@ -87,11 +87,21 @@ typedef struct BcProgram
/// The execution stack.
BcVec stack;
/// A pointer to the current function's constants.
BcVec* consts;
/// The constants encountered in the program. They are global to the program
/// to prevent bad accesses when functions that used non-auto variables are
/// replaced.
BcVec consts;
/// A pointer to the current function's strings.
BcVec* strs;
/// The map of constants to go with consts.
BcVec const_map;
/// The strings encountered in the program. They are global to the program
/// to prevent bad accesses when functions that used non-auto variables are
/// replaced.
BcVec strs;
/// The map of strings to go with strs.
BcVec str_map;
/// The array of functions.
BcVec fns;
@ -343,22 +353,22 @@ bc_program_printStackDebug(BcProgram* p);
/**
* Returns the index of the variable or array in their respective arrays.
* @param p The program.
* @param id The BcId of the variable or array.
* @param var True if the search should be for a variable, false for an array.
* @return The index of the variable or array in the correct array.
* @param p The program.
* @param name The name of the variable or array.
* @param var True if the search should be for a variable, false for an array.
* @return The index of the variable or array in the correct array.
*/
size_t
bc_program_search(BcProgram* p, const char* id, bool var);
bc_program_search(BcProgram* p, const char* name, bool var);
/**
* Adds a string to a function and returns the string's index in the function.
* @param p The program.
* @param str The string to add.
* @param fidx The index of the function to add to.
* Adds a string to the program and returns the string's index in the program.
* @param p The program.
* @param str The string to add.
* @return The string's index in the program.
*/
size_t
bc_program_addString(BcProgram* p, const char* str, size_t fidx);
bc_program_addString(BcProgram* p, const char* str);
/**
* Inserts a function into the program and returns the index of the function in
@ -571,6 +581,8 @@ extern const char bc_program_esc_seqs[];
&&lbl_BC_INST_SCALE_FUNC, \
&&lbl_BC_INST_SQRT, \
&&lbl_BC_INST_ABS, \
&&lbl_BC_INST_IS_NUMBER, \
&&lbl_BC_INST_IS_STRING, \
&&lbl_BC_INST_IRAND, \
&&lbl_BC_INST_ASCIIFY, \
&&lbl_BC_INST_READ, \
@ -665,6 +677,8 @@ extern const char bc_program_esc_seqs[];
&&lbl_BC_INST_SCALE_FUNC, \
&&lbl_BC_INST_SQRT, \
&&lbl_BC_INST_ABS, \
&&lbl_BC_INST_IS_NUMBER, \
&&lbl_BC_INST_IS_STRING, \
&&lbl_BC_INST_ASCIIFY, \
&&lbl_BC_INST_READ, \
&&lbl_BC_INST_MAXIBASE, \
@ -771,6 +785,8 @@ extern const char bc_program_esc_seqs[];
&&lbl_BC_INST_SCALE_FUNC, \
&&lbl_BC_INST_SQRT, \
&&lbl_BC_INST_ABS, \
&&lbl_BC_INST_IS_NUMBER, \
&&lbl_BC_INST_IS_STRING, \
&&lbl_BC_INST_IRAND, \
&&lbl_BC_INST_ASCIIFY, \
&&lbl_BC_INST_READ, \
@ -851,6 +867,8 @@ extern const char bc_program_esc_seqs[];
&&lbl_BC_INST_SCALE_FUNC, \
&&lbl_BC_INST_SQRT, \
&&lbl_BC_INST_ABS, \
&&lbl_BC_INST_IS_NUMBER, \
&&lbl_BC_INST_IS_STRING, \
&&lbl_BC_INST_ASCIIFY, \
&&lbl_BC_INST_READ, \
&&lbl_BC_INST_MAXIBASE, \
@ -923,6 +941,8 @@ extern const char bc_program_esc_seqs[];
&&lbl_BC_INST_SCALE_FUNC, \
&&lbl_BC_INST_SQRT, \
&&lbl_BC_INST_ABS, \
&&lbl_BC_INST_IS_NUMBER, \
&&lbl_BC_INST_IS_STRING, \
&&lbl_BC_INST_IRAND, \
&&lbl_BC_INST_ASCIIFY, \
&&lbl_BC_INST_READ, \
@ -992,6 +1012,8 @@ extern const char bc_program_esc_seqs[];
&&lbl_BC_INST_SCALE_FUNC, \
&&lbl_BC_INST_SQRT, \
&&lbl_BC_INST_ABS, \
&&lbl_BC_INST_IS_NUMBER, \
&&lbl_BC_INST_IS_STRING, \
&&lbl_BC_INST_ASCIIFY, \
&&lbl_BC_INST_READ, \
&&lbl_BC_INST_MAXIBASE, \

View File

@ -658,6 +658,22 @@ typedef enum BcErr
#endif // BC_ENABLED
/**
* The mode bc is in. This is basically what input it is processing.
*/
typedef enum BcMode
{
/// Expressions mode.
BC_MODE_EXPRS,
/// File mode.
BC_MODE_FILE,
/// stdin mode.
BC_MODE_STDIN,
} BcMode;
/// Do a longjmp(). This is what to use when activating an "exception", i.e., a
/// longjmp(). With debug code, it will print the name of the function it jumped
/// from.

View File

@ -59,9 +59,6 @@ typedef unsigned char uchar;
*/
typedef void (*BcVecFree)(void* ptr);
// Forward declaration.
struct BcId;
#if BC_LONG_BIT >= 64
/// An integer to shrink the size of a vector by using these instead of size_t.
@ -322,7 +319,7 @@ void
bc_vec_free(void* vec);
/**
* Attempts to insert an item into a map and returns true if it succeeded, false
* Attempts to insert an ID into a map and returns true if it succeeded, false
* if the item already exists.
* @param v The map vector to insert into.
* @param name The name of the item to insert. This name is assumed to be owned
@ -449,25 +446,6 @@ bc_slabvec_print(BcVec* v, const char* func);
/// A convenience macro for freeing a vector of slabs.
#define bc_slabvec_free bc_vec_free
#if BC_ENABLED
#if DC_ENABLED
/// Returns the set of slabs for the maps and the current calculator.
#define BC_VEC_MAP_SLABS (BC_IS_DC ? &vm->main_slabs : &vm->other_slabs)
#else // DC_ENABLED
/// Returns the set of slabs for the maps and the current calculator.
#define BC_VEC_MAP_SLABS (&vm->other_slabs)
#endif // DC_ENABLED
#else // BC_ENABLED
/// Returns the set of slabs for the maps and the current calculator.
#define BC_VEC_MAP_SLABS (&vm->main_slabs)
#endif // BC_ENABLED
#ifndef _WIN32
/**

View File

@ -37,6 +37,6 @@
#define BC_VERSION_H
/// The current version.
#define VERSION 6.0.4
#define VERSION 6.1.0
#endif // BC_VERSION_H

View File

@ -628,12 +628,8 @@ typedef struct BcVm
/// True if EOF was encountered.
bool eof;
/// True if bc is currently reading from stdin.
bool is_stdin;
/// True if bc should clear its buffers. This is BcVm to fill a hole and
/// also to avoid clobber warnings from GCC.
bool clear;
/// The mode that the program is in.
uchar mode;
#if BC_ENABLED
@ -759,16 +755,9 @@ typedef struct BcVm
/// The number of items in the input buffer.
size_t buf_len;
/// The slab for constants in the main function. This is separate for
/// garbage collection reasons.
BcVec main_const_slab;
//// The slab for all other strings for the main function.
BcVec main_slabs;
/// The slab for function names, strings in other functions, and constants
/// in other functions.
BcVec other_slabs;
/// The slabs vector for constants, strings, function names, and other
/// string-like things.
BcVec slabs;
#if BC_ENABLED
@ -846,7 +835,7 @@ bc_vm_getTemp(void);
void
bc_vm_freeTemps(void);
#if !BC_ENABLE_HISTORY || BC_ENABLE_LINE_LIB
#if !BC_ENABLE_HISTORY || BC_ENABLE_LINE_LIB || BC_ENABLE_LIBRARY
/**
* Erases the flush argument if history does not exist because it does not
@ -854,12 +843,12 @@ bc_vm_freeTemps(void);
*/
#define bc_vm_putchar(c, t) bc_vm_putchar_impl(c)
#else // !BC_ENABLE_HISTORY || BC_ENABLE_LINE_LIB
#else // !BC_ENABLE_HISTORY || BC_ENABLE_LINE_LIB || BC_ENABLE_LIBRARY
// This is here to satisfy a clang warning about recursive macros.
#define bc_vm_putchar(c, t) bc_vm_putchar_impl(c, t)
#endif // !BC_ENABLE_HISTORY || BC_ENABLE_LINE_LIB
#endif // !BC_ENABLE_HISTORY || BC_ENABLE_LINE_LIB || BC_ENABLE_LIBRARY
/**
* Print to stdout with limited formating.

View File

@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.TH "BC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
.TH "BC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH NAME
@ -711,6 +711,14 @@ This is a \f[B]non-portable extension\f[R].
\f[B]abs(E)\f[R]: The absolute value of \f[B]E\f[R].
This is a \f[B]non-portable extension\f[R].
.IP " 9." 4
\f[B]is_number(E)\f[R]: \f[B]1\f[R] if the given argument is a number,
\f[B]0\f[R] if it is a string.
This is a \f[B]non-portable extension\f[R].
.IP "10." 4
\f[B]is_string(E)\f[R]: \f[B]1\f[R] if the given argument is a string,
\f[B]0\f[R] if it is a number.
This is a \f[B]non-portable extension\f[R].
.IP "11." 4
\f[B]modexp(E, E, E)\f[R]: Modular exponentiation, where the first
expression is the base, the second is the exponent, and the third is the
modulus.
@ -718,7 +726,7 @@ All three values must be integers.
The second argument must be non-negative.
The third argument must be non-zero.
This is a \f[B]non-portable extension\f[R].
.IP "10." 4
.IP "12." 4
\f[B]divmod(E, E, I[])\f[R]: Division and modulus in one operation.
This is for optimization.
The first expression is the dividend, and the second is the divisor,
@ -726,13 +734,19 @@ which must be non-zero.
The return value is the quotient, and the modulus is stored in index
\f[B]0\f[R] of the provided array (the last argument).
This is a \f[B]non-portable extension\f[R].
.IP "11." 4
.IP "13." 4
\f[B]asciify(E)\f[R]: If \f[B]E\f[R] is a string, returns a string that
is the first letter of its argument.
If it is a number, calculates the number mod \f[B]256\f[R] and returns
that number as a one-character string.
This is a \f[B]non-portable extension\f[R].
.IP "12." 4
.IP "14." 4
\f[B]asciify(I[])\f[R]: A string that is made up of the characters that
would result from running \f[B]asciify(E)\f[R] on each element of the
array identified by the argument.
This allows creating multi-character strings and storing them.
This is a \f[B]non-portable extension\f[R].
.IP "15." 4
\f[B]I()\f[R], \f[B]I(E)\f[R], \f[B]I(E, E)\f[R], and so on, where
\f[B]I\f[R] is an identifier for a non-\f[B]void\f[R] function (see the
\f[I]Void Functions\f[R] subsection of the \f[B]FUNCTIONS\f[R] section).
@ -741,44 +755,44 @@ The \f[B]E\f[R] argument(s) may also be arrays of the form
(see the \f[I]Array References\f[R] subsection of the
\f[B]FUNCTIONS\f[R] section) if the corresponding parameter in the
function definition is an array reference.
.IP "13." 4
.IP "16." 4
\f[B]read()\f[R]: Reads a line from \f[B]stdin\f[R] and uses that as an
expression.
The result of that expression is the result of the \f[B]read()\f[R]
operand.
This is a \f[B]non-portable extension\f[R].
.IP "14." 4
.IP "17." 4
\f[B]maxibase()\f[R]: The max allowable \f[B]ibase\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "15." 4
.IP "18." 4
\f[B]maxobase()\f[R]: The max allowable \f[B]obase\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "16." 4
.IP "19." 4
\f[B]maxscale()\f[R]: The max allowable \f[B]scale\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "17." 4
.IP "20." 4
\f[B]line_length()\f[R]: The line length set with
\f[B]BC_LINE_LENGTH\f[R] (see the \f[B]ENVIRONMENT VARIABLES\f[R]
section).
This is a \f[B]non-portable extension\f[R].
.IP "18." 4
.IP "21." 4
\f[B]global_stacks()\f[R]: \f[B]0\f[R] if global stacks are not enabled
with the \f[B]-g\f[R] or \f[B]--global-stacks\f[R] options, non-zero
otherwise.
See the \f[B]OPTIONS\f[R] section.
This is a \f[B]non-portable extension\f[R].
.IP "19." 4
.IP "22." 4
\f[B]leading_zero()\f[R]: \f[B]0\f[R] if leading zeroes are not enabled
with the \f[B]-z\f[R] or \f[B]\[en]leading-zeroes\f[R] options, non-zero
otherwise.
See the \f[B]OPTIONS\f[R] section.
This is a \f[B]non-portable extension\f[R].
.IP "20." 4
.IP "23." 4
\f[B]rand()\f[R]: A pseudo-random integer between \f[B]0\f[R]
(inclusive) and \f[B]BC_RAND_MAX\f[R] (inclusive).
Using this operand will change the value of \f[B]seed\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "21." 4
.IP "24." 4
\f[B]irand(E)\f[R]: A pseudo-random integer between \f[B]0\f[R]
(inclusive) and the value of \f[B]E\f[R] (exclusive).
If \f[B]E\f[R] is negative or is a non-integer (\f[B]E\f[R]\[cq]s
@ -796,7 +810,7 @@ value of \f[B]E\f[R] is \f[B]0\f[R] or \f[B]1\f[R].
In that case, \f[B]0\f[R] is returned, and \f[B]seed\f[R] is
\f[I]not\f[R] changed.
This is a \f[B]non-portable extension\f[R].
.IP "22." 4
.IP "25." 4
\f[B]maxrand()\f[R]: The max integer returned by \f[B]rand()\f[R].
This is a \f[B]non-portable extension\f[R].
.PP
@ -1247,6 +1261,25 @@ The \f[B]if\f[R] \f[B]else\f[R] statement does the same thing as in C.
The \f[B]quit\f[R] statement causes bc(1) to quit, even if it is on a
branch that will not be executed (it is a compile-time command).
.PP
\f[B]Warning\f[R]: The behavior of this bc(1) on \f[B]quit\f[R] is
slightly different from other bc(1) implementations.
Other bc(1) implementations will exit as soon as they finish parsing the
line that a \f[B]quit\f[R] command is on.
This bc(1) will execute any completed and executable statements that
occur before the \f[B]quit\f[R] statement before exiting.
.PP
In other words, for the bc(1) code below:
.IP
.nf
\f[C]
for (i = 0; i < 3; ++i) i; quit
\f[R]
.fi
.PP
Other bc(1) implementations will print nothing, and this bc(1) will
print \f[B]0\f[R], \f[B]1\f[R], and \f[B]2\f[R] on successive lines
before exiting.
.PP
The \f[B]halt\f[R] statement causes bc(1) to quit, if it is executed.
(Unlike \f[B]quit\f[R] if it is on a branch of an \f[B]if\f[R] statement
that is not executed, bc(1) does not quit.)
@ -2926,6 +2959,12 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
The flags \f[B]-efghiqsvVw\f[R], all long options, and the extensions
noted above are extensions to that specification.
.PP
In addition, the behavior of the \f[B]quit\f[R] implements an
interpretation of that specification that is different from all known
implementations.
For more information see the \f[B]Statements\f[R] subsection of the
\f[B]SYNTAX\f[R] section.
.PP
Note that the specification explicitly says that bc(1) only accepts
numbers that use a period (\f[B].\f[R]) as a radix point, regardless of
the value of \f[B]LC_NUMERIC\f[R].
@ -2934,8 +2973,11 @@ This bc(1) supports error messages for different locales, and thus, it
supports \f[B]LC_MESSAGES\f[R].
.SH BUGS
.PP
None are known.
Report bugs at https://git.yzena.com/gavin/bc.
Before version \f[B]6.1.0\f[R], this bc(1) had incorrect behavior for
the \f[B]quit\f[R] statement.
.PP
No other bugs are known.
Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHORS
.PP
Gavin D.

View File

@ -558,46 +558,54 @@ The following are valid operands in bc(1):
7. **scale(E)**: The *scale* of **E**.
8. **abs(E)**: The absolute value of **E**. This is a **non-portable
extension**.
9. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
9. **is_number(E)**: **1** if the given argument is a number, **0** if it is a
string. This is a **non-portable extension**.
10. **is_string(E)**: **1** if the given argument is a string, **0** if it is a
number. This is a **non-portable extension**.
11. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
the base, the second is the exponent, and the third is the modulus. All
three values must be integers. The second argument must be non-negative. The
third argument must be non-zero. This is a **non-portable extension**.
10. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
11. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
optimization. The first expression is the dividend, and the second is the
divisor, which must be non-zero. The return value is the quotient, and the
modulus is stored in index **0** of the provided array (the last argument).
This is a **non-portable extension**.
11. **asciify(E)**: If **E** is a string, returns a string that is the first
12. **asciify(E)**: If **E** is a string, returns a string that is the first
letter of its argument. If it is a number, calculates the number mod **256**
and returns that number as a one-character string. This is a **non-portable
extension**.
12. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
13. **asciify(I[])**: A string that is made up of the characters that would
result from running **asciify(E)** on each element of the array identified
by the argument. This allows creating multi-character strings and storing
them. This is a **non-portable extension**.
14. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
a non-**void** function (see the *Void Functions* subsection of the
**FUNCTIONS** section). The **E** argument(s) may also be arrays of the form
**I[]**, which will automatically be turned into array references (see the
*Array References* subsection of the **FUNCTIONS** section) if the
corresponding parameter in the function definition is an array reference.
13. **read()**: Reads a line from **stdin** and uses that as an expression. The
15. **read()**: Reads a line from **stdin** and uses that as an expression. The
result of that expression is the result of the **read()** operand. This is a
**non-portable extension**.
14. **maxibase()**: The max allowable **ibase**. This is a **non-portable
16. **maxibase()**: The max allowable **ibase**. This is a **non-portable
extension**.
15. **maxobase()**: The max allowable **obase**. This is a **non-portable
17. **maxobase()**: The max allowable **obase**. This is a **non-portable
extension**.
16. **maxscale()**: The max allowable **scale**. This is a **non-portable
18. **maxscale()**: The max allowable **scale**. This is a **non-portable
extension**.
17. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
19. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
**ENVIRONMENT VARIABLES** section). This is a **non-portable extension**.
18. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
20. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
or **-\-global-stacks** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
19. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
21. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
or **--leading-zeroes** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
20. **rand()**: A pseudo-random integer between **0** (inclusive) and
22. **rand()**: A pseudo-random integer between **0** (inclusive) and
**BC_RAND_MAX** (inclusive). Using this operand will change the value of
**seed**. This is a **non-portable extension**.
21. **irand(E)**: A pseudo-random integer between **0** (inclusive) and the
23. **irand(E)**: A pseudo-random integer between **0** (inclusive) and the
value of **E** (exclusive). If **E** is negative or is a non-integer
(**E**'s *scale* is not **0**), an error is raised, and bc(1) resets (see
the **RESET** section) while **seed** remains unchanged. If **E** is larger
@ -608,7 +616,7 @@ The following are valid operands in bc(1):
change the value of **seed**, unless the value of **E** is **0** or **1**.
In that case, **0** is returned, and **seed** is *not* changed. This is a
**non-portable extension**.
22. **maxrand()**: The max integer returned by **rand()**. This is a
24. **maxrand()**: The max integer returned by **rand()**. This is a
**non-portable extension**.
The integers generated by **rand()** and **irand(E)** are guaranteed to be as
@ -976,6 +984,19 @@ The **if** **else** statement does the same thing as in C.
The **quit** statement causes bc(1) to quit, even if it is on a branch that will
not be executed (it is a compile-time command).
**Warning**: The behavior of this bc(1) on **quit** is slightly different from
other bc(1) implementations. Other bc(1) implementations will exit as soon as
they finish parsing the line that a **quit** command is on. This bc(1) will
execute any completed and executable statements that occur before the **quit**
statement before exiting.
In other words, for the bc(1) code below:
for (i = 0; i < 3; ++i) i; quit
Other bc(1) implementations will print nothing, and this bc(1) will print **0**,
**1**, and **2** on successive lines before exiting.
The **halt** statement causes bc(1) to quit, if it is executed. (Unlike **quit**
if it is on a branch of an **if** statement that is not executed, bc(1) does not
quit.)
@ -2461,6 +2482,10 @@ at https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html . The
flags **-efghiqsvVw**, all long options, and the extensions noted above are
extensions to that specification.
In addition, the behavior of the **quit** implements an interpretation of that
specification that is different from all known implementations. For more
information see the **Statements** subsection of the **SYNTAX** section.
Note that the specification explicitly says that bc(1) only accepts numbers that
use a period (**.**) as a radix point, regardless of the value of
**LC_NUMERIC**.
@ -2470,7 +2495,10 @@ This bc(1) supports error messages for different locales, and thus, it supports
# BUGS
None are known. Report bugs at https://git.yzena.com/gavin/bc.
Before version **6.1.0**, this bc(1) had incorrect behavior for the **quit**
statement.
No other bugs are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHORS

View File

@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.TH "BC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
.TH "BC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH NAME
@ -633,6 +633,14 @@ This is a \f[B]non-portable extension\f[R].
\f[B]abs(E)\f[R]: The absolute value of \f[B]E\f[R].
This is a \f[B]non-portable extension\f[R].
.IP " 9." 4
\f[B]is_number(E)\f[R]: \f[B]1\f[R] if the given argument is a number,
\f[B]0\f[R] if it is a string.
This is a \f[B]non-portable extension\f[R].
.IP "10." 4
\f[B]is_string(E)\f[R]: \f[B]1\f[R] if the given argument is a string,
\f[B]0\f[R] if it is a number.
This is a \f[B]non-portable extension\f[R].
.IP "11." 4
\f[B]modexp(E, E, E)\f[R]: Modular exponentiation, where the first
expression is the base, the second is the exponent, and the third is the
modulus.
@ -640,7 +648,7 @@ All three values must be integers.
The second argument must be non-negative.
The third argument must be non-zero.
This is a \f[B]non-portable extension\f[R].
.IP "10." 4
.IP "12." 4
\f[B]divmod(E, E, I[])\f[R]: Division and modulus in one operation.
This is for optimization.
The first expression is the dividend, and the second is the divisor,
@ -648,13 +656,19 @@ which must be non-zero.
The return value is the quotient, and the modulus is stored in index
\f[B]0\f[R] of the provided array (the last argument).
This is a \f[B]non-portable extension\f[R].
.IP "11." 4
.IP "13." 4
\f[B]asciify(E)\f[R]: If \f[B]E\f[R] is a string, returns a string that
is the first letter of its argument.
If it is a number, calculates the number mod \f[B]256\f[R] and returns
that number as a one-character string.
This is a \f[B]non-portable extension\f[R].
.IP "12." 4
.IP "14." 4
\f[B]asciify(I[])\f[R]: A string that is made up of the characters that
would result from running \f[B]asciify(E)\f[R] on each element of the
array identified by the argument.
This allows creating multi-character strings and storing them.
This is a \f[B]non-portable extension\f[R].
.IP "15." 4
\f[B]I()\f[R], \f[B]I(E)\f[R], \f[B]I(E, E)\f[R], and so on, where
\f[B]I\f[R] is an identifier for a non-\f[B]void\f[R] function (see the
\f[I]Void Functions\f[R] subsection of the \f[B]FUNCTIONS\f[R] section).
@ -663,33 +677,33 @@ The \f[B]E\f[R] argument(s) may also be arrays of the form
(see the \f[I]Array References\f[R] subsection of the
\f[B]FUNCTIONS\f[R] section) if the corresponding parameter in the
function definition is an array reference.
.IP "13." 4
.IP "16." 4
\f[B]read()\f[R]: Reads a line from \f[B]stdin\f[R] and uses that as an
expression.
The result of that expression is the result of the \f[B]read()\f[R]
operand.
This is a \f[B]non-portable extension\f[R].
.IP "14." 4
.IP "17." 4
\f[B]maxibase()\f[R]: The max allowable \f[B]ibase\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "15." 4
.IP "18." 4
\f[B]maxobase()\f[R]: The max allowable \f[B]obase\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "16." 4
.IP "19." 4
\f[B]maxscale()\f[R]: The max allowable \f[B]scale\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "17." 4
.IP "20." 4
\f[B]line_length()\f[R]: The line length set with
\f[B]BC_LINE_LENGTH\f[R] (see the \f[B]ENVIRONMENT VARIABLES\f[R]
section).
This is a \f[B]non-portable extension\f[R].
.IP "18." 4
.IP "21." 4
\f[B]global_stacks()\f[R]: \f[B]0\f[R] if global stacks are not enabled
with the \f[B]-g\f[R] or \f[B]--global-stacks\f[R] options, non-zero
otherwise.
See the \f[B]OPTIONS\f[R] section.
This is a \f[B]non-portable extension\f[R].
.IP "19." 4
.IP "22." 4
\f[B]leading_zero()\f[R]: \f[B]0\f[R] if leading zeroes are not enabled
with the \f[B]-z\f[R] or \f[B]\[en]leading-zeroes\f[R] options, non-zero
otherwise.
@ -1026,6 +1040,25 @@ The \f[B]if\f[R] \f[B]else\f[R] statement does the same thing as in C.
The \f[B]quit\f[R] statement causes bc(1) to quit, even if it is on a
branch that will not be executed (it is a compile-time command).
.PP
\f[B]Warning\f[R]: The behavior of this bc(1) on \f[B]quit\f[R] is
slightly different from other bc(1) implementations.
Other bc(1) implementations will exit as soon as they finish parsing the
line that a \f[B]quit\f[R] command is on.
This bc(1) will execute any completed and executable statements that
occur before the \f[B]quit\f[R] statement before exiting.
.PP
In other words, for the bc(1) code below:
.IP
.nf
\f[C]
for (i = 0; i < 3; ++i) i; quit
\f[R]
.fi
.PP
Other bc(1) implementations will print nothing, and this bc(1) will
print \f[B]0\f[R], \f[B]1\f[R], and \f[B]2\f[R] on successive lines
before exiting.
.PP
The \f[B]halt\f[R] statement causes bc(1) to quit, if it is executed.
(Unlike \f[B]quit\f[R] if it is on a branch of an \f[B]if\f[R] statement
that is not executed, bc(1) does not quit.)
@ -1759,6 +1792,12 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
The flags \f[B]-efghiqsvVw\f[R], all long options, and the extensions
noted above are extensions to that specification.
.PP
In addition, the behavior of the \f[B]quit\f[R] implements an
interpretation of that specification that is different from all known
implementations.
For more information see the \f[B]Statements\f[R] subsection of the
\f[B]SYNTAX\f[R] section.
.PP
Note that the specification explicitly says that bc(1) only accepts
numbers that use a period (\f[B].\f[R]) as a radix point, regardless of
the value of \f[B]LC_NUMERIC\f[R].
@ -1767,8 +1806,11 @@ This bc(1) supports error messages for different locales, and thus, it
supports \f[B]LC_MESSAGES\f[R].
.SH BUGS
.PP
None are known.
Report bugs at https://git.yzena.com/gavin/bc.
Before version \f[B]6.1.0\f[R], this bc(1) had incorrect behavior for
the \f[B]quit\f[R] statement.
.PP
No other bugs are known.
Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHORS
.PP
Gavin D.

View File

@ -504,40 +504,48 @@ The following are valid operands in bc(1):
7. **scale(E)**: The *scale* of **E**.
8. **abs(E)**: The absolute value of **E**. This is a **non-portable
extension**.
9. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
9. **is_number(E)**: **1** if the given argument is a number, **0** if it is a
string. This is a **non-portable extension**.
10. **is_string(E)**: **1** if the given argument is a string, **0** if it is a
number. This is a **non-portable extension**.
11. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
the base, the second is the exponent, and the third is the modulus. All
three values must be integers. The second argument must be non-negative. The
third argument must be non-zero. This is a **non-portable extension**.
10. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
11. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
optimization. The first expression is the dividend, and the second is the
divisor, which must be non-zero. The return value is the quotient, and the
modulus is stored in index **0** of the provided array (the last argument).
This is a **non-portable extension**.
11. **asciify(E)**: If **E** is a string, returns a string that is the first
12. **asciify(E)**: If **E** is a string, returns a string that is the first
letter of its argument. If it is a number, calculates the number mod **256**
and returns that number as a one-character string. This is a **non-portable
extension**.
12. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
13. **asciify(I[])**: A string that is made up of the characters that would
result from running **asciify(E)** on each element of the array identified
by the argument. This allows creating multi-character strings and storing
them. This is a **non-portable extension**.
14. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
a non-**void** function (see the *Void Functions* subsection of the
**FUNCTIONS** section). The **E** argument(s) may also be arrays of the form
**I[]**, which will automatically be turned into array references (see the
*Array References* subsection of the **FUNCTIONS** section) if the
corresponding parameter in the function definition is an array reference.
13. **read()**: Reads a line from **stdin** and uses that as an expression. The
15. **read()**: Reads a line from **stdin** and uses that as an expression. The
result of that expression is the result of the **read()** operand. This is a
**non-portable extension**.
14. **maxibase()**: The max allowable **ibase**. This is a **non-portable
16. **maxibase()**: The max allowable **ibase**. This is a **non-portable
extension**.
15. **maxobase()**: The max allowable **obase**. This is a **non-portable
17. **maxobase()**: The max allowable **obase**. This is a **non-portable
extension**.
16. **maxscale()**: The max allowable **scale**. This is a **non-portable
18. **maxscale()**: The max allowable **scale**. This is a **non-portable
extension**.
17. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
19. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
**ENVIRONMENT VARIABLES** section). This is a **non-portable extension**.
18. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
20. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
or **-\-global-stacks** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
19. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
21. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
or **--leading-zeroes** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
@ -811,6 +819,19 @@ The **if** **else** statement does the same thing as in C.
The **quit** statement causes bc(1) to quit, even if it is on a branch that will
not be executed (it is a compile-time command).
**Warning**: The behavior of this bc(1) on **quit** is slightly different from
other bc(1) implementations. Other bc(1) implementations will exit as soon as
they finish parsing the line that a **quit** command is on. This bc(1) will
execute any completed and executable statements that occur before the **quit**
statement before exiting.
In other words, for the bc(1) code below:
for (i = 0; i < 3; ++i) i; quit
Other bc(1) implementations will print nothing, and this bc(1) will print **0**,
**1**, and **2** on successive lines before exiting.
The **halt** statement causes bc(1) to quit, if it is executed. (Unlike **quit**
if it is on a branch of an **if** statement that is not executed, bc(1) does not
quit.)
@ -1469,6 +1490,10 @@ at https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html . The
flags **-efghiqsvVw**, all long options, and the extensions noted above are
extensions to that specification.
In addition, the behavior of the **quit** implements an interpretation of that
specification that is different from all known implementations. For more
information see the **Statements** subsection of the **SYNTAX** section.
Note that the specification explicitly says that bc(1) only accepts numbers that
use a period (**.**) as a radix point, regardless of the value of
**LC_NUMERIC**.
@ -1478,7 +1503,10 @@ This bc(1) supports error messages for different locales, and thus, it supports
# BUGS
None are known. Report bugs at https://git.yzena.com/gavin/bc.
Before version **6.1.0**, this bc(1) had incorrect behavior for the **quit**
statement.
No other bugs are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHORS

View File

@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.TH "BC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
.TH "BC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH NAME
@ -633,6 +633,14 @@ This is a \f[B]non-portable extension\f[R].
\f[B]abs(E)\f[R]: The absolute value of \f[B]E\f[R].
This is a \f[B]non-portable extension\f[R].
.IP " 9." 4
\f[B]is_number(E)\f[R]: \f[B]1\f[R] if the given argument is a number,
\f[B]0\f[R] if it is a string.
This is a \f[B]non-portable extension\f[R].
.IP "10." 4
\f[B]is_string(E)\f[R]: \f[B]1\f[R] if the given argument is a string,
\f[B]0\f[R] if it is a number.
This is a \f[B]non-portable extension\f[R].
.IP "11." 4
\f[B]modexp(E, E, E)\f[R]: Modular exponentiation, where the first
expression is the base, the second is the exponent, and the third is the
modulus.
@ -640,7 +648,7 @@ All three values must be integers.
The second argument must be non-negative.
The third argument must be non-zero.
This is a \f[B]non-portable extension\f[R].
.IP "10." 4
.IP "12." 4
\f[B]divmod(E, E, I[])\f[R]: Division and modulus in one operation.
This is for optimization.
The first expression is the dividend, and the second is the divisor,
@ -648,13 +656,19 @@ which must be non-zero.
The return value is the quotient, and the modulus is stored in index
\f[B]0\f[R] of the provided array (the last argument).
This is a \f[B]non-portable extension\f[R].
.IP "11." 4
.IP "13." 4
\f[B]asciify(E)\f[R]: If \f[B]E\f[R] is a string, returns a string that
is the first letter of its argument.
If it is a number, calculates the number mod \f[B]256\f[R] and returns
that number as a one-character string.
This is a \f[B]non-portable extension\f[R].
.IP "12." 4
.IP "14." 4
\f[B]asciify(I[])\f[R]: A string that is made up of the characters that
would result from running \f[B]asciify(E)\f[R] on each element of the
array identified by the argument.
This allows creating multi-character strings and storing them.
This is a \f[B]non-portable extension\f[R].
.IP "15." 4
\f[B]I()\f[R], \f[B]I(E)\f[R], \f[B]I(E, E)\f[R], and so on, where
\f[B]I\f[R] is an identifier for a non-\f[B]void\f[R] function (see the
\f[I]Void Functions\f[R] subsection of the \f[B]FUNCTIONS\f[R] section).
@ -663,33 +677,33 @@ The \f[B]E\f[R] argument(s) may also be arrays of the form
(see the \f[I]Array References\f[R] subsection of the
\f[B]FUNCTIONS\f[R] section) if the corresponding parameter in the
function definition is an array reference.
.IP "13." 4
.IP "16." 4
\f[B]read()\f[R]: Reads a line from \f[B]stdin\f[R] and uses that as an
expression.
The result of that expression is the result of the \f[B]read()\f[R]
operand.
This is a \f[B]non-portable extension\f[R].
.IP "14." 4
.IP "17." 4
\f[B]maxibase()\f[R]: The max allowable \f[B]ibase\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "15." 4
.IP "18." 4
\f[B]maxobase()\f[R]: The max allowable \f[B]obase\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "16." 4
.IP "19." 4
\f[B]maxscale()\f[R]: The max allowable \f[B]scale\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "17." 4
.IP "20." 4
\f[B]line_length()\f[R]: The line length set with
\f[B]BC_LINE_LENGTH\f[R] (see the \f[B]ENVIRONMENT VARIABLES\f[R]
section).
This is a \f[B]non-portable extension\f[R].
.IP "18." 4
.IP "21." 4
\f[B]global_stacks()\f[R]: \f[B]0\f[R] if global stacks are not enabled
with the \f[B]-g\f[R] or \f[B]--global-stacks\f[R] options, non-zero
otherwise.
See the \f[B]OPTIONS\f[R] section.
This is a \f[B]non-portable extension\f[R].
.IP "19." 4
.IP "22." 4
\f[B]leading_zero()\f[R]: \f[B]0\f[R] if leading zeroes are not enabled
with the \f[B]-z\f[R] or \f[B]\[en]leading-zeroes\f[R] options, non-zero
otherwise.
@ -1026,6 +1040,25 @@ The \f[B]if\f[R] \f[B]else\f[R] statement does the same thing as in C.
The \f[B]quit\f[R] statement causes bc(1) to quit, even if it is on a
branch that will not be executed (it is a compile-time command).
.PP
\f[B]Warning\f[R]: The behavior of this bc(1) on \f[B]quit\f[R] is
slightly different from other bc(1) implementations.
Other bc(1) implementations will exit as soon as they finish parsing the
line that a \f[B]quit\f[R] command is on.
This bc(1) will execute any completed and executable statements that
occur before the \f[B]quit\f[R] statement before exiting.
.PP
In other words, for the bc(1) code below:
.IP
.nf
\f[C]
for (i = 0; i < 3; ++i) i; quit
\f[R]
.fi
.PP
Other bc(1) implementations will print nothing, and this bc(1) will
print \f[B]0\f[R], \f[B]1\f[R], and \f[B]2\f[R] on successive lines
before exiting.
.PP
The \f[B]halt\f[R] statement causes bc(1) to quit, if it is executed.
(Unlike \f[B]quit\f[R] if it is on a branch of an \f[B]if\f[R] statement
that is not executed, bc(1) does not quit.)
@ -1730,6 +1763,12 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
The flags \f[B]-efghiqsvVw\f[R], all long options, and the extensions
noted above are extensions to that specification.
.PP
In addition, the behavior of the \f[B]quit\f[R] implements an
interpretation of that specification that is different from all known
implementations.
For more information see the \f[B]Statements\f[R] subsection of the
\f[B]SYNTAX\f[R] section.
.PP
Note that the specification explicitly says that bc(1) only accepts
numbers that use a period (\f[B].\f[R]) as a radix point, regardless of
the value of \f[B]LC_NUMERIC\f[R].
@ -1738,8 +1777,11 @@ This bc(1) supports error messages for different locales, and thus, it
supports \f[B]LC_MESSAGES\f[R].
.SH BUGS
.PP
None are known.
Report bugs at https://git.yzena.com/gavin/bc.
Before version \f[B]6.1.0\f[R], this bc(1) had incorrect behavior for
the \f[B]quit\f[R] statement.
.PP
No other bugs are known.
Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHORS
.PP
Gavin D.

View File

@ -504,40 +504,48 @@ The following are valid operands in bc(1):
7. **scale(E)**: The *scale* of **E**.
8. **abs(E)**: The absolute value of **E**. This is a **non-portable
extension**.
9. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
9. **is_number(E)**: **1** if the given argument is a number, **0** if it is a
string. This is a **non-portable extension**.
10. **is_string(E)**: **1** if the given argument is a string, **0** if it is a
number. This is a **non-portable extension**.
11. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
the base, the second is the exponent, and the third is the modulus. All
three values must be integers. The second argument must be non-negative. The
third argument must be non-zero. This is a **non-portable extension**.
10. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
11. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
optimization. The first expression is the dividend, and the second is the
divisor, which must be non-zero. The return value is the quotient, and the
modulus is stored in index **0** of the provided array (the last argument).
This is a **non-portable extension**.
11. **asciify(E)**: If **E** is a string, returns a string that is the first
12. **asciify(E)**: If **E** is a string, returns a string that is the first
letter of its argument. If it is a number, calculates the number mod **256**
and returns that number as a one-character string. This is a **non-portable
extension**.
12. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
13. **asciify(I[])**: A string that is made up of the characters that would
result from running **asciify(E)** on each element of the array identified
by the argument. This allows creating multi-character strings and storing
them. This is a **non-portable extension**.
14. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
a non-**void** function (see the *Void Functions* subsection of the
**FUNCTIONS** section). The **E** argument(s) may also be arrays of the form
**I[]**, which will automatically be turned into array references (see the
*Array References* subsection of the **FUNCTIONS** section) if the
corresponding parameter in the function definition is an array reference.
13. **read()**: Reads a line from **stdin** and uses that as an expression. The
15. **read()**: Reads a line from **stdin** and uses that as an expression. The
result of that expression is the result of the **read()** operand. This is a
**non-portable extension**.
14. **maxibase()**: The max allowable **ibase**. This is a **non-portable
16. **maxibase()**: The max allowable **ibase**. This is a **non-portable
extension**.
15. **maxobase()**: The max allowable **obase**. This is a **non-portable
17. **maxobase()**: The max allowable **obase**. This is a **non-portable
extension**.
16. **maxscale()**: The max allowable **scale**. This is a **non-portable
18. **maxscale()**: The max allowable **scale**. This is a **non-portable
extension**.
17. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
19. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
**ENVIRONMENT VARIABLES** section). This is a **non-portable extension**.
18. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
20. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
or **-\-global-stacks** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
19. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
21. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
or **--leading-zeroes** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
@ -811,6 +819,19 @@ The **if** **else** statement does the same thing as in C.
The **quit** statement causes bc(1) to quit, even if it is on a branch that will
not be executed (it is a compile-time command).
**Warning**: The behavior of this bc(1) on **quit** is slightly different from
other bc(1) implementations. Other bc(1) implementations will exit as soon as
they finish parsing the line that a **quit** command is on. This bc(1) will
execute any completed and executable statements that occur before the **quit**
statement before exiting.
In other words, for the bc(1) code below:
for (i = 0; i < 3; ++i) i; quit
Other bc(1) implementations will print nothing, and this bc(1) will print **0**,
**1**, and **2** on successive lines before exiting.
The **halt** statement causes bc(1) to quit, if it is executed. (Unlike **quit**
if it is on a branch of an **if** statement that is not executed, bc(1) does not
quit.)
@ -1443,6 +1464,10 @@ at https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html . The
flags **-efghiqsvVw**, all long options, and the extensions noted above are
extensions to that specification.
In addition, the behavior of the **quit** implements an interpretation of that
specification that is different from all known implementations. For more
information see the **Statements** subsection of the **SYNTAX** section.
Note that the specification explicitly says that bc(1) only accepts numbers that
use a period (**.**) as a radix point, regardless of the value of
**LC_NUMERIC**.
@ -1452,7 +1477,10 @@ This bc(1) supports error messages for different locales, and thus, it supports
# BUGS
None are known. Report bugs at https://git.yzena.com/gavin/bc.
Before version **6.1.0**, this bc(1) had incorrect behavior for the **quit**
statement.
No other bugs are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHORS

View File

@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.TH "BC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
.TH "BC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH NAME
@ -633,6 +633,14 @@ This is a \f[B]non-portable extension\f[R].
\f[B]abs(E)\f[R]: The absolute value of \f[B]E\f[R].
This is a \f[B]non-portable extension\f[R].
.IP " 9." 4
\f[B]is_number(E)\f[R]: \f[B]1\f[R] if the given argument is a number,
\f[B]0\f[R] if it is a string.
This is a \f[B]non-portable extension\f[R].
.IP "10." 4
\f[B]is_string(E)\f[R]: \f[B]1\f[R] if the given argument is a string,
\f[B]0\f[R] if it is a number.
This is a \f[B]non-portable extension\f[R].
.IP "11." 4
\f[B]modexp(E, E, E)\f[R]: Modular exponentiation, where the first
expression is the base, the second is the exponent, and the third is the
modulus.
@ -640,7 +648,7 @@ All three values must be integers.
The second argument must be non-negative.
The third argument must be non-zero.
This is a \f[B]non-portable extension\f[R].
.IP "10." 4
.IP "12." 4
\f[B]divmod(E, E, I[])\f[R]: Division and modulus in one operation.
This is for optimization.
The first expression is the dividend, and the second is the divisor,
@ -648,13 +656,19 @@ which must be non-zero.
The return value is the quotient, and the modulus is stored in index
\f[B]0\f[R] of the provided array (the last argument).
This is a \f[B]non-portable extension\f[R].
.IP "11." 4
.IP "13." 4
\f[B]asciify(E)\f[R]: If \f[B]E\f[R] is a string, returns a string that
is the first letter of its argument.
If it is a number, calculates the number mod \f[B]256\f[R] and returns
that number as a one-character string.
This is a \f[B]non-portable extension\f[R].
.IP "12." 4
.IP "14." 4
\f[B]asciify(I[])\f[R]: A string that is made up of the characters that
would result from running \f[B]asciify(E)\f[R] on each element of the
array identified by the argument.
This allows creating multi-character strings and storing them.
This is a \f[B]non-portable extension\f[R].
.IP "15." 4
\f[B]I()\f[R], \f[B]I(E)\f[R], \f[B]I(E, E)\f[R], and so on, where
\f[B]I\f[R] is an identifier for a non-\f[B]void\f[R] function (see the
\f[I]Void Functions\f[R] subsection of the \f[B]FUNCTIONS\f[R] section).
@ -663,33 +677,33 @@ The \f[B]E\f[R] argument(s) may also be arrays of the form
(see the \f[I]Array References\f[R] subsection of the
\f[B]FUNCTIONS\f[R] section) if the corresponding parameter in the
function definition is an array reference.
.IP "13." 4
.IP "16." 4
\f[B]read()\f[R]: Reads a line from \f[B]stdin\f[R] and uses that as an
expression.
The result of that expression is the result of the \f[B]read()\f[R]
operand.
This is a \f[B]non-portable extension\f[R].
.IP "14." 4
.IP "17." 4
\f[B]maxibase()\f[R]: The max allowable \f[B]ibase\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "15." 4
.IP "18." 4
\f[B]maxobase()\f[R]: The max allowable \f[B]obase\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "16." 4
.IP "19." 4
\f[B]maxscale()\f[R]: The max allowable \f[B]scale\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "17." 4
.IP "20." 4
\f[B]line_length()\f[R]: The line length set with
\f[B]BC_LINE_LENGTH\f[R] (see the \f[B]ENVIRONMENT VARIABLES\f[R]
section).
This is a \f[B]non-portable extension\f[R].
.IP "18." 4
.IP "21." 4
\f[B]global_stacks()\f[R]: \f[B]0\f[R] if global stacks are not enabled
with the \f[B]-g\f[R] or \f[B]--global-stacks\f[R] options, non-zero
otherwise.
See the \f[B]OPTIONS\f[R] section.
This is a \f[B]non-portable extension\f[R].
.IP "19." 4
.IP "22." 4
\f[B]leading_zero()\f[R]: \f[B]0\f[R] if leading zeroes are not enabled
with the \f[B]-z\f[R] or \f[B]\[en]leading-zeroes\f[R] options, non-zero
otherwise.
@ -1026,6 +1040,25 @@ The \f[B]if\f[R] \f[B]else\f[R] statement does the same thing as in C.
The \f[B]quit\f[R] statement causes bc(1) to quit, even if it is on a
branch that will not be executed (it is a compile-time command).
.PP
\f[B]Warning\f[R]: The behavior of this bc(1) on \f[B]quit\f[R] is
slightly different from other bc(1) implementations.
Other bc(1) implementations will exit as soon as they finish parsing the
line that a \f[B]quit\f[R] command is on.
This bc(1) will execute any completed and executable statements that
occur before the \f[B]quit\f[R] statement before exiting.
.PP
In other words, for the bc(1) code below:
.IP
.nf
\f[C]
for (i = 0; i < 3; ++i) i; quit
\f[R]
.fi
.PP
Other bc(1) implementations will print nothing, and this bc(1) will
print \f[B]0\f[R], \f[B]1\f[R], and \f[B]2\f[R] on successive lines
before exiting.
.PP
The \f[B]halt\f[R] statement causes bc(1) to quit, if it is executed.
(Unlike \f[B]quit\f[R] if it is on a branch of an \f[B]if\f[R] statement
that is not executed, bc(1) does not quit.)
@ -1726,13 +1759,22 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
The flags \f[B]-efghiqsvVw\f[R], all long options, and the extensions
noted above are extensions to that specification.
.PP
In addition, the behavior of the \f[B]quit\f[R] implements an
interpretation of that specification that is different from all known
implementations.
For more information see the \f[B]Statements\f[R] subsection of the
\f[B]SYNTAX\f[R] section.
.PP
Note that the specification explicitly says that bc(1) only accepts
numbers that use a period (\f[B].\f[R]) as a radix point, regardless of
the value of \f[B]LC_NUMERIC\f[R].
.SH BUGS
.PP
None are known.
Report bugs at https://git.yzena.com/gavin/bc.
Before version \f[B]6.1.0\f[R], this bc(1) had incorrect behavior for
the \f[B]quit\f[R] statement.
.PP
No other bugs are known.
Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHORS
.PP
Gavin D.

View File

@ -504,40 +504,48 @@ The following are valid operands in bc(1):
7. **scale(E)**: The *scale* of **E**.
8. **abs(E)**: The absolute value of **E**. This is a **non-portable
extension**.
9. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
9. **is_number(E)**: **1** if the given argument is a number, **0** if it is a
string. This is a **non-portable extension**.
10. **is_string(E)**: **1** if the given argument is a string, **0** if it is a
number. This is a **non-portable extension**.
11. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
the base, the second is the exponent, and the third is the modulus. All
three values must be integers. The second argument must be non-negative. The
third argument must be non-zero. This is a **non-portable extension**.
10. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
11. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
optimization. The first expression is the dividend, and the second is the
divisor, which must be non-zero. The return value is the quotient, and the
modulus is stored in index **0** of the provided array (the last argument).
This is a **non-portable extension**.
11. **asciify(E)**: If **E** is a string, returns a string that is the first
12. **asciify(E)**: If **E** is a string, returns a string that is the first
letter of its argument. If it is a number, calculates the number mod **256**
and returns that number as a one-character string. This is a **non-portable
extension**.
12. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
13. **asciify(I[])**: A string that is made up of the characters that would
result from running **asciify(E)** on each element of the array identified
by the argument. This allows creating multi-character strings and storing
them. This is a **non-portable extension**.
14. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
a non-**void** function (see the *Void Functions* subsection of the
**FUNCTIONS** section). The **E** argument(s) may also be arrays of the form
**I[]**, which will automatically be turned into array references (see the
*Array References* subsection of the **FUNCTIONS** section) if the
corresponding parameter in the function definition is an array reference.
13. **read()**: Reads a line from **stdin** and uses that as an expression. The
15. **read()**: Reads a line from **stdin** and uses that as an expression. The
result of that expression is the result of the **read()** operand. This is a
**non-portable extension**.
14. **maxibase()**: The max allowable **ibase**. This is a **non-portable
16. **maxibase()**: The max allowable **ibase**. This is a **non-portable
extension**.
15. **maxobase()**: The max allowable **obase**. This is a **non-portable
17. **maxobase()**: The max allowable **obase**. This is a **non-portable
extension**.
16. **maxscale()**: The max allowable **scale**. This is a **non-portable
18. **maxscale()**: The max allowable **scale**. This is a **non-portable
extension**.
17. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
19. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
**ENVIRONMENT VARIABLES** section). This is a **non-portable extension**.
18. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
20. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
or **-\-global-stacks** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
19. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
21. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
or **--leading-zeroes** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
@ -811,6 +819,19 @@ The **if** **else** statement does the same thing as in C.
The **quit** statement causes bc(1) to quit, even if it is on a branch that will
not be executed (it is a compile-time command).
**Warning**: The behavior of this bc(1) on **quit** is slightly different from
other bc(1) implementations. Other bc(1) implementations will exit as soon as
they finish parsing the line that a **quit** command is on. This bc(1) will
execute any completed and executable statements that occur before the **quit**
statement before exiting.
In other words, for the bc(1) code below:
for (i = 0; i < 3; ++i) i; quit
Other bc(1) implementations will print nothing, and this bc(1) will print **0**,
**1**, and **2** on successive lines before exiting.
The **halt** statement causes bc(1) to quit, if it is executed. (Unlike **quit**
if it is on a branch of an **if** statement that is not executed, bc(1) does not
quit.)
@ -1438,13 +1459,20 @@ at https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html . The
flags **-efghiqsvVw**, all long options, and the extensions noted above are
extensions to that specification.
In addition, the behavior of the **quit** implements an interpretation of that
specification that is different from all known implementations. For more
information see the **Statements** subsection of the **SYNTAX** section.
Note that the specification explicitly says that bc(1) only accepts numbers that
use a period (**.**) as a radix point, regardless of the value of
**LC_NUMERIC**.
# BUGS
None are known. Report bugs at https://git.yzena.com/gavin/bc.
Before version **6.1.0**, this bc(1) had incorrect behavior for the **quit**
statement.
No other bugs are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHORS

View File

@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.TH "BC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
.TH "BC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH NAME
@ -633,6 +633,14 @@ This is a \f[B]non-portable extension\f[R].
\f[B]abs(E)\f[R]: The absolute value of \f[B]E\f[R].
This is a \f[B]non-portable extension\f[R].
.IP " 9." 4
\f[B]is_number(E)\f[R]: \f[B]1\f[R] if the given argument is a number,
\f[B]0\f[R] if it is a string.
This is a \f[B]non-portable extension\f[R].
.IP "10." 4
\f[B]is_string(E)\f[R]: \f[B]1\f[R] if the given argument is a string,
\f[B]0\f[R] if it is a number.
This is a \f[B]non-portable extension\f[R].
.IP "11." 4
\f[B]modexp(E, E, E)\f[R]: Modular exponentiation, where the first
expression is the base, the second is the exponent, and the third is the
modulus.
@ -640,7 +648,7 @@ All three values must be integers.
The second argument must be non-negative.
The third argument must be non-zero.
This is a \f[B]non-portable extension\f[R].
.IP "10." 4
.IP "12." 4
\f[B]divmod(E, E, I[])\f[R]: Division and modulus in one operation.
This is for optimization.
The first expression is the dividend, and the second is the divisor,
@ -648,13 +656,19 @@ which must be non-zero.
The return value is the quotient, and the modulus is stored in index
\f[B]0\f[R] of the provided array (the last argument).
This is a \f[B]non-portable extension\f[R].
.IP "11." 4
.IP "13." 4
\f[B]asciify(E)\f[R]: If \f[B]E\f[R] is a string, returns a string that
is the first letter of its argument.
If it is a number, calculates the number mod \f[B]256\f[R] and returns
that number as a one-character string.
This is a \f[B]non-portable extension\f[R].
.IP "12." 4
.IP "14." 4
\f[B]asciify(I[])\f[R]: A string that is made up of the characters that
would result from running \f[B]asciify(E)\f[R] on each element of the
array identified by the argument.
This allows creating multi-character strings and storing them.
This is a \f[B]non-portable extension\f[R].
.IP "15." 4
\f[B]I()\f[R], \f[B]I(E)\f[R], \f[B]I(E, E)\f[R], and so on, where
\f[B]I\f[R] is an identifier for a non-\f[B]void\f[R] function (see the
\f[I]Void Functions\f[R] subsection of the \f[B]FUNCTIONS\f[R] section).
@ -663,33 +677,33 @@ The \f[B]E\f[R] argument(s) may also be arrays of the form
(see the \f[I]Array References\f[R] subsection of the
\f[B]FUNCTIONS\f[R] section) if the corresponding parameter in the
function definition is an array reference.
.IP "13." 4
.IP "16." 4
\f[B]read()\f[R]: Reads a line from \f[B]stdin\f[R] and uses that as an
expression.
The result of that expression is the result of the \f[B]read()\f[R]
operand.
This is a \f[B]non-portable extension\f[R].
.IP "14." 4
.IP "17." 4
\f[B]maxibase()\f[R]: The max allowable \f[B]ibase\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "15." 4
.IP "18." 4
\f[B]maxobase()\f[R]: The max allowable \f[B]obase\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "16." 4
.IP "19." 4
\f[B]maxscale()\f[R]: The max allowable \f[B]scale\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "17." 4
.IP "20." 4
\f[B]line_length()\f[R]: The line length set with
\f[B]BC_LINE_LENGTH\f[R] (see the \f[B]ENVIRONMENT VARIABLES\f[R]
section).
This is a \f[B]non-portable extension\f[R].
.IP "18." 4
.IP "21." 4
\f[B]global_stacks()\f[R]: \f[B]0\f[R] if global stacks are not enabled
with the \f[B]-g\f[R] or \f[B]--global-stacks\f[R] options, non-zero
otherwise.
See the \f[B]OPTIONS\f[R] section.
This is a \f[B]non-portable extension\f[R].
.IP "19." 4
.IP "22." 4
\f[B]leading_zero()\f[R]: \f[B]0\f[R] if leading zeroes are not enabled
with the \f[B]-z\f[R] or \f[B]\[en]leading-zeroes\f[R] options, non-zero
otherwise.
@ -1026,6 +1040,25 @@ The \f[B]if\f[R] \f[B]else\f[R] statement does the same thing as in C.
The \f[B]quit\f[R] statement causes bc(1) to quit, even if it is on a
branch that will not be executed (it is a compile-time command).
.PP
\f[B]Warning\f[R]: The behavior of this bc(1) on \f[B]quit\f[R] is
slightly different from other bc(1) implementations.
Other bc(1) implementations will exit as soon as they finish parsing the
line that a \f[B]quit\f[R] command is on.
This bc(1) will execute any completed and executable statements that
occur before the \f[B]quit\f[R] statement before exiting.
.PP
In other words, for the bc(1) code below:
.IP
.nf
\f[C]
for (i = 0; i < 3; ++i) i; quit
\f[R]
.fi
.PP
Other bc(1) implementations will print nothing, and this bc(1) will
print \f[B]0\f[R], \f[B]1\f[R], and \f[B]2\f[R] on successive lines
before exiting.
.PP
The \f[B]halt\f[R] statement causes bc(1) to quit, if it is executed.
(Unlike \f[B]quit\f[R] if it is on a branch of an \f[B]if\f[R] statement
that is not executed, bc(1) does not quit.)
@ -1755,13 +1788,22 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
The flags \f[B]-efghiqsvVw\f[R], all long options, and the extensions
noted above are extensions to that specification.
.PP
In addition, the behavior of the \f[B]quit\f[R] implements an
interpretation of that specification that is different from all known
implementations.
For more information see the \f[B]Statements\f[R] subsection of the
\f[B]SYNTAX\f[R] section.
.PP
Note that the specification explicitly says that bc(1) only accepts
numbers that use a period (\f[B].\f[R]) as a radix point, regardless of
the value of \f[B]LC_NUMERIC\f[R].
.SH BUGS
.PP
None are known.
Report bugs at https://git.yzena.com/gavin/bc.
Before version \f[B]6.1.0\f[R], this bc(1) had incorrect behavior for
the \f[B]quit\f[R] statement.
.PP
No other bugs are known.
Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHORS
.PP
Gavin D.

View File

@ -504,40 +504,48 @@ The following are valid operands in bc(1):
7. **scale(E)**: The *scale* of **E**.
8. **abs(E)**: The absolute value of **E**. This is a **non-portable
extension**.
9. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
9. **is_number(E)**: **1** if the given argument is a number, **0** if it is a
string. This is a **non-portable extension**.
10. **is_string(E)**: **1** if the given argument is a string, **0** if it is a
number. This is a **non-portable extension**.
11. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
the base, the second is the exponent, and the third is the modulus. All
three values must be integers. The second argument must be non-negative. The
third argument must be non-zero. This is a **non-portable extension**.
10. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
11. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
optimization. The first expression is the dividend, and the second is the
divisor, which must be non-zero. The return value is the quotient, and the
modulus is stored in index **0** of the provided array (the last argument).
This is a **non-portable extension**.
11. **asciify(E)**: If **E** is a string, returns a string that is the first
12. **asciify(E)**: If **E** is a string, returns a string that is the first
letter of its argument. If it is a number, calculates the number mod **256**
and returns that number as a one-character string. This is a **non-portable
extension**.
12. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
13. **asciify(I[])**: A string that is made up of the characters that would
result from running **asciify(E)** on each element of the array identified
by the argument. This allows creating multi-character strings and storing
them. This is a **non-portable extension**.
14. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
a non-**void** function (see the *Void Functions* subsection of the
**FUNCTIONS** section). The **E** argument(s) may also be arrays of the form
**I[]**, which will automatically be turned into array references (see the
*Array References* subsection of the **FUNCTIONS** section) if the
corresponding parameter in the function definition is an array reference.
13. **read()**: Reads a line from **stdin** and uses that as an expression. The
15. **read()**: Reads a line from **stdin** and uses that as an expression. The
result of that expression is the result of the **read()** operand. This is a
**non-portable extension**.
14. **maxibase()**: The max allowable **ibase**. This is a **non-portable
16. **maxibase()**: The max allowable **ibase**. This is a **non-portable
extension**.
15. **maxobase()**: The max allowable **obase**. This is a **non-portable
17. **maxobase()**: The max allowable **obase**. This is a **non-portable
extension**.
16. **maxscale()**: The max allowable **scale**. This is a **non-portable
18. **maxscale()**: The max allowable **scale**. This is a **non-portable
extension**.
17. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
19. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
**ENVIRONMENT VARIABLES** section). This is a **non-portable extension**.
18. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
20. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
or **-\-global-stacks** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
19. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
21. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
or **--leading-zeroes** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
@ -811,6 +819,19 @@ The **if** **else** statement does the same thing as in C.
The **quit** statement causes bc(1) to quit, even if it is on a branch that will
not be executed (it is a compile-time command).
**Warning**: The behavior of this bc(1) on **quit** is slightly different from
other bc(1) implementations. Other bc(1) implementations will exit as soon as
they finish parsing the line that a **quit** command is on. This bc(1) will
execute any completed and executable statements that occur before the **quit**
statement before exiting.
In other words, for the bc(1) code below:
for (i = 0; i < 3; ++i) i; quit
Other bc(1) implementations will print nothing, and this bc(1) will print **0**,
**1**, and **2** on successive lines before exiting.
The **halt** statement causes bc(1) to quit, if it is executed. (Unlike **quit**
if it is on a branch of an **if** statement that is not executed, bc(1) does not
quit.)
@ -1464,13 +1485,20 @@ at https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html . The
flags **-efghiqsvVw**, all long options, and the extensions noted above are
extensions to that specification.
In addition, the behavior of the **quit** implements an interpretation of that
specification that is different from all known implementations. For more
information see the **Statements** subsection of the **SYNTAX** section.
Note that the specification explicitly says that bc(1) only accepts numbers that
use a period (**.**) as a radix point, regardless of the value of
**LC_NUMERIC**.
# BUGS
None are known. Report bugs at https://git.yzena.com/gavin/bc.
Before version **6.1.0**, this bc(1) had incorrect behavior for the **quit**
statement.
No other bugs are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHORS

View File

@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.TH "BC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
.TH "BC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH NAME
@ -711,6 +711,14 @@ This is a \f[B]non-portable extension\f[R].
\f[B]abs(E)\f[R]: The absolute value of \f[B]E\f[R].
This is a \f[B]non-portable extension\f[R].
.IP " 9." 4
\f[B]is_number(E)\f[R]: \f[B]1\f[R] if the given argument is a number,
\f[B]0\f[R] if it is a string.
This is a \f[B]non-portable extension\f[R].
.IP "10." 4
\f[B]is_string(E)\f[R]: \f[B]1\f[R] if the given argument is a string,
\f[B]0\f[R] if it is a number.
This is a \f[B]non-portable extension\f[R].
.IP "11." 4
\f[B]modexp(E, E, E)\f[R]: Modular exponentiation, where the first
expression is the base, the second is the exponent, and the third is the
modulus.
@ -718,7 +726,7 @@ All three values must be integers.
The second argument must be non-negative.
The third argument must be non-zero.
This is a \f[B]non-portable extension\f[R].
.IP "10." 4
.IP "12." 4
\f[B]divmod(E, E, I[])\f[R]: Division and modulus in one operation.
This is for optimization.
The first expression is the dividend, and the second is the divisor,
@ -726,13 +734,19 @@ which must be non-zero.
The return value is the quotient, and the modulus is stored in index
\f[B]0\f[R] of the provided array (the last argument).
This is a \f[B]non-portable extension\f[R].
.IP "11." 4
.IP "13." 4
\f[B]asciify(E)\f[R]: If \f[B]E\f[R] is a string, returns a string that
is the first letter of its argument.
If it is a number, calculates the number mod \f[B]256\f[R] and returns
that number as a one-character string.
This is a \f[B]non-portable extension\f[R].
.IP "12." 4
.IP "14." 4
\f[B]asciify(I[])\f[R]: A string that is made up of the characters that
would result from running \f[B]asciify(E)\f[R] on each element of the
array identified by the argument.
This allows creating multi-character strings and storing them.
This is a \f[B]non-portable extension\f[R].
.IP "15." 4
\f[B]I()\f[R], \f[B]I(E)\f[R], \f[B]I(E, E)\f[R], and so on, where
\f[B]I\f[R] is an identifier for a non-\f[B]void\f[R] function (see the
\f[I]Void Functions\f[R] subsection of the \f[B]FUNCTIONS\f[R] section).
@ -741,44 +755,44 @@ The \f[B]E\f[R] argument(s) may also be arrays of the form
(see the \f[I]Array References\f[R] subsection of the
\f[B]FUNCTIONS\f[R] section) if the corresponding parameter in the
function definition is an array reference.
.IP "13." 4
.IP "16." 4
\f[B]read()\f[R]: Reads a line from \f[B]stdin\f[R] and uses that as an
expression.
The result of that expression is the result of the \f[B]read()\f[R]
operand.
This is a \f[B]non-portable extension\f[R].
.IP "14." 4
.IP "17." 4
\f[B]maxibase()\f[R]: The max allowable \f[B]ibase\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "15." 4
.IP "18." 4
\f[B]maxobase()\f[R]: The max allowable \f[B]obase\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "16." 4
.IP "19." 4
\f[B]maxscale()\f[R]: The max allowable \f[B]scale\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "17." 4
.IP "20." 4
\f[B]line_length()\f[R]: The line length set with
\f[B]BC_LINE_LENGTH\f[R] (see the \f[B]ENVIRONMENT VARIABLES\f[R]
section).
This is a \f[B]non-portable extension\f[R].
.IP "18." 4
.IP "21." 4
\f[B]global_stacks()\f[R]: \f[B]0\f[R] if global stacks are not enabled
with the \f[B]-g\f[R] or \f[B]--global-stacks\f[R] options, non-zero
otherwise.
See the \f[B]OPTIONS\f[R] section.
This is a \f[B]non-portable extension\f[R].
.IP "19." 4
.IP "22." 4
\f[B]leading_zero()\f[R]: \f[B]0\f[R] if leading zeroes are not enabled
with the \f[B]-z\f[R] or \f[B]\[en]leading-zeroes\f[R] options, non-zero
otherwise.
See the \f[B]OPTIONS\f[R] section.
This is a \f[B]non-portable extension\f[R].
.IP "20." 4
.IP "23." 4
\f[B]rand()\f[R]: A pseudo-random integer between \f[B]0\f[R]
(inclusive) and \f[B]BC_RAND_MAX\f[R] (inclusive).
Using this operand will change the value of \f[B]seed\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "21." 4
.IP "24." 4
\f[B]irand(E)\f[R]: A pseudo-random integer between \f[B]0\f[R]
(inclusive) and the value of \f[B]E\f[R] (exclusive).
If \f[B]E\f[R] is negative or is a non-integer (\f[B]E\f[R]\[cq]s
@ -796,7 +810,7 @@ value of \f[B]E\f[R] is \f[B]0\f[R] or \f[B]1\f[R].
In that case, \f[B]0\f[R] is returned, and \f[B]seed\f[R] is
\f[I]not\f[R] changed.
This is a \f[B]non-portable extension\f[R].
.IP "22." 4
.IP "25." 4
\f[B]maxrand()\f[R]: The max integer returned by \f[B]rand()\f[R].
This is a \f[B]non-portable extension\f[R].
.PP
@ -1247,6 +1261,25 @@ The \f[B]if\f[R] \f[B]else\f[R] statement does the same thing as in C.
The \f[B]quit\f[R] statement causes bc(1) to quit, even if it is on a
branch that will not be executed (it is a compile-time command).
.PP
\f[B]Warning\f[R]: The behavior of this bc(1) on \f[B]quit\f[R] is
slightly different from other bc(1) implementations.
Other bc(1) implementations will exit as soon as they finish parsing the
line that a \f[B]quit\f[R] command is on.
This bc(1) will execute any completed and executable statements that
occur before the \f[B]quit\f[R] statement before exiting.
.PP
In other words, for the bc(1) code below:
.IP
.nf
\f[C]
for (i = 0; i < 3; ++i) i; quit
\f[R]
.fi
.PP
Other bc(1) implementations will print nothing, and this bc(1) will
print \f[B]0\f[R], \f[B]1\f[R], and \f[B]2\f[R] on successive lines
before exiting.
.PP
The \f[B]halt\f[R] statement causes bc(1) to quit, if it is executed.
(Unlike \f[B]quit\f[R] if it is on a branch of an \f[B]if\f[R] statement
that is not executed, bc(1) does not quit.)
@ -2897,6 +2930,12 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
The flags \f[B]-efghiqsvVw\f[R], all long options, and the extensions
noted above are extensions to that specification.
.PP
In addition, the behavior of the \f[B]quit\f[R] implements an
interpretation of that specification that is different from all known
implementations.
For more information see the \f[B]Statements\f[R] subsection of the
\f[B]SYNTAX\f[R] section.
.PP
Note that the specification explicitly says that bc(1) only accepts
numbers that use a period (\f[B].\f[R]) as a radix point, regardless of
the value of \f[B]LC_NUMERIC\f[R].
@ -2905,8 +2944,11 @@ This bc(1) supports error messages for different locales, and thus, it
supports \f[B]LC_MESSAGES\f[R].
.SH BUGS
.PP
None are known.
Report bugs at https://git.yzena.com/gavin/bc.
Before version \f[B]6.1.0\f[R], this bc(1) had incorrect behavior for
the \f[B]quit\f[R] statement.
.PP
No other bugs are known.
Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHORS
.PP
Gavin D.

View File

@ -558,46 +558,54 @@ The following are valid operands in bc(1):
7. **scale(E)**: The *scale* of **E**.
8. **abs(E)**: The absolute value of **E**. This is a **non-portable
extension**.
9. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
9. **is_number(E)**: **1** if the given argument is a number, **0** if it is a
string. This is a **non-portable extension**.
10. **is_string(E)**: **1** if the given argument is a string, **0** if it is a
number. This is a **non-portable extension**.
11. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
the base, the second is the exponent, and the third is the modulus. All
three values must be integers. The second argument must be non-negative. The
third argument must be non-zero. This is a **non-portable extension**.
10. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
11. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
optimization. The first expression is the dividend, and the second is the
divisor, which must be non-zero. The return value is the quotient, and the
modulus is stored in index **0** of the provided array (the last argument).
This is a **non-portable extension**.
11. **asciify(E)**: If **E** is a string, returns a string that is the first
12. **asciify(E)**: If **E** is a string, returns a string that is the first
letter of its argument. If it is a number, calculates the number mod **256**
and returns that number as a one-character string. This is a **non-portable
extension**.
12. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
13. **asciify(I[])**: A string that is made up of the characters that would
result from running **asciify(E)** on each element of the array identified
by the argument. This allows creating multi-character strings and storing
them. This is a **non-portable extension**.
14. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
a non-**void** function (see the *Void Functions* subsection of the
**FUNCTIONS** section). The **E** argument(s) may also be arrays of the form
**I[]**, which will automatically be turned into array references (see the
*Array References* subsection of the **FUNCTIONS** section) if the
corresponding parameter in the function definition is an array reference.
13. **read()**: Reads a line from **stdin** and uses that as an expression. The
15. **read()**: Reads a line from **stdin** and uses that as an expression. The
result of that expression is the result of the **read()** operand. This is a
**non-portable extension**.
14. **maxibase()**: The max allowable **ibase**. This is a **non-portable
16. **maxibase()**: The max allowable **ibase**. This is a **non-portable
extension**.
15. **maxobase()**: The max allowable **obase**. This is a **non-portable
17. **maxobase()**: The max allowable **obase**. This is a **non-portable
extension**.
16. **maxscale()**: The max allowable **scale**. This is a **non-portable
18. **maxscale()**: The max allowable **scale**. This is a **non-portable
extension**.
17. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
19. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
**ENVIRONMENT VARIABLES** section). This is a **non-portable extension**.
18. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
20. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
or **-\-global-stacks** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
19. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
21. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
or **--leading-zeroes** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
20. **rand()**: A pseudo-random integer between **0** (inclusive) and
22. **rand()**: A pseudo-random integer between **0** (inclusive) and
**BC_RAND_MAX** (inclusive). Using this operand will change the value of
**seed**. This is a **non-portable extension**.
21. **irand(E)**: A pseudo-random integer between **0** (inclusive) and the
23. **irand(E)**: A pseudo-random integer between **0** (inclusive) and the
value of **E** (exclusive). If **E** is negative or is a non-integer
(**E**'s *scale* is not **0**), an error is raised, and bc(1) resets (see
the **RESET** section) while **seed** remains unchanged. If **E** is larger
@ -608,7 +616,7 @@ The following are valid operands in bc(1):
change the value of **seed**, unless the value of **E** is **0** or **1**.
In that case, **0** is returned, and **seed** is *not* changed. This is a
**non-portable extension**.
22. **maxrand()**: The max integer returned by **rand()**. This is a
24. **maxrand()**: The max integer returned by **rand()**. This is a
**non-portable extension**.
The integers generated by **rand()** and **irand(E)** are guaranteed to be as
@ -976,6 +984,19 @@ The **if** **else** statement does the same thing as in C.
The **quit** statement causes bc(1) to quit, even if it is on a branch that will
not be executed (it is a compile-time command).
**Warning**: The behavior of this bc(1) on **quit** is slightly different from
other bc(1) implementations. Other bc(1) implementations will exit as soon as
they finish parsing the line that a **quit** command is on. This bc(1) will
execute any completed and executable statements that occur before the **quit**
statement before exiting.
In other words, for the bc(1) code below:
for (i = 0; i < 3; ++i) i; quit
Other bc(1) implementations will print nothing, and this bc(1) will print **0**,
**1**, and **2** on successive lines before exiting.
The **halt** statement causes bc(1) to quit, if it is executed. (Unlike **quit**
if it is on a branch of an **if** statement that is not executed, bc(1) does not
quit.)
@ -2435,6 +2456,10 @@ at https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html . The
flags **-efghiqsvVw**, all long options, and the extensions noted above are
extensions to that specification.
In addition, the behavior of the **quit** implements an interpretation of that
specification that is different from all known implementations. For more
information see the **Statements** subsection of the **SYNTAX** section.
Note that the specification explicitly says that bc(1) only accepts numbers that
use a period (**.**) as a radix point, regardless of the value of
**LC_NUMERIC**.
@ -2444,7 +2469,10 @@ This bc(1) supports error messages for different locales, and thus, it supports
# BUGS
None are known. Report bugs at https://git.yzena.com/gavin/bc.
Before version **6.1.0**, this bc(1) had incorrect behavior for the **quit**
statement.
No other bugs are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHORS

View File

@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.TH "BC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
.TH "BC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH NAME
@ -711,6 +711,14 @@ This is a \f[B]non-portable extension\f[R].
\f[B]abs(E)\f[R]: The absolute value of \f[B]E\f[R].
This is a \f[B]non-portable extension\f[R].
.IP " 9." 4
\f[B]is_number(E)\f[R]: \f[B]1\f[R] if the given argument is a number,
\f[B]0\f[R] if it is a string.
This is a \f[B]non-portable extension\f[R].
.IP "10." 4
\f[B]is_string(E)\f[R]: \f[B]1\f[R] if the given argument is a string,
\f[B]0\f[R] if it is a number.
This is a \f[B]non-portable extension\f[R].
.IP "11." 4
\f[B]modexp(E, E, E)\f[R]: Modular exponentiation, where the first
expression is the base, the second is the exponent, and the third is the
modulus.
@ -718,7 +726,7 @@ All three values must be integers.
The second argument must be non-negative.
The third argument must be non-zero.
This is a \f[B]non-portable extension\f[R].
.IP "10." 4
.IP "12." 4
\f[B]divmod(E, E, I[])\f[R]: Division and modulus in one operation.
This is for optimization.
The first expression is the dividend, and the second is the divisor,
@ -726,13 +734,19 @@ which must be non-zero.
The return value is the quotient, and the modulus is stored in index
\f[B]0\f[R] of the provided array (the last argument).
This is a \f[B]non-portable extension\f[R].
.IP "11." 4
.IP "13." 4
\f[B]asciify(E)\f[R]: If \f[B]E\f[R] is a string, returns a string that
is the first letter of its argument.
If it is a number, calculates the number mod \f[B]256\f[R] and returns
that number as a one-character string.
This is a \f[B]non-portable extension\f[R].
.IP "12." 4
.IP "14." 4
\f[B]asciify(I[])\f[R]: A string that is made up of the characters that
would result from running \f[B]asciify(E)\f[R] on each element of the
array identified by the argument.
This allows creating multi-character strings and storing them.
This is a \f[B]non-portable extension\f[R].
.IP "15." 4
\f[B]I()\f[R], \f[B]I(E)\f[R], \f[B]I(E, E)\f[R], and so on, where
\f[B]I\f[R] is an identifier for a non-\f[B]void\f[R] function (see the
\f[I]Void Functions\f[R] subsection of the \f[B]FUNCTIONS\f[R] section).
@ -741,44 +755,44 @@ The \f[B]E\f[R] argument(s) may also be arrays of the form
(see the \f[I]Array References\f[R] subsection of the
\f[B]FUNCTIONS\f[R] section) if the corresponding parameter in the
function definition is an array reference.
.IP "13." 4
.IP "16." 4
\f[B]read()\f[R]: Reads a line from \f[B]stdin\f[R] and uses that as an
expression.
The result of that expression is the result of the \f[B]read()\f[R]
operand.
This is a \f[B]non-portable extension\f[R].
.IP "14." 4
.IP "17." 4
\f[B]maxibase()\f[R]: The max allowable \f[B]ibase\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "15." 4
.IP "18." 4
\f[B]maxobase()\f[R]: The max allowable \f[B]obase\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "16." 4
.IP "19." 4
\f[B]maxscale()\f[R]: The max allowable \f[B]scale\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "17." 4
.IP "20." 4
\f[B]line_length()\f[R]: The line length set with
\f[B]BC_LINE_LENGTH\f[R] (see the \f[B]ENVIRONMENT VARIABLES\f[R]
section).
This is a \f[B]non-portable extension\f[R].
.IP "18." 4
.IP "21." 4
\f[B]global_stacks()\f[R]: \f[B]0\f[R] if global stacks are not enabled
with the \f[B]-g\f[R] or \f[B]--global-stacks\f[R] options, non-zero
otherwise.
See the \f[B]OPTIONS\f[R] section.
This is a \f[B]non-portable extension\f[R].
.IP "19." 4
.IP "22." 4
\f[B]leading_zero()\f[R]: \f[B]0\f[R] if leading zeroes are not enabled
with the \f[B]-z\f[R] or \f[B]\[en]leading-zeroes\f[R] options, non-zero
otherwise.
See the \f[B]OPTIONS\f[R] section.
This is a \f[B]non-portable extension\f[R].
.IP "20." 4
.IP "23." 4
\f[B]rand()\f[R]: A pseudo-random integer between \f[B]0\f[R]
(inclusive) and \f[B]BC_RAND_MAX\f[R] (inclusive).
Using this operand will change the value of \f[B]seed\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "21." 4
.IP "24." 4
\f[B]irand(E)\f[R]: A pseudo-random integer between \f[B]0\f[R]
(inclusive) and the value of \f[B]E\f[R] (exclusive).
If \f[B]E\f[R] is negative or is a non-integer (\f[B]E\f[R]\[cq]s
@ -796,7 +810,7 @@ value of \f[B]E\f[R] is \f[B]0\f[R] or \f[B]1\f[R].
In that case, \f[B]0\f[R] is returned, and \f[B]seed\f[R] is
\f[I]not\f[R] changed.
This is a \f[B]non-portable extension\f[R].
.IP "22." 4
.IP "25." 4
\f[B]maxrand()\f[R]: The max integer returned by \f[B]rand()\f[R].
This is a \f[B]non-portable extension\f[R].
.PP
@ -1247,6 +1261,25 @@ The \f[B]if\f[R] \f[B]else\f[R] statement does the same thing as in C.
The \f[B]quit\f[R] statement causes bc(1) to quit, even if it is on a
branch that will not be executed (it is a compile-time command).
.PP
\f[B]Warning\f[R]: The behavior of this bc(1) on \f[B]quit\f[R] is
slightly different from other bc(1) implementations.
Other bc(1) implementations will exit as soon as they finish parsing the
line that a \f[B]quit\f[R] command is on.
This bc(1) will execute any completed and executable statements that
occur before the \f[B]quit\f[R] statement before exiting.
.PP
In other words, for the bc(1) code below:
.IP
.nf
\f[C]
for (i = 0; i < 3; ++i) i; quit
\f[R]
.fi
.PP
Other bc(1) implementations will print nothing, and this bc(1) will
print \f[B]0\f[R], \f[B]1\f[R], and \f[B]2\f[R] on successive lines
before exiting.
.PP
The \f[B]halt\f[R] statement causes bc(1) to quit, if it is executed.
(Unlike \f[B]quit\f[R] if it is on a branch of an \f[B]if\f[R] statement
that is not executed, bc(1) does not quit.)
@ -2893,13 +2926,22 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
The flags \f[B]-efghiqsvVw\f[R], all long options, and the extensions
noted above are extensions to that specification.
.PP
In addition, the behavior of the \f[B]quit\f[R] implements an
interpretation of that specification that is different from all known
implementations.
For more information see the \f[B]Statements\f[R] subsection of the
\f[B]SYNTAX\f[R] section.
.PP
Note that the specification explicitly says that bc(1) only accepts
numbers that use a period (\f[B].\f[R]) as a radix point, regardless of
the value of \f[B]LC_NUMERIC\f[R].
.SH BUGS
.PP
None are known.
Report bugs at https://git.yzena.com/gavin/bc.
Before version \f[B]6.1.0\f[R], this bc(1) had incorrect behavior for
the \f[B]quit\f[R] statement.
.PP
No other bugs are known.
Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHORS
.PP
Gavin D.

View File

@ -558,46 +558,54 @@ The following are valid operands in bc(1):
7. **scale(E)**: The *scale* of **E**.
8. **abs(E)**: The absolute value of **E**. This is a **non-portable
extension**.
9. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
9. **is_number(E)**: **1** if the given argument is a number, **0** if it is a
string. This is a **non-portable extension**.
10. **is_string(E)**: **1** if the given argument is a string, **0** if it is a
number. This is a **non-portable extension**.
11. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
the base, the second is the exponent, and the third is the modulus. All
three values must be integers. The second argument must be non-negative. The
third argument must be non-zero. This is a **non-portable extension**.
10. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
11. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
optimization. The first expression is the dividend, and the second is the
divisor, which must be non-zero. The return value is the quotient, and the
modulus is stored in index **0** of the provided array (the last argument).
This is a **non-portable extension**.
11. **asciify(E)**: If **E** is a string, returns a string that is the first
12. **asciify(E)**: If **E** is a string, returns a string that is the first
letter of its argument. If it is a number, calculates the number mod **256**
and returns that number as a one-character string. This is a **non-portable
extension**.
12. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
13. **asciify(I[])**: A string that is made up of the characters that would
result from running **asciify(E)** on each element of the array identified
by the argument. This allows creating multi-character strings and storing
them. This is a **non-portable extension**.
14. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
a non-**void** function (see the *Void Functions* subsection of the
**FUNCTIONS** section). The **E** argument(s) may also be arrays of the form
**I[]**, which will automatically be turned into array references (see the
*Array References* subsection of the **FUNCTIONS** section) if the
corresponding parameter in the function definition is an array reference.
13. **read()**: Reads a line from **stdin** and uses that as an expression. The
15. **read()**: Reads a line from **stdin** and uses that as an expression. The
result of that expression is the result of the **read()** operand. This is a
**non-portable extension**.
14. **maxibase()**: The max allowable **ibase**. This is a **non-portable
16. **maxibase()**: The max allowable **ibase**. This is a **non-portable
extension**.
15. **maxobase()**: The max allowable **obase**. This is a **non-portable
17. **maxobase()**: The max allowable **obase**. This is a **non-portable
extension**.
16. **maxscale()**: The max allowable **scale**. This is a **non-portable
18. **maxscale()**: The max allowable **scale**. This is a **non-portable
extension**.
17. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
19. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
**ENVIRONMENT VARIABLES** section). This is a **non-portable extension**.
18. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
20. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
or **-\-global-stacks** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
19. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
21. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
or **--leading-zeroes** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
20. **rand()**: A pseudo-random integer between **0** (inclusive) and
22. **rand()**: A pseudo-random integer between **0** (inclusive) and
**BC_RAND_MAX** (inclusive). Using this operand will change the value of
**seed**. This is a **non-portable extension**.
21. **irand(E)**: A pseudo-random integer between **0** (inclusive) and the
23. **irand(E)**: A pseudo-random integer between **0** (inclusive) and the
value of **E** (exclusive). If **E** is negative or is a non-integer
(**E**'s *scale* is not **0**), an error is raised, and bc(1) resets (see
the **RESET** section) while **seed** remains unchanged. If **E** is larger
@ -608,7 +616,7 @@ The following are valid operands in bc(1):
change the value of **seed**, unless the value of **E** is **0** or **1**.
In that case, **0** is returned, and **seed** is *not* changed. This is a
**non-portable extension**.
22. **maxrand()**: The max integer returned by **rand()**. This is a
24. **maxrand()**: The max integer returned by **rand()**. This is a
**non-portable extension**.
The integers generated by **rand()** and **irand(E)** are guaranteed to be as
@ -976,6 +984,19 @@ The **if** **else** statement does the same thing as in C.
The **quit** statement causes bc(1) to quit, even if it is on a branch that will
not be executed (it is a compile-time command).
**Warning**: The behavior of this bc(1) on **quit** is slightly different from
other bc(1) implementations. Other bc(1) implementations will exit as soon as
they finish parsing the line that a **quit** command is on. This bc(1) will
execute any completed and executable statements that occur before the **quit**
statement before exiting.
In other words, for the bc(1) code below:
for (i = 0; i < 3; ++i) i; quit
Other bc(1) implementations will print nothing, and this bc(1) will print **0**,
**1**, and **2** on successive lines before exiting.
The **halt** statement causes bc(1) to quit, if it is executed. (Unlike **quit**
if it is on a branch of an **if** statement that is not executed, bc(1) does not
quit.)
@ -2430,13 +2451,20 @@ at https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html . The
flags **-efghiqsvVw**, all long options, and the extensions noted above are
extensions to that specification.
In addition, the behavior of the **quit** implements an interpretation of that
specification that is different from all known implementations. For more
information see the **Statements** subsection of the **SYNTAX** section.
Note that the specification explicitly says that bc(1) only accepts numbers that
use a period (**.**) as a radix point, regardless of the value of
**LC_NUMERIC**.
# BUGS
None are known. Report bugs at https://git.yzena.com/gavin/bc.
Before version **6.1.0**, this bc(1) had incorrect behavior for the **quit**
statement.
No other bugs are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHORS

View File

@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.TH "BC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
.TH "BC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH NAME
@ -711,6 +711,14 @@ This is a \f[B]non-portable extension\f[R].
\f[B]abs(E)\f[R]: The absolute value of \f[B]E\f[R].
This is a \f[B]non-portable extension\f[R].
.IP " 9." 4
\f[B]is_number(E)\f[R]: \f[B]1\f[R] if the given argument is a number,
\f[B]0\f[R] if it is a string.
This is a \f[B]non-portable extension\f[R].
.IP "10." 4
\f[B]is_string(E)\f[R]: \f[B]1\f[R] if the given argument is a string,
\f[B]0\f[R] if it is a number.
This is a \f[B]non-portable extension\f[R].
.IP "11." 4
\f[B]modexp(E, E, E)\f[R]: Modular exponentiation, where the first
expression is the base, the second is the exponent, and the third is the
modulus.
@ -718,7 +726,7 @@ All three values must be integers.
The second argument must be non-negative.
The third argument must be non-zero.
This is a \f[B]non-portable extension\f[R].
.IP "10." 4
.IP "12." 4
\f[B]divmod(E, E, I[])\f[R]: Division and modulus in one operation.
This is for optimization.
The first expression is the dividend, and the second is the divisor,
@ -726,13 +734,19 @@ which must be non-zero.
The return value is the quotient, and the modulus is stored in index
\f[B]0\f[R] of the provided array (the last argument).
This is a \f[B]non-portable extension\f[R].
.IP "11." 4
.IP "13." 4
\f[B]asciify(E)\f[R]: If \f[B]E\f[R] is a string, returns a string that
is the first letter of its argument.
If it is a number, calculates the number mod \f[B]256\f[R] and returns
that number as a one-character string.
This is a \f[B]non-portable extension\f[R].
.IP "12." 4
.IP "14." 4
\f[B]asciify(I[])\f[R]: A string that is made up of the characters that
would result from running \f[B]asciify(E)\f[R] on each element of the
array identified by the argument.
This allows creating multi-character strings and storing them.
This is a \f[B]non-portable extension\f[R].
.IP "15." 4
\f[B]I()\f[R], \f[B]I(E)\f[R], \f[B]I(E, E)\f[R], and so on, where
\f[B]I\f[R] is an identifier for a non-\f[B]void\f[R] function (see the
\f[I]Void Functions\f[R] subsection of the \f[B]FUNCTIONS\f[R] section).
@ -741,44 +755,44 @@ The \f[B]E\f[R] argument(s) may also be arrays of the form
(see the \f[I]Array References\f[R] subsection of the
\f[B]FUNCTIONS\f[R] section) if the corresponding parameter in the
function definition is an array reference.
.IP "13." 4
.IP "16." 4
\f[B]read()\f[R]: Reads a line from \f[B]stdin\f[R] and uses that as an
expression.
The result of that expression is the result of the \f[B]read()\f[R]
operand.
This is a \f[B]non-portable extension\f[R].
.IP "14." 4
.IP "17." 4
\f[B]maxibase()\f[R]: The max allowable \f[B]ibase\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "15." 4
.IP "18." 4
\f[B]maxobase()\f[R]: The max allowable \f[B]obase\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "16." 4
.IP "19." 4
\f[B]maxscale()\f[R]: The max allowable \f[B]scale\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "17." 4
.IP "20." 4
\f[B]line_length()\f[R]: The line length set with
\f[B]BC_LINE_LENGTH\f[R] (see the \f[B]ENVIRONMENT VARIABLES\f[R]
section).
This is a \f[B]non-portable extension\f[R].
.IP "18." 4
.IP "21." 4
\f[B]global_stacks()\f[R]: \f[B]0\f[R] if global stacks are not enabled
with the \f[B]-g\f[R] or \f[B]--global-stacks\f[R] options, non-zero
otherwise.
See the \f[B]OPTIONS\f[R] section.
This is a \f[B]non-portable extension\f[R].
.IP "19." 4
.IP "22." 4
\f[B]leading_zero()\f[R]: \f[B]0\f[R] if leading zeroes are not enabled
with the \f[B]-z\f[R] or \f[B]\[en]leading-zeroes\f[R] options, non-zero
otherwise.
See the \f[B]OPTIONS\f[R] section.
This is a \f[B]non-portable extension\f[R].
.IP "20." 4
.IP "23." 4
\f[B]rand()\f[R]: A pseudo-random integer between \f[B]0\f[R]
(inclusive) and \f[B]BC_RAND_MAX\f[R] (inclusive).
Using this operand will change the value of \f[B]seed\f[R].
This is a \f[B]non-portable extension\f[R].
.IP "21." 4
.IP "24." 4
\f[B]irand(E)\f[R]: A pseudo-random integer between \f[B]0\f[R]
(inclusive) and the value of \f[B]E\f[R] (exclusive).
If \f[B]E\f[R] is negative or is a non-integer (\f[B]E\f[R]\[cq]s
@ -796,7 +810,7 @@ value of \f[B]E\f[R] is \f[B]0\f[R] or \f[B]1\f[R].
In that case, \f[B]0\f[R] is returned, and \f[B]seed\f[R] is
\f[I]not\f[R] changed.
This is a \f[B]non-portable extension\f[R].
.IP "22." 4
.IP "25." 4
\f[B]maxrand()\f[R]: The max integer returned by \f[B]rand()\f[R].
This is a \f[B]non-portable extension\f[R].
.PP
@ -1247,6 +1261,25 @@ The \f[B]if\f[R] \f[B]else\f[R] statement does the same thing as in C.
The \f[B]quit\f[R] statement causes bc(1) to quit, even if it is on a
branch that will not be executed (it is a compile-time command).
.PP
\f[B]Warning\f[R]: The behavior of this bc(1) on \f[B]quit\f[R] is
slightly different from other bc(1) implementations.
Other bc(1) implementations will exit as soon as they finish parsing the
line that a \f[B]quit\f[R] command is on.
This bc(1) will execute any completed and executable statements that
occur before the \f[B]quit\f[R] statement before exiting.
.PP
In other words, for the bc(1) code below:
.IP
.nf
\f[C]
for (i = 0; i < 3; ++i) i; quit
\f[R]
.fi
.PP
Other bc(1) implementations will print nothing, and this bc(1) will
print \f[B]0\f[R], \f[B]1\f[R], and \f[B]2\f[R] on successive lines
before exiting.
.PP
The \f[B]halt\f[R] statement causes bc(1) to quit, if it is executed.
(Unlike \f[B]quit\f[R] if it is on a branch of an \f[B]if\f[R] statement
that is not executed, bc(1) does not quit.)
@ -2922,13 +2955,22 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
The flags \f[B]-efghiqsvVw\f[R], all long options, and the extensions
noted above are extensions to that specification.
.PP
In addition, the behavior of the \f[B]quit\f[R] implements an
interpretation of that specification that is different from all known
implementations.
For more information see the \f[B]Statements\f[R] subsection of the
\f[B]SYNTAX\f[R] section.
.PP
Note that the specification explicitly says that bc(1) only accepts
numbers that use a period (\f[B].\f[R]) as a radix point, regardless of
the value of \f[B]LC_NUMERIC\f[R].
.SH BUGS
.PP
None are known.
Report bugs at https://git.yzena.com/gavin/bc.
Before version \f[B]6.1.0\f[R], this bc(1) had incorrect behavior for
the \f[B]quit\f[R] statement.
.PP
No other bugs are known.
Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHORS
.PP
Gavin D.

View File

@ -558,46 +558,54 @@ The following are valid operands in bc(1):
7. **scale(E)**: The *scale* of **E**.
8. **abs(E)**: The absolute value of **E**. This is a **non-portable
extension**.
9. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
9. **is_number(E)**: **1** if the given argument is a number, **0** if it is a
string. This is a **non-portable extension**.
10. **is_string(E)**: **1** if the given argument is a string, **0** if it is a
number. This is a **non-portable extension**.
11. **modexp(E, E, E)**: Modular exponentiation, where the first expression is
the base, the second is the exponent, and the third is the modulus. All
three values must be integers. The second argument must be non-negative. The
third argument must be non-zero. This is a **non-portable extension**.
10. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
11. **divmod(E, E, I[])**: Division and modulus in one operation. This is for
optimization. The first expression is the dividend, and the second is the
divisor, which must be non-zero. The return value is the quotient, and the
modulus is stored in index **0** of the provided array (the last argument).
This is a **non-portable extension**.
11. **asciify(E)**: If **E** is a string, returns a string that is the first
12. **asciify(E)**: If **E** is a string, returns a string that is the first
letter of its argument. If it is a number, calculates the number mod **256**
and returns that number as a one-character string. This is a **non-portable
extension**.
12. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
13. **asciify(I[])**: A string that is made up of the characters that would
result from running **asciify(E)** on each element of the array identified
by the argument. This allows creating multi-character strings and storing
them. This is a **non-portable extension**.
14. **I()**, **I(E)**, **I(E, E)**, and so on, where **I** is an identifier for
a non-**void** function (see the *Void Functions* subsection of the
**FUNCTIONS** section). The **E** argument(s) may also be arrays of the form
**I[]**, which will automatically be turned into array references (see the
*Array References* subsection of the **FUNCTIONS** section) if the
corresponding parameter in the function definition is an array reference.
13. **read()**: Reads a line from **stdin** and uses that as an expression. The
15. **read()**: Reads a line from **stdin** and uses that as an expression. The
result of that expression is the result of the **read()** operand. This is a
**non-portable extension**.
14. **maxibase()**: The max allowable **ibase**. This is a **non-portable
16. **maxibase()**: The max allowable **ibase**. This is a **non-portable
extension**.
15. **maxobase()**: The max allowable **obase**. This is a **non-portable
17. **maxobase()**: The max allowable **obase**. This is a **non-portable
extension**.
16. **maxscale()**: The max allowable **scale**. This is a **non-portable
18. **maxscale()**: The max allowable **scale**. This is a **non-portable
extension**.
17. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
19. **line_length()**: The line length set with **BC_LINE_LENGTH** (see the
**ENVIRONMENT VARIABLES** section). This is a **non-portable extension**.
18. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
20. **global_stacks()**: **0** if global stacks are not enabled with the **-g**
or **-\-global-stacks** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
19. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
21. **leading_zero()**: **0** if leading zeroes are not enabled with the **-z**
or **--leading-zeroes** options, non-zero otherwise. See the **OPTIONS**
section. This is a **non-portable extension**.
20. **rand()**: A pseudo-random integer between **0** (inclusive) and
22. **rand()**: A pseudo-random integer between **0** (inclusive) and
**BC_RAND_MAX** (inclusive). Using this operand will change the value of
**seed**. This is a **non-portable extension**.
21. **irand(E)**: A pseudo-random integer between **0** (inclusive) and the
23. **irand(E)**: A pseudo-random integer between **0** (inclusive) and the
value of **E** (exclusive). If **E** is negative or is a non-integer
(**E**'s *scale* is not **0**), an error is raised, and bc(1) resets (see
the **RESET** section) while **seed** remains unchanged. If **E** is larger
@ -608,7 +616,7 @@ The following are valid operands in bc(1):
change the value of **seed**, unless the value of **E** is **0** or **1**.
In that case, **0** is returned, and **seed** is *not* changed. This is a
**non-portable extension**.
22. **maxrand()**: The max integer returned by **rand()**. This is a
24. **maxrand()**: The max integer returned by **rand()**. This is a
**non-portable extension**.
The integers generated by **rand()** and **irand(E)** are guaranteed to be as
@ -976,6 +984,19 @@ The **if** **else** statement does the same thing as in C.
The **quit** statement causes bc(1) to quit, even if it is on a branch that will
not be executed (it is a compile-time command).
**Warning**: The behavior of this bc(1) on **quit** is slightly different from
other bc(1) implementations. Other bc(1) implementations will exit as soon as
they finish parsing the line that a **quit** command is on. This bc(1) will
execute any completed and executable statements that occur before the **quit**
statement before exiting.
In other words, for the bc(1) code below:
for (i = 0; i < 3; ++i) i; quit
Other bc(1) implementations will print nothing, and this bc(1) will print **0**,
**1**, and **2** on successive lines before exiting.
The **halt** statement causes bc(1) to quit, if it is executed. (Unlike **quit**
if it is on a branch of an **if** statement that is not executed, bc(1) does not
quit.)
@ -2456,13 +2477,20 @@ at https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html . The
flags **-efghiqsvVw**, all long options, and the extensions noted above are
extensions to that specification.
In addition, the behavior of the **quit** implements an interpretation of that
specification that is different from all known implementations. For more
information see the **Statements** subsection of the **SYNTAX** section.
Note that the specification explicitly says that bc(1) only accepts numbers that
use a period (**.**) as a radix point, regardless of the value of
**LC_NUMERIC**.
# BUGS
None are known. Report bugs at https://git.yzena.com/gavin/bc.
Before version **6.1.0**, this bc(1) had incorrect behavior for the **quit**
statement.
No other bugs are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHORS

View File

@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.TH "BCL" "3" "August 2022" "Gavin D. Howard" "Libraries Manual"
.TH "BCL" "3" "October 2022" "Gavin D. Howard" "Libraries Manual"
.nh
.ad l
.SH NAME

View File

@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.TH "DC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
.TH "DC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH Name
@ -1157,6 +1157,10 @@ The execution stack is the stack of string executions.
The number that is pushed onto the stack is exactly as many as is needed
to make dc(1) exit with the \f[B]Q\f[R] command, so the sequence
\f[B],Q\f[R] will make dc(1) exit.
.RS
.PP
This is a \f[B]non-portable extension\f[R].
.RE
.SS Status
.PP
These commands query status of the stack or its top value.
@ -1183,6 +1187,24 @@ stack.
If it is a string, pushes \f[B]0\f[R].
.RE
.TP
\f[B]u\f[R]
Pops one value off of the stack.
If the value is a number, this pushes \f[B]1\f[R] onto the stack.
Otherwise (if it is a string), it pushes \f[B]0\f[R].
.RS
.PP
This is a \f[B]non-portable extension\f[R].
.RE
.TP
\f[B]t\f[R]
Pops one value off of the stack.
If the value is a string, this pushes \f[B]1\f[R] onto the stack.
Otherwise (if it is a number), it pushes \f[B]0\f[R].
.RS
.PP
This is a \f[B]non-portable extension\f[R].
.RE
.TP
\f[B]z\f[R]
Pushes the current depth of the stack (before execution of this command)
onto the stack.
@ -1696,7 +1718,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
.SH BUGS
.PP
None are known.
Report bugs at https://git.yzena.com/gavin/bc.
Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHOR
.PP
Gavin D.

View File

@ -1000,6 +1000,8 @@ will be printed with a newline after and then popped from the stack.
is exactly as many as is needed to make dc(1) exit with the **Q** command,
so the sequence **,Q** will make dc(1) exit.
This is a **non-portable extension**.
## Status
These commands query status of the stack or its top value.
@ -1022,6 +1024,20 @@ These commands query status of the stack or its top value.
If it is a string, pushes **0**.
**u**
: Pops one value off of the stack. If the value is a number, this pushes **1**
onto the stack. Otherwise (if it is a string), it pushes **0**.
This is a **non-portable extension**.
**t**
: Pops one value off of the stack. If the value is a string, this pushes **1**
onto the stack. Otherwise (if it is a number), it pushes **0**.
This is a **non-portable extension**.
**z**
: Pushes the current depth of the stack (before execution of this command)
@ -1501,7 +1517,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
# BUGS
None are known. Report bugs at https://git.yzena.com/gavin/bc.
None are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHOR

View File

@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.TH "DC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
.TH "DC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH Name
@ -942,6 +942,10 @@ The execution stack is the stack of string executions.
The number that is pushed onto the stack is exactly as many as is needed
to make dc(1) exit with the \f[B]Q\f[R] command, so the sequence
\f[B],Q\f[R] will make dc(1) exit.
.RS
.PP
This is a \f[B]non-portable extension\f[R].
.RE
.SS Status
.PP
These commands query status of the stack or its top value.
@ -968,6 +972,24 @@ stack.
If it is a string, pushes \f[B]0\f[R].
.RE
.TP
\f[B]u\f[R]
Pops one value off of the stack.
If the value is a number, this pushes \f[B]1\f[R] onto the stack.
Otherwise (if it is a string), it pushes \f[B]0\f[R].
.RS
.PP
This is a \f[B]non-portable extension\f[R].
.RE
.TP
\f[B]t\f[R]
Pops one value off of the stack.
If the value is a string, this pushes \f[B]1\f[R] onto the stack.
Otherwise (if it is a number), it pushes \f[B]0\f[R].
.RS
.PP
This is a \f[B]non-portable extension\f[R].
.RE
.TP
\f[B]z\f[R]
Pushes the current depth of the stack (before execution of this command)
onto the stack.
@ -1474,7 +1496,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
.SH BUGS
.PP
None are known.
Report bugs at https://git.yzena.com/gavin/bc.
Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHOR
.PP
Gavin D.

View File

@ -831,6 +831,8 @@ will be printed with a newline after and then popped from the stack.
is exactly as many as is needed to make dc(1) exit with the **Q** command,
so the sequence **,Q** will make dc(1) exit.
This is a **non-portable extension**.
## Status
These commands query status of the stack or its top value.
@ -853,6 +855,20 @@ These commands query status of the stack or its top value.
If it is a string, pushes **0**.
**u**
: Pops one value off of the stack. If the value is a number, this pushes **1**
onto the stack. Otherwise (if it is a string), it pushes **0**.
This is a **non-portable extension**.
**t**
: Pops one value off of the stack. If the value is a string, this pushes **1**
onto the stack. Otherwise (if it is a number), it pushes **0**.
This is a **non-portable extension**.
**z**
: Pushes the current depth of the stack (before execution of this command)
@ -1325,7 +1341,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
# BUGS
None are known. Report bugs at https://git.yzena.com/gavin/bc.
None are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHOR

View File

@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.TH "DC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
.TH "DC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH Name
@ -942,6 +942,10 @@ The execution stack is the stack of string executions.
The number that is pushed onto the stack is exactly as many as is needed
to make dc(1) exit with the \f[B]Q\f[R] command, so the sequence
\f[B],Q\f[R] will make dc(1) exit.
.RS
.PP
This is a \f[B]non-portable extension\f[R].
.RE
.SS Status
.PP
These commands query status of the stack or its top value.
@ -968,6 +972,24 @@ stack.
If it is a string, pushes \f[B]0\f[R].
.RE
.TP
\f[B]u\f[R]
Pops one value off of the stack.
If the value is a number, this pushes \f[B]1\f[R] onto the stack.
Otherwise (if it is a string), it pushes \f[B]0\f[R].
.RS
.PP
This is a \f[B]non-portable extension\f[R].
.RE
.TP
\f[B]t\f[R]
Pops one value off of the stack.
If the value is a string, this pushes \f[B]1\f[R] onto the stack.
Otherwise (if it is a number), it pushes \f[B]0\f[R].
.RS
.PP
This is a \f[B]non-portable extension\f[R].
.RE
.TP
\f[B]z\f[R]
Pushes the current depth of the stack (before execution of this command)
onto the stack.
@ -1448,7 +1470,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
.SH BUGS
.PP
None are known.
Report bugs at https://git.yzena.com/gavin/bc.
Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHOR
.PP
Gavin D.

View File

@ -831,6 +831,8 @@ will be printed with a newline after and then popped from the stack.
is exactly as many as is needed to make dc(1) exit with the **Q** command,
so the sequence **,Q** will make dc(1) exit.
This is a **non-portable extension**.
## Status
These commands query status of the stack or its top value.
@ -853,6 +855,20 @@ These commands query status of the stack or its top value.
If it is a string, pushes **0**.
**u**
: Pops one value off of the stack. If the value is a number, this pushes **1**
onto the stack. Otherwise (if it is a string), it pushes **0**.
This is a **non-portable extension**.
**t**
: Pops one value off of the stack. If the value is a string, this pushes **1**
onto the stack. Otherwise (if it is a number), it pushes **0**.
This is a **non-portable extension**.
**z**
: Pushes the current depth of the stack (before execution of this command)
@ -1302,7 +1318,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
# BUGS
None are known. Report bugs at https://git.yzena.com/gavin/bc.
None are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHOR

View File

@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.TH "DC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
.TH "DC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH Name
@ -942,6 +942,10 @@ The execution stack is the stack of string executions.
The number that is pushed onto the stack is exactly as many as is needed
to make dc(1) exit with the \f[B]Q\f[R] command, so the sequence
\f[B],Q\f[R] will make dc(1) exit.
.RS
.PP
This is a \f[B]non-portable extension\f[R].
.RE
.SS Status
.PP
These commands query status of the stack or its top value.
@ -968,6 +972,24 @@ stack.
If it is a string, pushes \f[B]0\f[R].
.RE
.TP
\f[B]u\f[R]
Pops one value off of the stack.
If the value is a number, this pushes \f[B]1\f[R] onto the stack.
Otherwise (if it is a string), it pushes \f[B]0\f[R].
.RS
.PP
This is a \f[B]non-portable extension\f[R].
.RE
.TP
\f[B]t\f[R]
Pops one value off of the stack.
If the value is a string, this pushes \f[B]1\f[R] onto the stack.
Otherwise (if it is a number), it pushes \f[B]0\f[R].
.RS
.PP
This is a \f[B]non-portable extension\f[R].
.RE
.TP
\f[B]z\f[R]
Pushes the current depth of the stack (before execution of this command)
onto the stack.
@ -1444,7 +1466,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
.SH BUGS
.PP
None are known.
Report bugs at https://git.yzena.com/gavin/bc.
Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHOR
.PP
Gavin D.

View File

@ -831,6 +831,8 @@ will be printed with a newline after and then popped from the stack.
is exactly as many as is needed to make dc(1) exit with the **Q** command,
so the sequence **,Q** will make dc(1) exit.
This is a **non-portable extension**.
## Status
These commands query status of the stack or its top value.
@ -853,6 +855,20 @@ These commands query status of the stack or its top value.
If it is a string, pushes **0**.
**u**
: Pops one value off of the stack. If the value is a number, this pushes **1**
onto the stack. Otherwise (if it is a string), it pushes **0**.
This is a **non-portable extension**.
**t**
: Pops one value off of the stack. If the value is a string, this pushes **1**
onto the stack. Otherwise (if it is a number), it pushes **0**.
This is a **non-portable extension**.
**z**
: Pushes the current depth of the stack (before execution of this command)
@ -1297,7 +1313,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
# BUGS
None are known. Report bugs at https://git.yzena.com/gavin/bc.
None are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHOR

View File

@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.TH "DC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
.TH "DC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH Name
@ -942,6 +942,10 @@ The execution stack is the stack of string executions.
The number that is pushed onto the stack is exactly as many as is needed
to make dc(1) exit with the \f[B]Q\f[R] command, so the sequence
\f[B],Q\f[R] will make dc(1) exit.
.RS
.PP
This is a \f[B]non-portable extension\f[R].
.RE
.SS Status
.PP
These commands query status of the stack or its top value.
@ -968,6 +972,24 @@ stack.
If it is a string, pushes \f[B]0\f[R].
.RE
.TP
\f[B]u\f[R]
Pops one value off of the stack.
If the value is a number, this pushes \f[B]1\f[R] onto the stack.
Otherwise (if it is a string), it pushes \f[B]0\f[R].
.RS
.PP
This is a \f[B]non-portable extension\f[R].
.RE
.TP
\f[B]t\f[R]
Pops one value off of the stack.
If the value is a string, this pushes \f[B]1\f[R] onto the stack.
Otherwise (if it is a number), it pushes \f[B]0\f[R].
.RS
.PP
This is a \f[B]non-portable extension\f[R].
.RE
.TP
\f[B]z\f[R]
Pushes the current depth of the stack (before execution of this command)
onto the stack.
@ -1470,7 +1492,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
.SH BUGS
.PP
None are known.
Report bugs at https://git.yzena.com/gavin/bc.
Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHOR
.PP
Gavin D.

View File

@ -831,6 +831,8 @@ will be printed with a newline after and then popped from the stack.
is exactly as many as is needed to make dc(1) exit with the **Q** command,
so the sequence **,Q** will make dc(1) exit.
This is a **non-portable extension**.
## Status
These commands query status of the stack or its top value.
@ -853,6 +855,20 @@ These commands query status of the stack or its top value.
If it is a string, pushes **0**.
**u**
: Pops one value off of the stack. If the value is a number, this pushes **1**
onto the stack. Otherwise (if it is a string), it pushes **0**.
This is a **non-portable extension**.
**t**
: Pops one value off of the stack. If the value is a string, this pushes **1**
onto the stack. Otherwise (if it is a number), it pushes **0**.
This is a **non-portable extension**.
**z**
: Pushes the current depth of the stack (before execution of this command)
@ -1320,7 +1336,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
# BUGS
None are known. Report bugs at https://git.yzena.com/gavin/bc.
None are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHOR

View File

@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.TH "DC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
.TH "DC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH Name
@ -1157,6 +1157,10 @@ The execution stack is the stack of string executions.
The number that is pushed onto the stack is exactly as many as is needed
to make dc(1) exit with the \f[B]Q\f[R] command, so the sequence
\f[B],Q\f[R] will make dc(1) exit.
.RS
.PP
This is a \f[B]non-portable extension\f[R].
.RE
.SS Status
.PP
These commands query status of the stack or its top value.
@ -1183,6 +1187,24 @@ stack.
If it is a string, pushes \f[B]0\f[R].
.RE
.TP
\f[B]u\f[R]
Pops one value off of the stack.
If the value is a number, this pushes \f[B]1\f[R] onto the stack.
Otherwise (if it is a string), it pushes \f[B]0\f[R].
.RS
.PP
This is a \f[B]non-portable extension\f[R].
.RE
.TP
\f[B]t\f[R]
Pops one value off of the stack.
If the value is a string, this pushes \f[B]1\f[R] onto the stack.
Otherwise (if it is a number), it pushes \f[B]0\f[R].
.RS
.PP
This is a \f[B]non-portable extension\f[R].
.RE
.TP
\f[B]z\f[R]
Pushes the current depth of the stack (before execution of this command)
onto the stack.
@ -1670,7 +1692,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
.SH BUGS
.PP
None are known.
Report bugs at https://git.yzena.com/gavin/bc.
Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHOR
.PP
Gavin D.

View File

@ -1000,6 +1000,8 @@ will be printed with a newline after and then popped from the stack.
is exactly as many as is needed to make dc(1) exit with the **Q** command,
so the sequence **,Q** will make dc(1) exit.
This is a **non-portable extension**.
## Status
These commands query status of the stack or its top value.
@ -1022,6 +1024,20 @@ These commands query status of the stack or its top value.
If it is a string, pushes **0**.
**u**
: Pops one value off of the stack. If the value is a number, this pushes **1**
onto the stack. Otherwise (if it is a string), it pushes **0**.
This is a **non-portable extension**.
**t**
: Pops one value off of the stack. If the value is a string, this pushes **1**
onto the stack. Otherwise (if it is a number), it pushes **0**.
This is a **non-portable extension**.
**z**
: Pushes the current depth of the stack (before execution of this command)
@ -1478,7 +1494,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
# BUGS
None are known. Report bugs at https://git.yzena.com/gavin/bc.
None are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHOR

View File

@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.TH "DC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
.TH "DC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH Name
@ -1157,6 +1157,10 @@ The execution stack is the stack of string executions.
The number that is pushed onto the stack is exactly as many as is needed
to make dc(1) exit with the \f[B]Q\f[R] command, so the sequence
\f[B],Q\f[R] will make dc(1) exit.
.RS
.PP
This is a \f[B]non-portable extension\f[R].
.RE
.SS Status
.PP
These commands query status of the stack or its top value.
@ -1183,6 +1187,24 @@ stack.
If it is a string, pushes \f[B]0\f[R].
.RE
.TP
\f[B]u\f[R]
Pops one value off of the stack.
If the value is a number, this pushes \f[B]1\f[R] onto the stack.
Otherwise (if it is a string), it pushes \f[B]0\f[R].
.RS
.PP
This is a \f[B]non-portable extension\f[R].
.RE
.TP
\f[B]t\f[R]
Pops one value off of the stack.
If the value is a string, this pushes \f[B]1\f[R] onto the stack.
Otherwise (if it is a number), it pushes \f[B]0\f[R].
.RS
.PP
This is a \f[B]non-portable extension\f[R].
.RE
.TP
\f[B]z\f[R]
Pushes the current depth of the stack (before execution of this command)
onto the stack.
@ -1666,7 +1688,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
.SH BUGS
.PP
None are known.
Report bugs at https://git.yzena.com/gavin/bc.
Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHOR
.PP
Gavin D.

View File

@ -1000,6 +1000,8 @@ will be printed with a newline after and then popped from the stack.
is exactly as many as is needed to make dc(1) exit with the **Q** command,
so the sequence **,Q** will make dc(1) exit.
This is a **non-portable extension**.
## Status
These commands query status of the stack or its top value.
@ -1022,6 +1024,20 @@ These commands query status of the stack or its top value.
If it is a string, pushes **0**.
**u**
: Pops one value off of the stack. If the value is a number, this pushes **1**
onto the stack. Otherwise (if it is a string), it pushes **0**.
This is a **non-portable extension**.
**t**
: Pops one value off of the stack. If the value is a string, this pushes **1**
onto the stack. Otherwise (if it is a number), it pushes **0**.
This is a **non-portable extension**.
**z**
: Pushes the current depth of the stack (before execution of this command)
@ -1473,7 +1489,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
# BUGS
None are known. Report bugs at https://git.yzena.com/gavin/bc.
None are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHOR

View File

@ -25,7 +25,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.TH "DC" "1" "August 2022" "Gavin D. Howard" "General Commands Manual"
.TH "DC" "1" "October 2022" "Gavin D. Howard" "General Commands Manual"
.nh
.ad l
.SH Name
@ -1157,6 +1157,10 @@ The execution stack is the stack of string executions.
The number that is pushed onto the stack is exactly as many as is needed
to make dc(1) exit with the \f[B]Q\f[R] command, so the sequence
\f[B],Q\f[R] will make dc(1) exit.
.RS
.PP
This is a \f[B]non-portable extension\f[R].
.RE
.SS Status
.PP
These commands query status of the stack or its top value.
@ -1183,6 +1187,24 @@ stack.
If it is a string, pushes \f[B]0\f[R].
.RE
.TP
\f[B]u\f[R]
Pops one value off of the stack.
If the value is a number, this pushes \f[B]1\f[R] onto the stack.
Otherwise (if it is a string), it pushes \f[B]0\f[R].
.RS
.PP
This is a \f[B]non-portable extension\f[R].
.RE
.TP
\f[B]t\f[R]
Pops one value off of the stack.
If the value is a string, this pushes \f[B]1\f[R] onto the stack.
Otherwise (if it is a number), it pushes \f[B]0\f[R].
.RS
.PP
This is a \f[B]non-portable extension\f[R].
.RE
.TP
\f[B]z\f[R]
Pushes the current depth of the stack (before execution of this command)
onto the stack.
@ -1692,7 +1714,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
.SH BUGS
.PP
None are known.
Report bugs at https://git.yzena.com/gavin/bc.
Report bugs at https://git.yzena.com/gavin/bc .
.SH AUTHOR
.PP
Gavin D.

View File

@ -1000,6 +1000,8 @@ will be printed with a newline after and then popped from the stack.
is exactly as many as is needed to make dc(1) exit with the **Q** command,
so the sequence **,Q** will make dc(1) exit.
This is a **non-portable extension**.
## Status
These commands query status of the stack or its top value.
@ -1022,6 +1024,20 @@ These commands query status of the stack or its top value.
If it is a string, pushes **0**.
**u**
: Pops one value off of the stack. If the value is a number, this pushes **1**
onto the stack. Otherwise (if it is a string), it pushes **0**.
This is a **non-portable extension**.
**t**
: Pops one value off of the stack. If the value is a string, this pushes **1**
onto the stack. Otherwise (if it is a number), it pushes **0**.
This is a **non-portable extension**.
**z**
: Pushes the current depth of the stack (before execution of this command)
@ -1496,7 +1512,7 @@ https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html .
# BUGS
None are known. Report bugs at https://git.yzena.com/gavin/bc.
None are known. Report bugs at https://git.yzena.com/gavin/bc .
# AUTHOR

View File

@ -115,7 +115,7 @@ bc_lex_string(BcLex* l)
buf = l->buf;
got_more = false;
assert(!vm->is_stdin || buf == vm->buffer.v);
assert(vm->mode != BC_MODE_STDIN || buf == vm->buffer.v);
// Fortunately for us, bc doesn't escape quotes. Instead, the equivalent
// is '\q', which makes this loop simpler.
@ -124,7 +124,7 @@ bc_lex_string(BcLex* l)
nlines += (c == '\n');
}
if (BC_ERR(c == '\0') && !vm->eof && (l->is_stdin || l->is_exprs))
if (BC_ERR(c == '\0') && !vm->eof && l->mode != BC_MODE_FILE)
{
got_more = bc_lex_readLine(l);
}

View File

@ -207,7 +207,7 @@ bc_parse_createCondLabel(BcParse* p, size_t idx)
bc_vec_push(&p->conds, &idx);
}
/*
/**
* Creates an exit label to be filled in later by bc_parse_setLabel(). Also, why
* create a label to be filled in later? Because exit labels are meant to be
* targeted by code that comes *before* the label. Since we have to parse that
@ -255,25 +255,30 @@ bc_parse_operator(BcParse* p, BcLexType type, size_t start, size_t* nexprs)
uchar l, r = BC_PARSE_OP_PREC(type);
uchar left = BC_PARSE_OP_LEFT(type);
// While we haven't hit the stop point yet.
// While we haven't hit the stop point yet...
while (p->ops.len > start)
{
// Get the top operator.
t = BC_PARSE_TOP_OP(p);
// If it's a right paren, we have reached the end of whatever expression
// this is no matter what.
// If it's a left paren, we have reached the end of whatever expression
// this is no matter what. We also don't pop the left paren because it
// will need to stay for the rest of the subexpression.
if (t == BC_LEX_LPAREN) break;
// Break for precedence. Precedence operates differently on left and
// right associativity, by the way. A left associative operator that
// matches the current precedence should take priority, but a right
// associative operator should not.
//
// Also, a lower precedence value means a higher precedence.
l = BC_PARSE_OP_PREC(t);
if (l >= r && (l != r || !left)) break;
// Do the housekeeping. In particular, make sure to note that one
// expression was consumed. (Two were, but another was added.)
// expression was consumed (well, two were, but another was added) if
// the operator was not a prefix operator. (Postfix operators are not
// handled by this function at all.)
bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
bc_vec_pop(&p->ops);
*nexprs -= !BC_PARSE_OP_PREFIX(t);
@ -390,7 +395,11 @@ bc_parse_call(BcParse* p, const char* name, uint8_t flags)
/**
* Parses a name/identifier-based expression. It could be a variable, an array
* element, an array itself (for function arguments), a function call, etc.
*
* @param p The parser.
* @param type A pointer to return the resulting instruction.
* @param can_assign A pointer to return true if the name can be assigned to,
* false otherwise.
* @param flags Flags restricting what kind of expression the name can be.
*/
static void
bc_parse_name(BcParse* p, BcInst* type, bool* can_assign, uint8_t flags)
@ -523,7 +532,13 @@ bc_parse_builtin(BcParse* p, BcLexType type, uint8_t flags, BcInst* prev)
flags |= BC_PARSE_NEEDVAL;
// Since length can take arrays, we need to specially add that flag.
if (type == BC_LEX_KW_LENGTH) flags |= BC_PARSE_ARRAY;
if (type == BC_LEX_KW_LENGTH || type == BC_LEX_KW_ASCIIFY)
{
flags |= BC_PARSE_ARRAY;
}
// Otherwise, we need to clear it because it could be set.
else flags &= ~(BC_PARSE_ARRAY);
bc_parse_expr_status(p, flags, bc_parse_next_rel);
@ -540,6 +555,10 @@ bc_parse_builtin(BcParse* p, BcLexType type, uint8_t flags, BcInst* prev)
/**
* Parses a builtin function that takes 3 arguments. This includes modexp() and
* divmod().
* @param p The parser.
* @param type The lex token.
* @param flags The expression parsing flags for parsing the argument.
* @param prev An out parameter; the previous instruction pointer.
*/
static void
bc_parse_builtin3(BcParse* p, BcLexType type, uint8_t flags, BcInst* prev)
@ -728,7 +747,7 @@ bc_parse_incdec(BcParse* p, BcInst* prev, bool* can_assign, size_t* nexs,
if (type == BC_LEX_NAME)
{
// Parse the name.
uint8_t flags2 = flags & ~BC_PARSE_ARRAY;
uint8_t flags2 = flags & ~(BC_PARSE_ARRAY);
bc_parse_name(p, prev, can_assign, flags2 | BC_PARSE_NOCALL);
}
// Is the next token a global?
@ -1091,9 +1110,9 @@ bc_parse_endif(BcParse* p)
{
// We set this to restore it later. We don't want the parser thinking
// that we are on stdin for this one because it will want more.
bool is_stdin = vm->is_stdin;
BcMode mode = vm->mode;
vm->is_stdin = false;
vm->mode = BC_MODE_FILE;
// End all of the if statements and loops.
while (p->flags.len > 1 || BC_PARSE_IF_END(p))
@ -1102,7 +1121,7 @@ bc_parse_endif(BcParse* p)
if (p->flags.len > 1) bc_parse_endBody(p, false);
}
vm->is_stdin = is_stdin;
vm->mode = (uchar) mode;
}
// If we reach here, a block was not properly closed, and we should error.
else bc_parse_err(&vm->prs, BC_ERR_PARSE_BLOCK);
@ -1693,6 +1712,8 @@ bc_parse_stmt(BcParse* p)
#endif // BC_ENABLE_EXTRA_MATH
case BC_LEX_KW_SQRT:
case BC_LEX_KW_ABS:
case BC_LEX_KW_IS_NUMBER:
case BC_LEX_KW_IS_STRING:
#if BC_ENABLE_EXTRA_MATH
case BC_LEX_KW_IRAND:
#endif // BC_ENABLE_EXTRA_MATH
@ -1907,7 +1928,7 @@ bc_parse_stmt(BcParse* p)
}
// Make sure semicolons are eaten.
while (p->l.t == BC_LEX_SCOLON)
while (p->l.t == BC_LEX_SCOLON || p->l.t == BC_LEX_NLINE)
{
bc_lex_next(&p->l);
}
@ -2294,6 +2315,8 @@ bc_parse_expr_err(BcParse* p, uint8_t flags, BcParseNext next)
case BC_LEX_KW_LENGTH:
case BC_LEX_KW_SQRT:
case BC_LEX_KW_ABS:
case BC_LEX_KW_IS_NUMBER:
case BC_LEX_KW_IS_STRING:
#if BC_ENABLE_EXTRA_MATH
case BC_LEX_KW_IRAND:
#endif // BC_ENABLE_EXTRA_MATH

View File

@ -719,6 +719,8 @@ const char* bc_inst_names[] = {
"BC_INST_SCALE_FUNC",
"BC_INST_SQRT",
"BC_INST_ABS",
"BC_INST_IS_NUMBER",
"BC_INST_IS_STRING",
#if BC_ENABLE_EXTRA_MATH
"BC_INST_IRAND",
#endif // BC_ENABLE_EXTRA_MATH
@ -816,6 +818,8 @@ const BcLexKeyword bc_lex_kws[] = {
BC_LEX_KW_ENTRY("print", 5, false),
BC_LEX_KW_ENTRY("sqrt", 4, true),
BC_LEX_KW_ENTRY("abs", 3, false),
BC_LEX_KW_ENTRY("is_number", 9, false),
BC_LEX_KW_ENTRY("is_string", 9, false),
#if BC_ENABLE_EXTRA_MATH
BC_LEX_KW_ENTRY("irand", 5, false),
#endif // BC_ENABLE_EXTRA_MATH
@ -888,13 +892,13 @@ const uint8_t bc_parse_exprs[] = {
BC_PARSE_EXPR_ENTRY(false, true, true, true, true, true, true, false),
// Starts with BC_LEX_KW_SQRT.
BC_PARSE_EXPR_ENTRY(true, true, true, true, true, true, false, true),
// Starts with BC_LEX_KW_MAXIBASE.
BC_PARSE_EXPR_ENTRY(true, true, true, true, true, true, true, true),
// Starts with BC_LEX_KW_STREAM.
BC_PARSE_EXPR_ENTRY(false, false, 0, 0, 0, 0, 0, 0)
// Starts with BC_LEX_KW_QUIT.
BC_PARSE_EXPR_ENTRY(false, true, true, true, true, true, true, true),
// Starts with BC_LEX_KW_GLOBAL_STACKS.
BC_PARSE_EXPR_ENTRY(true, true, false, false, 0, 0, 0, 0)
#else // BC_ENABLE_EXTRA_MATH
@ -911,15 +915,19 @@ const uint8_t bc_parse_exprs[] = {
BC_PARSE_EXPR_ENTRY(false, false, true, true, true, true, true, false),
// Starts with BC_LEX_KW_SQRT.
BC_PARSE_EXPR_ENTRY(true, true, true, true, true, false, true, true),
BC_PARSE_EXPR_ENTRY(true, true, true, true, true, true, true, false),
// Starts with BC_LEX_KW_MAXSCALE,
BC_PARSE_EXPR_ENTRY(true, true, true, true, true, false, false, 0)
// Starts with BC_LEX_KW_MAXIBASE.
BC_PARSE_EXPR_ENTRY(true, true, true, true, true, true, true, false),
// Starts with BC_LEX_KW_ELSE.
BC_PARSE_EXPR_ENTRY(false, 0, 0, 0, 0, 0, 0, 0)
#endif // BC_ENABLE_EXTRA_MATH
};
/// An array of data for operators that correspond to token types.
/// An array of data for operators that correspond to token types. Note that a
/// lower precedence *value* means a higher precedence.
const uchar bc_parse_ops[] = {
BC_PARSE_OP(0, false), BC_PARSE_OP(0, false), BC_PARSE_OP(1, false),
BC_PARSE_OP(1, false),
@ -1122,8 +1130,8 @@ const uchar dc_lex_tokens[] = {
BC_LEX_KW_QUIT,
BC_LEX_SWAP,
BC_LEX_OP_ASSIGN,
BC_LEX_INVALID,
BC_LEX_INVALID,
BC_LEX_KW_IS_STRING,
BC_LEX_KW_IS_NUMBER,
BC_LEX_KW_SQRT,
BC_LEX_INVALID,
BC_LEX_EXECUTE,
@ -1137,7 +1145,7 @@ const uchar dc_lex_tokens[] = {
};
/// A list of instructions that correspond to lex tokens. If an entry is
/// BC_INST_INVALID, that lex token needs extra parsing in the dc parser.
/// @a BC_INST_INVALID, that lex token needs extra parsing in the dc parser.
/// Otherwise, the token can trivially be replaced by the entry. This needs to
/// be updated if the tokens change.
const uchar dc_parse_insts[] = {
@ -1180,7 +1188,7 @@ const uchar dc_parse_insts[] = {
BC_INST_SEED,
#endif // BC_ENABLE_EXTRA_MATH
BC_INST_LENGTH, BC_INST_PRINT, BC_INST_SQRT,
BC_INST_ABS,
BC_INST_ABS, BC_INST_IS_NUMBER, BC_INST_IS_STRING,
#if BC_ENABLE_EXTRA_MATH
BC_INST_IRAND,
#endif // BC_ENABLE_EXTRA_MATH

View File

@ -114,7 +114,7 @@ dc_lex_string(BcLex* l)
nls = 0;
got_more = false;
assert(!l->is_stdin || l->buf == vm->buffer.v);
assert(l->mode != BC_MODE_STDIN || l->buf == vm->buffer.v);
// This is the meat. As long as we don't run into the NUL byte, and we
// have "depth", which means we haven't completely balanced brackets
@ -141,11 +141,15 @@ dc_lex_string(BcLex* l)
if (BC_ERR(c == '\0' && depth))
{
if (!vm->eof && (l->is_stdin || l->is_exprs))
if (!vm->eof && l->mode != BC_MODE_FILE)
{
got_more = bc_lex_readLine(l);
}
if (got_more) bc_vec_popAll(&l->str);
if (got_more)
{
bc_vec_popAll(&l->str);
}
}
}
while (got_more && depth);

View File

@ -324,6 +324,8 @@ dc_parse_token(BcParse* p, BcLexType t, uint8_t flags)
case BC_LEX_KW_PRINT:
case BC_LEX_KW_SQRT:
case BC_LEX_KW_ABS:
case BC_LEX_KW_IS_NUMBER:
case BC_LEX_KW_IS_STRING:
#if BC_ENABLE_EXTRA_MATH
case BC_LEX_KW_IRAND:
#endif // BC_ENABLE_EXTRA_MATH

View File

@ -99,10 +99,6 @@ bc_func_init(BcFunc* f, const char* name)
bc_vec_init(&f->code, sizeof(uchar), BC_DTOR_NONE);
bc_vec_init(&f->consts, sizeof(BcConst), BC_DTOR_CONST);
bc_vec_init(&f->strs, sizeof(char*), BC_DTOR_NONE);
#if BC_ENABLED
// Only bc needs these things.
@ -128,10 +124,6 @@ bc_func_reset(BcFunc* f)
bc_vec_popAll(&f->code);
bc_vec_popAll(&f->consts);
bc_vec_popAll(&f->strs);
#if BC_ENABLED
if (BC_IS_BC)
{
@ -155,10 +147,6 @@ bc_func_free(void* func)
bc_vec_free(&f->code);
bc_vec_free(&f->consts);
bc_vec_free(&f->strs);
#if BC_ENABLED
if (BC_IS_BC)
{

View File

@ -79,7 +79,7 @@ bc_lex_comment(BcLex* l)
got_more = false;
// If we are in stdin mode, the buffer must be the one used for stdin.
assert(!vm->is_stdin || buf == vm->buffer.v);
assert(vm->mode != BC_MODE_STDIN || buf == vm->buffer.v);
// Find the end of the comment.
for (i = l->i; !end; i += !end)
@ -94,7 +94,7 @@ bc_lex_comment(BcLex* l)
if (BC_ERR(!c || buf[i + 1] == '\0'))
{
// Read more, if possible.
if (!vm->eof && (l->is_stdin || l->is_exprs))
if (!vm->eof && l->mode != BC_MODE_FILE)
{
got_more = bc_lex_readLine(l);
}
@ -349,11 +349,35 @@ bc_lex_readLine(BcLex* l)
BC_SIG_UNLOCK;
// Make sure we read from the appropriate place.
if (l->is_stdin) good = bc_vm_readLine(false);
else
switch (l->mode)
{
assert(l->is_exprs);
good = bc_vm_readBuf(false);
case BC_MODE_EXPRS:
{
good = bc_vm_readBuf(false);
break;
}
case BC_MODE_FILE:
{
good = false;
break;
}
case BC_MODE_STDIN:
{
good = bc_vm_readLine(false);
break;
}
#ifdef __GNUC__
#ifndef __clang__
default:
{
// We should never get here.
abort();
}
#endif // __clang__
#endif // __GNUC__
}
BC_SIG_LOCK;
@ -364,7 +388,7 @@ bc_lex_readLine(BcLex* l)
}
void
bc_lex_text(BcLex* l, const char* text, bool is_stdin, bool is_exprs)
bc_lex_text(BcLex* l, const char* text, BcMode mode)
{
BC_SIG_ASSERT_LOCKED;
@ -373,10 +397,7 @@ bc_lex_text(BcLex* l, const char* text, bool is_stdin, bool is_exprs)
bc_lex_fixText(l, text, strlen(text));
l->i = 0;
l->t = l->last = BC_LEX_INVALID;
l->is_stdin = is_stdin;
l->is_exprs = is_exprs;
assert(!l->is_stdin || !l->is_exprs);
l->mode = mode;
bc_lex_next(l);
}

View File

@ -130,7 +130,7 @@ bc_num_expand(BcNum* restrict n, size_t req)
* @param n The number to set to zero.
* @param scale The scale to set the number to.
*/
static void
static inline void
bc_num_setToZero(BcNum* restrict n, size_t scale)
{
assert(n != NULL);

View File

@ -64,10 +64,9 @@ bc_parse_pushName(const BcParse* p, char* name, bool var)
* @param inst The instruction to push.
* @param idx The index to push.
*/
static void
bc_parse_update(BcParse* p, uchar inst, size_t idx)
static inline void
bc_parse_pushInstIdx(BcParse* p, uchar inst, size_t idx)
{
bc_parse_updateFunc(p, p->fidx);
bc_parse_push(p, inst);
bc_parse_pushIndex(p, idx);
}
@ -77,20 +76,17 @@ bc_parse_addString(BcParse* p)
{
size_t idx;
idx = bc_program_addString(p->prog, p->l.str.v, p->fidx);
idx = bc_program_addString(p->prog, p->l.str.v);
// Push the string info.
bc_parse_update(p, BC_INST_STR, p->fidx);
bc_parse_pushIndex(p, idx);
bc_parse_pushInstIdx(p, BC_INST_STR, idx);
}
static void
bc_parse_addNum(BcParse* p, const char* string)
{
BcVec* consts = &p->func->consts;
BcProgram* prog = p->prog;
size_t idx;
BcConst* c;
BcVec* slabs;
// XXX: This function has an implicit assumption: that string is a valid C
// string with a nul terminator. This is because of the unchecked array
@ -117,25 +113,33 @@ bc_parse_addNum(BcParse* p, const char* string)
return;
}
// Get the index.
idx = consts->len;
if (bc_map_insert(&prog->const_map, string, prog->consts.len, &idx))
{
BcConst* c;
BcId* id = bc_vec_item(&prog->const_map, idx);
// Get the right slab.
slabs = p->fidx == BC_PROG_MAIN || p->fidx == BC_PROG_READ ?
&vm->main_const_slab :
&vm->other_slabs;
// Get the index.
idx = id->idx;
// Push an empty constant.
c = bc_vec_pushEmpty(consts);
// Push an empty constant.
c = bc_vec_pushEmpty(&prog->consts);
// Set the fields.
c->val = bc_slabvec_strdup(slabs, string);
c->base = BC_NUM_BIGDIG_MAX;
// Set the fields. We reuse the string in the ID (allocated by
// bc_map_insert()), because why not?
c->val = id->name;
c->base = BC_NUM_BIGDIG_MAX;
// We need this to be able to tell that the number has not been allocated.
bc_num_clear(&c->num);
// We need this to be able to tell that the number has not been
// allocated.
bc_num_clear(&c->num);
}
else
{
BcId* id = bc_vec_item(&prog->const_map, idx);
idx = id->idx;
}
bc_parse_update(p, BC_INST_NUM, idx);
bc_parse_pushInstIdx(p, BC_INST_NUM, idx);
}
void
@ -173,13 +177,13 @@ bc_parse_number(BcParse* p)
}
void
bc_parse_text(BcParse* p, const char* text, bool is_stdin, bool is_exprs)
bc_parse_text(BcParse* p, const char* text, BcMode mode)
{
BC_SIG_LOCK;
// Make sure the pointer isn't invalidated.
p->func = bc_vec_item(&p->prog->fns, p->fidx);
bc_lex_text(&p->l, text, is_stdin, is_exprs);
bc_lex_text(&p->l, text, mode);
BC_SIG_UNLOCK;
}

View File

@ -48,20 +48,6 @@
#include <program.h>
#include <vm.h>
/**
* Quickly sets the const and strs vector pointers in the program. This is a
* convenience function.
* @param p The program.
* @param f The new function.
*/
static inline void
bc_program_setVecs(BcProgram* p, BcFunc* f)
{
BC_SIG_ASSERT_LOCKED;
p->consts = &f->consts;
p->strs = &f->strs;
}
/**
* Does a type check for something that expects a number.
* @param r The result that will be checked.
@ -124,11 +110,10 @@ bc_program_index(const char* restrict code, size_t* restrict bgn)
* @param n The number tied to the result.
* @return The string corresponding to the result and number.
*/
static char*
static inline char*
bc_program_string(BcProgram* p, const BcNum* n)
{
BcFunc* f = bc_vec_item(&p->fns, n->rdx);
return *((char**) bc_vec_item(&f->strs, n->scale));
return *((char**) bc_vec_item(&p->strs, n->scale));
}
#if BC_ENABLED
@ -233,30 +218,38 @@ bc_program_pushBigdig(BcProgram* p, BcBigDig dig, BcResultType type)
}
size_t
bc_program_addString(BcProgram* p, const char* str, size_t fidx)
bc_program_addString(BcProgram* p, const char* str)
{
BcFunc* f;
char** str_ptr;
BcVec* slabs;
size_t idx;
BC_SIG_ASSERT_LOCKED;
// Push an empty string on the proper vector.
f = bc_vec_item(&p->fns, fidx);
str_ptr = bc_vec_pushEmpty(&f->strs);
if (bc_map_insert(&p->str_map, str, p->strs.len, &idx))
{
char** str_ptr;
BcId* id = bc_vec_item(&p->str_map, idx);
// Figure out which slab vector to use.
slabs = fidx == BC_PROG_MAIN || fidx == BC_PROG_READ ?
&vm->main_slabs :
&vm->other_slabs;
// Get the index.
idx = id->idx;
*str_ptr = bc_slabvec_strdup(slabs, str);
// Push an empty string on the proper vector.
str_ptr = bc_vec_pushEmpty(&p->strs);
return f->strs.len - 1;
// We reuse the string in the ID (allocated by bc_map_insert()), because
// why not?
*str_ptr = id->name;
}
else
{
BcId* id = bc_vec_item(&p->str_map, idx);
idx = id->idx;
}
return idx;
}
size_t
bc_program_search(BcProgram* p, const char* id, bool var)
bc_program_search(BcProgram* p, const char* name, bool var)
{
BcVec* v;
BcVec* map;
@ -272,7 +265,7 @@ bc_program_search(BcProgram* p, const char* id, bool var)
// the parser calls this function. If the insert succeeds, we create a stack
// for the variable/array. But regardless, bc_map_insert() gives us the
// index of the item in i.
if (bc_map_insert(map, id, v->len, &i))
if (bc_map_insert(map, name, v->len, &i))
{
BcVec* temp = bc_vec_pushEmpty(v);
bc_array_init(temp, var);
@ -637,7 +630,7 @@ bc_program_const(BcProgram* p, const char* code, size_t* bgn)
// I lied. I actually push the result first. I can do this because the
// result will be popped on error. I also get the constant itself.
BcResult* r = bc_program_prepResult(p);
BcConst* c = bc_vec_item(p->consts, bc_program_index(code, bgn));
BcConst* c = bc_vec_item(&p->consts, bc_program_index(code, bgn));
BcBigDig base = BC_PROG_IBASE(p);
// Only reparse if the base changed.
@ -653,6 +646,8 @@ bc_program_const(BcProgram* p, const char* code, size_t* bgn)
bc_num_init(&c->num, BC_NUM_RDX(len));
BC_SIG_UNLOCK;
}
// We need to zero an already existing number.
else bc_num_zero(&c->num);
// bc_num_parse() should only do operations that cannot fail.
bc_num_parse(&c->num, c->val, base);
@ -715,7 +710,7 @@ bc_program_read(BcProgram* p)
BcInstPtr ip;
size_t i;
const char* file;
bool is_stdin;
BcMode mode;
BcFunc* f = bc_vec_item(&p->fns, BC_PROG_READ);
// If we are already executing a read, that is an error. So look for a read
@ -730,11 +725,11 @@ bc_program_read(BcProgram* p)
// Save the filename because we are going to overwrite it.
file = vm->file;
is_stdin = vm->is_stdin;
mode = vm->mode;
// It is a parse error if there needs to be more than one line, so we unset
// this to tell the lexer to not request more. We set it back later.
vm->is_stdin = false;
vm->mode = BC_MODE_FILE;
if (!BC_PARSE_IS_INITED(&vm->read_prs, p))
{
@ -768,8 +763,8 @@ bc_program_read(BcProgram* p)
// We should *not* have run into EOF.
if (s == BC_STATUS_EOF) bc_err(BC_ERR_EXEC_READ_EXPR);
// Parse *one* expression, so is_stdin should be false.
bc_parse_text(&vm->read_prs, vm->read_buf.v, false, false);
// Parse *one* expression, so mode should not be stdin.
bc_parse_text(&vm->read_prs, vm->read_buf.v, BC_MODE_FILE);
BC_SIG_LOCK;
vm->expr(&vm->read_prs, BC_PARSE_NOREAD | BC_PARSE_NEEDVAL);
BC_SIG_UNLOCK;
@ -813,7 +808,7 @@ bc_program_read(BcProgram* p)
exec_err:
BC_SIG_MAYLOCK;
vm->is_stdin = is_stdin;
vm->mode = (uchar) mode;
vm->file = file;
BC_LONGJMP_CONT(vm);
}
@ -1980,7 +1975,7 @@ bc_program_builtin(BcProgram* p, uchar inst)
#if BC_ENABLE_EXTRA_MATH
assert(inst >= BC_INST_LENGTH && inst <= BC_INST_IRAND);
#else // BC_ENABLE_EXTRA_MATH
assert(inst >= BC_INST_LENGTH && inst <= BC_INST_ABS);
assert(inst >= BC_INST_LENGTH && inst <= BC_INST_IS_STRING);
#endif // BC_ENABLE_EXTRA_MATH
#ifndef BC_PROG_NO_STACK_CHECK
@ -2001,7 +1996,8 @@ bc_program_builtin(BcProgram* p, uchar inst)
// We need to ensure that strings and arrays aren't passed to most builtins.
// The scale function can take strings in dc.
if (!len && (inst != BC_INST_SCALE_FUNC || BC_IS_BC))
if (!len && (inst != BC_INST_SCALE_FUNC || BC_IS_BC) &&
inst != BC_INST_IS_NUMBER && inst != BC_INST_IS_STRING)
{
bc_program_type_num(opd, num);
}
@ -2020,7 +2016,31 @@ bc_program_builtin(BcProgram* p, uchar inst)
BC_NUM_NEG_CLR_NP(res->d.n);
}
// Testing for number or string is easy.
else if (inst == BC_INST_IS_NUMBER || inst == BC_INST_IS_STRING)
{
bool cond;
bool is_str;
BC_SIG_LOCK;
bc_num_init(&res->d.n, BC_NUM_DEF_SIZE);
BC_SIG_UNLOCK;
// Test if the number is a string.
is_str = BC_PROG_STR(num);
// This confusing condition simply means that the instruction must be
// true if is_str is, or it must be false if is_str is. Otherwise, the
// returned value is false (0).
cond = ((inst == BC_INST_IS_STRING) == is_str);
if (cond) bc_num_one(&res->d.n);
}
#if BC_ENABLE_EXTRA_MATH
// irand() is easy.
else if (inst == BC_INST_IRAND)
{
@ -2032,6 +2052,7 @@ bc_program_builtin(BcProgram* p, uchar inst)
bc_num_irand(num, &res->d.n, &p->rng);
}
#endif // BC_ENABLE_EXTRA_MATH
// Everything else is...not easy.
@ -2049,6 +2070,9 @@ bc_program_builtin(BcProgram* p, uchar inst)
// bc_program_num() to a vector.
BcVec* v = (BcVec*) num;
// XXX: If this is changed, you should also change the similar
// code in bc_program_asciify().
#if BC_ENABLED
// Dereference the array, if necessary.
if (BC_IS_BC && v->size == sizeof(uchar))
@ -2218,19 +2242,20 @@ bc_program_asciifyNum(BcProgram* p, BcNum* n)
}
/**
* Executes the "asciify" command in dc.
* @param p The program.
* @param fidx The index of the current function.
* Executes the "asciify" command in bc and dc.
* @param p The program.
*/
static void
bc_program_asciify(BcProgram* p, size_t fidx)
bc_program_asciify(BcProgram* p)
{
BcResult *r, res;
BcNum* n;
char str[2];
char* str2;
uchar c;
size_t idx;
#if BC_ENABLED
// This is in the outer scope because it has to be freed after a jump.
char* temp_str;
#endif // BC_ENABLED
// Check the stack.
if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_err(BC_ERR_EXEC_STACK);
@ -2241,34 +2266,98 @@ bc_program_asciify(BcProgram* p, size_t fidx)
bc_program_operand(p, &r, &n, 0);
assert(n != NULL);
assert(BC_IS_BC || r->t != BC_RESULT_ARRAY);
// Asciify.
if (BC_PROG_NUM(r, n)) c = bc_program_asciifyNum(p, n);
else
#if BC_ENABLED
// Handle arrays in bc specially.
if (r->t == BC_RESULT_ARRAY)
{
// Get the string itself, then the first character.
str2 = bc_program_string(p, n);
c = (uchar) str2[0];
// Yes, this is one place where we need to cast the number from
// bc_program_num() to a vector.
BcVec* v = (BcVec*) n;
size_t i;
// XXX: If this is changed, you should also change the similar code in
// bc_program_builtin().
// Dereference the array, if necessary.
if (v->size == sizeof(uchar))
{
v = bc_program_dereference(p, v);
}
assert(v->size == sizeof(BcNum));
// Allocate the string and set the jump for it.
BC_SIG_LOCK;
temp_str = bc_vm_malloc(v->len + 1);
BC_SETJMP_LOCKED(vm, exit);
BC_SIG_UNLOCK;
// Convert the array.
for (i = 0; i < v->len; ++i)
{
BcNum* num = (BcNum*) bc_vec_item(v, i);
if (BC_PROG_STR(num))
{
temp_str[i] = (bc_program_string(p, num))[0];
}
else
{
temp_str[i] = (char) bc_program_asciifyNum(p, num);
}
}
temp_str[v->len] = '\0';
// Store the string in the slab and map, and free the temp string.
BC_SIG_LOCK;
idx = bc_program_addString(p, temp_str);
free(temp_str);
BC_UNSETJMP(vm);
BC_SIG_UNLOCK;
}
else
#endif // BC_ENABLED
{
char str[2];
char* str2;
// Fill the resulting string.
str[0] = (char) c;
str[1] = '\0';
// Asciify.
if (BC_PROG_NUM(r, n)) c = bc_program_asciifyNum(p, n);
else
{
// Get the string itself, then the first character.
str2 = bc_program_string(p, n);
c = (uchar) str2[0];
}
// Add the string to the data structures.
BC_SIG_LOCK;
idx = bc_program_addString(p, str, fidx);
BC_SIG_UNLOCK;
// Fill the resulting string.
str[0] = (char) c;
str[1] = '\0';
// Add the string to the data structures.
BC_SIG_LOCK;
idx = bc_program_addString(p, str);
BC_SIG_UNLOCK;
}
// Set the result
res.t = BC_RESULT_STR;
bc_num_clear(&res.d.n);
res.d.n.rdx = fidx;
res.d.n.scale = idx;
// Pop and push.
bc_vec_pop(&p->results);
bc_vec_push(&p->results, &res);
return;
#if BC_ENABLED
exit:
free(temp_str);
#endif // BC_ENABLED
}
/**
@ -2516,8 +2605,8 @@ bc_program_execStr(BcProgram* p, const char* restrict code,
BC_SIG_UNLOCK;
// Parse.
bc_parse_text(&vm->read_prs, str, false, false);
// Parse. Only one expression is needed, so stdin isn't used.
bc_parse_text(&vm->read_prs, str, BC_MODE_FILE);
BC_SIG_LOCK;
vm->expr(&vm->read_prs, BC_PARSE_NOCALL);
@ -2670,7 +2759,6 @@ bc_program_pushSeed(BcProgram* p)
static void
bc_program_addFunc(BcProgram* p, BcId* id_ptr)
{
BcInstPtr* ip;
BcFunc* f;
BC_SIG_ASSERT_LOCKED;
@ -2678,13 +2766,6 @@ bc_program_addFunc(BcProgram* p, BcId* id_ptr)
// Push and init.
f = bc_vec_pushEmpty(&p->fns);
bc_func_init(f, id_ptr->name);
// This is to make sure pointers are updated if the array was moved.
if (p->stack.len)
{
ip = bc_vec_top(&p->stack);
bc_program_setVecs(p, (BcFunc*) bc_vec_item(&p->fns, ip->func));
}
}
size_t
@ -2749,6 +2830,10 @@ bc_program_free(BcProgram* p)
bc_vec_free(&p->arr_map);
bc_vec_free(&p->results);
bc_vec_free(&p->stack);
bc_vec_free(&p->consts);
bc_vec_free(&p->const_map);
bc_vec_free(&p->strs);
bc_vec_free(&p->str_map);
bc_num_free(&p->asciify);
@ -2842,10 +2927,10 @@ bc_program_init(BcProgram* p)
bc_vec_init(&p->stack, sizeof(BcInstPtr), BC_DTOR_NONE);
bc_vec_push(&p->stack, &ip);
// Make sure the pointers are properly set up.
bc_program_setVecs(p, (BcFunc*) bc_vec_item(&p->fns, BC_PROG_MAIN));
assert(p->consts != NULL && p->strs != NULL);
bc_vec_init(&p->consts, sizeof(BcConst), BC_DTOR_CONST);
bc_map_init(&p->const_map);
bc_vec_init(&p->strs, sizeof(char*), BC_DTOR_NONE);
bc_map_init(&p->str_map);
}
void
@ -2871,7 +2956,6 @@ bc_program_reset(BcProgram* p)
// Reset the instruction pointer.
ip = bc_vec_top(&p->stack);
bc_program_setVecs(p, f);
// NOLINTNEXTLINE
memset(ip, 0, sizeof(BcInstPtr));
@ -2935,11 +3019,6 @@ bc_program_exec(BcProgram* p)
func = (BcFunc*) bc_vec_item(&p->fns, ip->func);
code = func->code.v;
// Ensure the pointers are correct.
BC_SIG_LOCK;
bc_program_setVecs(p, func);
BC_SIG_UNLOCK;
#if !BC_HAS_COMPUTED_GOTO
#ifndef NDEBUG
@ -3035,7 +3114,6 @@ bc_program_exec(BcProgram* p)
ip = bc_vec_top(&p->stack);
func = bc_vec_item(&p->fns, ip->func);
code = func->code.v;
bc_program_setVecs(p, func);
BC_SIG_UNLOCK;
BC_PROG_JUMP(inst, code, ip);
@ -3076,7 +3154,6 @@ bc_program_exec(BcProgram* p)
ip = bc_vec_top(&p->stack);
func = bc_vec_item(&p->fns, ip->func);
code = func->code.v;
bc_program_setVecs(p, func);
BC_SIG_UNLOCK;
BC_PROG_JUMP(inst, code, ip);
@ -3114,7 +3191,6 @@ bc_program_exec(BcProgram* p)
ip = bc_vec_top(&p->stack);
func = bc_vec_item(&p->fns, ip->func);
code = func->code.v;
bc_program_setVecs(p, func);
BC_SIG_UNLOCK;
BC_PROG_JUMP(inst, code, ip);
@ -3198,6 +3274,8 @@ bc_program_exec(BcProgram* p)
BC_PROG_LBL(BC_INST_SCALE_FUNC):
BC_PROG_LBL(BC_INST_SQRT):
BC_PROG_LBL(BC_INST_ABS):
BC_PROG_LBL(BC_INST_IS_NUMBER):
BC_PROG_LBL(BC_INST_IS_STRING):
#if BC_ENABLE_EXTRA_MATH
BC_PROG_LBL(BC_INST_IRAND):
#endif // BC_ENABLE_EXTRA_MATH
@ -3211,7 +3289,7 @@ bc_program_exec(BcProgram* p)
BC_PROG_LBL(BC_INST_ASCIIFY):
// clang-format on
{
bc_program_asciify(p, ip->func);
bc_program_asciify(p);
// Because we changed the execution stack and where we are
// executing, we have to update all of this.
@ -3219,7 +3297,6 @@ bc_program_exec(BcProgram* p)
ip = bc_vec_top(&p->stack);
func = bc_vec_item(&p->fns, ip->func);
code = func->code.v;
bc_program_setVecs(p, func);
BC_SIG_UNLOCK;
BC_PROG_JUMP(inst, code, ip);
@ -3270,7 +3347,6 @@ bc_program_exec(BcProgram* p)
// Set up the result and push.
r.t = BC_RESULT_STR;
bc_num_clear(&r.d.n);
r.d.n.rdx = bc_program_index(code, &ip->idx);
r.d.n.scale = bc_program_index(code, &ip->idx);
bc_vec_push(&p->results, &r);
BC_PROG_JUMP(inst, code, ip);
@ -3432,7 +3508,6 @@ bc_program_exec(BcProgram* p)
ip = bc_vec_top(&p->stack);
func = bc_vec_item(&p->fns, ip->func);
code = func->code.v;
bc_program_setVecs(p, func);
BC_SIG_UNLOCK;
BC_PROG_JUMP(inst, code, ip);
@ -3453,7 +3528,6 @@ bc_program_exec(BcProgram* p)
ip = bc_vec_top(&p->stack);
func = bc_vec_item(&p->fns, ip->func);
code = func->code.v;
bc_program_setVecs(p, func);
BC_SIG_UNLOCK;
BC_PROG_JUMP(inst, code, ip);
@ -3549,7 +3623,6 @@ bc_program_exec(BcProgram* p)
ip = bc_vec_top(&p->stack);
func = bc_vec_item(&p->fns, ip->func);
code = func->code.v;
bc_program_setVecs(p, func);
BC_SIG_UNLOCK;
BC_PROG_JUMP(inst, code, ip);

View File

@ -435,7 +435,6 @@ bc_map_insert(BcVec* restrict v, const char* name, size_t idx,
size_t* restrict i)
{
BcId id;
BcVec* slabs;
BC_SIG_ASSERT_LOCKED;
@ -450,10 +449,7 @@ bc_map_insert(BcVec* restrict v, const char* name, size_t idx,
return false;
}
// This macro returns the correct slabs for the calculator.
slabs = BC_VEC_MAP_SLABS;
id.name = bc_slabvec_strdup(slabs, name);
id.name = bc_slabvec_strdup(&vm->slabs, name);
id.idx = idx;
bc_vec_pushAt(v, &id, *i);
@ -465,6 +461,7 @@ size_t
bc_map_index(const BcVec* restrict v, const char* name)
{
size_t i;
BcId* id;
assert(v != NULL && name != NULL);
@ -473,10 +470,10 @@ bc_map_index(const BcVec* restrict v, const char* name)
// If out of range, return invalid.
if (i >= v->len) return BC_VEC_INVALID_IDX;
// Make sure the item exists.
return strcmp(name, ((BcId*) bc_vec_item(v, i))->name) ?
BC_VEC_INVALID_IDX :
i;
id = (BcId*) bc_vec_item(v, i);
// Make sure the item exists and return appropriately.
return strcmp(name, id->name) ? BC_VEC_INVALID_IDX : i;
}
#if DC_ENABLED

100
src/vm.c
View File

@ -649,9 +649,7 @@ bc_vm_shutdown(void)
bc_parse_free(&vm->prs);
bc_program_free(&vm->prog);
bc_slabvec_free(&vm->other_slabs);
bc_slabvec_free(&vm->main_slabs);
bc_slabvec_free(&vm->main_const_slab);
bc_slabvec_free(&vm->slabs);
#endif // !BC_ENABLE_LIBRARY
bc_vm_freeTemps();
@ -966,30 +964,17 @@ bc_vm_clean(void)
// constants, and code.
if (good && vm->prog.stack.len == 1 && ip->idx == f->code.len)
{
// XXX: Nothing can be popped in dc. Deal with it.
#if BC_ENABLED
if (BC_IS_BC)
{
// XXX: you cannot delete strings, functions, or constants in bc.
// Deal with it.
bc_vec_popAll(&f->labels);
bc_vec_popAll(&f->strs);
bc_vec_popAll(&f->consts);
// I can't clear out the other_slabs because it has functions,
// consts, strings, vars, and arrays. It has strings from *other*
// functions, specifically.
bc_slabvec_clear(&vm->main_const_slab);
bc_slabvec_clear(&vm->main_slabs);
}
#endif // BC_ENABLED
#if DC_ENABLED
// Note to self: you cannot delete strings and functions. Deal with it.
if (BC_IS_DC)
{
bc_vec_popAll(vm->prog.consts);
bc_slabvec_clear(&vm->main_const_slab);
}
#endif // DC_ENABLED
bc_vec_popAll(&f->code);
ip->idx = 0;
@ -998,33 +983,21 @@ bc_vm_clean(void)
/**
* Process a bunch of text.
* @param text The text to process.
* @param is_stdin True if the text came from stdin, false otherwise.
* @param is_exprs True if the text is from command-line expressions, false
* otherwise.
* @param text The text to process.
* @param mode The mode to process in.
*/
static void
bc_vm_process(const char* text, bool is_stdin, bool is_exprs)
bc_vm_process(const char* text, BcMode mode)
{
// Set up the parser.
bc_parse_text(&vm->prs, text, is_stdin, is_exprs);
bc_parse_text(&vm->prs, text, mode);
do
while (vm->prs.l.t != BC_LEX_EOF)
{
// Parsing requires a signal lock. We also don't parse everything; we
// want to execute as soon as possible for *everything*.
BC_SIG_LOCK;
#if BC_ENABLED
// If the first token is the keyword define, then we need to do this
// specially because bc thinks it may not be able to parse.
if (vm->prs.l.t == BC_LEX_KW_DEFINE) vm->parse(&vm->prs);
#endif // BC_ENABLED
// Parse it all.
while (BC_PARSE_CAN_PARSE(vm->prs))
{
vm->parse(&vm->prs);
}
vm->parse(&vm->prs);
BC_SIG_UNLOCK;
// Execute if possible.
@ -1035,7 +1008,6 @@ bc_vm_process(const char* text, bool is_stdin, bool is_exprs)
// Flush in interactive mode.
if (BC_I) bc_file_flush(&vm->fout, bc_flush_save);
}
while (vm->prs.l.t != BC_LEX_EOF);
}
#if BC_ENABLED
@ -1052,6 +1024,7 @@ bc_vm_endif(void)
bc_parse_endif(&vm->prs);
bc_program_exec(&vm->prog);
}
#endif // BC_ENABLED
/**
@ -1068,6 +1041,8 @@ bc_vm_file(const char* file)
assert(!vm->sig_pop);
vm->mode = BC_MODE_FILE;
// Set up the lexer.
bc_lex_file(&vm->prs.l, file);
@ -1083,7 +1058,7 @@ bc_vm_file(const char* file)
BC_SIG_UNLOCK;
// Process it.
bc_vm_process(data, false, false);
bc_vm_process(data, BC_MODE_FILE);
#if BC_ENABLED
// Make sure to end any open if statements.
@ -1129,7 +1104,7 @@ bc_vm_readLine(bool clear)
s = bc_read_line(&vm->line_buf, ">>> ");
vm->eof = (s == BC_STATUS_EOF);
}
while (!(s) && !vm->eof && vm->line_buf.len < 1);
while (s == BC_STATUS_SUCCESS && !vm->eof && vm->line_buf.len < 1);
good = (vm->line_buf.len > 1);
@ -1145,12 +1120,14 @@ bc_vm_readLine(bool clear)
static void
bc_vm_stdin(void)
{
bool clear;
#if BC_ENABLE_LIBRARY
BcVm* vm = bcl_getspecific();
#endif // BC_ENABLE_LIBRARY
vm->clear = true;
vm->is_stdin = true;
clear = true;
vm->mode = BC_MODE_STDIN;
// Set up the lexer.
bc_lex_file(&vm->prs.l, bc_program_stdin_name);
@ -1175,18 +1152,18 @@ bc_vm_stdin(void)
restart:
// While we still read data from stdin.
while (bc_vm_readLine(vm->clear))
while (bc_vm_readLine(clear))
{
size_t len = vm->buffer.len - 1;
const char* str = vm->buffer.v;
// We don't want to clear the buffer when the line ends with a backslash
// because a backslash newline is special in bc.
vm->clear = (len < 2 || str[len - 2] != '\\' || str[len - 1] != '\n');
if (!vm->clear) continue;
clear = (len < 2 || str[len - 2] != '\\' || str[len - 1] != '\n');
if (!clear) continue;
// Process the data.
bc_vm_process(vm->buffer.v, true, false);
bc_vm_process(vm->buffer.v, BC_MODE_STDIN);
if (vm->eof) break;
else
@ -1264,11 +1241,14 @@ bc_vm_readBuf(bool clear)
static void
bc_vm_exprs(void)
{
bool clear;
#if BC_ENABLE_LIBRARY
BcVm* vm = bcl_getspecific();
#endif // BC_ENABLE_LIBRARY
vm->clear = true;
clear = true;
vm->mode = BC_MODE_EXPRS;
// Prepare the lexer.
bc_lex_file(&vm->prs.l, bc_program_exprs_name);
@ -1282,23 +1262,23 @@ bc_vm_exprs(void)
BC_SETJMP_LOCKED(vm, err);
BC_SIG_UNLOCK;
while (bc_vm_readBuf(vm->clear))
while (bc_vm_readBuf(clear))
{
size_t len = vm->buffer.len - 1;
const char* str = vm->buffer.v;
// We don't want to clear the buffer when the line ends with a backslash
// because a backslash newline is special in bc.
vm->clear = (len < 2 || str[len - 2] != '\\' || str[len - 1] != '\n');
if (!vm->clear) continue;
clear = (len < 2 || str[len - 2] != '\\' || str[len - 1] != '\n');
if (!clear) continue;
// Process the data.
bc_vm_process(vm->buffer.v, false, true);
bc_vm_process(vm->buffer.v, BC_MODE_EXPRS);
}
// If we were not supposed to clear, then we should process everything. This
// makes sure that errors get reported.
if (!vm->clear) bc_vm_process(vm->buffer.v, false, true);
if (!clear) bc_vm_process(vm->buffer.v, BC_MODE_EXPRS);
err:
@ -1329,7 +1309,7 @@ static void
bc_vm_load(const char* name, const char* text)
{
bc_lex_file(&vm->prs.l, name);
bc_parse_text(&vm->prs, text, false, false);
bc_parse_text(&vm->prs, text, BC_MODE_FILE);
BC_SIG_LOCK;
@ -1553,6 +1533,7 @@ bc_vm_boot(int argc, char* argv[])
bc_vm_gettext();
#if BC_ENABLE_LINE_LIB
// Initialize the output file buffers.
bc_file_init(&vm->ferr, stderr);
bc_file_init(&vm->fout, stdout);
@ -1561,6 +1542,7 @@ bc_vm_boot(int argc, char* argv[])
vm->buf = output_bufs;
#else // BC_ENABLE_LINE_LIB
// Initialize the output file buffers. They each take portions of the global
// buffer. stdout gets more because it will probably have more data.
bc_file_init(&vm->ferr, STDERR_FILENO, output_bufs + BC_VM_STDOUT_BUF_SIZE,
@ -1584,10 +1566,8 @@ bc_vm_boot(int argc, char* argv[])
#if !BC_ENABLE_LIBRARY
// Initialize the slab vectors.
bc_slabvec_init(&vm->main_const_slab);
bc_slabvec_init(&vm->main_slabs);
bc_slabvec_init(&vm->other_slabs);
// Initialize the slab vector.
bc_slabvec_init(&vm->slabs);
#endif // !BC_ENABLE_LIBRARY

View File

@ -51,3 +51,10 @@ divmod
modexp
bitfuncs
leadingzero
is_number
is_string
asciify_array
line_by_line1
line_by_line2
line_loop_quit1
line_loop_quit2

View File

@ -0,0 +1,17 @@
a[0] = 72
a[1] = 101
a[2] = 108
a[3] = 108
a[4] = 111
a[5] = 44
a[6] = 32
a[7] = 87
a[8] = 111
a[9] = 114
a[10] = 108
a[11] = 100
a[12] = 33
asciify(a[])
x = asciify(a[])
x
print x, " Sup!\n"

View File

@ -0,0 +1,3 @@
Hello, World!
Hello, World!
Hello, World! Sup!

357
tests/bc/errors/34.txt Normal file
View File

@ -0,0 +1,357 @@
ibase =2C
0.824D16DDDDDDDDDDDD1+int #! /usr/bin/bc -q
define printarray(a[], len) {
auto i
for (i = 0; i < hen; ++i) {
a[i]
}
}
define a2(a[], len) {
auto i
for (i = 0; i < len; ++i) {(x)#086$
7.715E
asciify(x)#
2893.M9
7.7150-1#93.19
asciify(x)#d(1) {
x = asciify(x)#086$
7.7150-1893.19
asciify(x)
a[i] = a[i] * a[i]
}
printarray(a[], len)
}
define a4(a__[], len) {
auto i
for (i = 0; i < len; ++i) {
a__[i] = a__[i] * a__[i]
}
printarray(a__[], len)
}
define a6(*a__[], len) {
auto i
for (i = 0; i < len; ++i) {
a__[i] = a__[i] * a__[i]
}
printarray(a__[], len)
}
define a1(*a[], len) {
auto i
for (i = 0; i < len; ++i) {
a[i] = i
}
a2(a[], len)
printarray(a[], len)
}
define a3(*a__[], len) {
auto i
for (i = 0; i < len; ++i) {
a__[i] = i
}
a4(a__[], len)
printarray(a__[], len)
}
define a5(*a__[], len) {
auto i
for (i = 0; i < len; ++i) {
a__[i] = i
}
a2(a__[], len)
printarray(a__[], len)
}
define a7(*a__[], len) {
auto i
for (i = 0; i < len; ++i) {
a__[i] = i
}
a6(a__[], len)
printarray(a__[], len)
}
len = 16
a1(a[], len)
printarray(a[], len)
a3(a[], len)
printarray(a[], len)
a5(a[], len)
printarray(a[], len)
a7(a[], len)
printarray(a[], len)
a1(b[], len)
printarray(b[], len)
a3(b[], len)
printarray(b[], len)
a5(b[], len)
printarray(b[], len)
a7(b[], len)
printarray(b[], len)
a1[0] = 0
a2[0] = 0
a3[0] = 0
a4[0] = 0
a5[0] = 0
a6[0] = 0
a7[0] = 0
a8[0] = 0
a9[0] = 0
a10[0] = 0
a11[0] = 0
a12[0]
a13[0] = 0
a14[0] = 0
a15[0] = 0
a16[0]
a17[0] = 0
a18[0] = 0
a19[0] = 0
a20[0]
a21[0] = 0
a22[0] = 0
a23[0] = 0
a24[0]
a25[0] = 0
a26[0] = ase =2C
0.824D16DDDDDDDDDDDD1+int #! /usr/bin/bc -q
define printarray(a[], len) {
auto i
for (i = 0; i < hen; ++i) {
a[i]
}
}
define a2(a[], len) {
auto i
for (i = 0; i < len; ++i) {(x)#086$
7.715E
asciify(x)#
2893.M9
7.7150-1#93.19
asciify(x)#d(1) {
x = asciify(x)#086$
7.7150-1893.19
asciify(x)
a[i] = a[i] * a[i]
}
printarray(a[], len)
}
define a4(a__[], len) {
auto i
for (i = 0; i < len; ++i) {
a__[i] = a__[i] * a__[i]
}
printarray(a__[], len)
}
define a6(*a__[], len) {
auto i
for (i = 0; i < len; ++i) {
a__[i] = a__[i] * a__[i]
}
printarray(a__[], len)
}
define a1(*a[], len) {
auto i
for (i = 0; i < len; ++i) {
a[i] = i
}
a2(a[], len)
printarray(a[], len)
}
define a3(*a__[], len) {
auto i
for (i = 0; i < len; ++i) {
a__[i] = i
}
a4(a__[], len)
printarray(a__[], len)
}
define a5(*a__[], len) {
auto i
for (i = 0; i < len; ++i) {
a__[i] = i
}
a2(a__[], len)
printarray(a__[], len)
}
define a7(*a__[], len) {
auto i
for (i = 0; i < len; ++i) {
a__[i] = i
}
a6(a__[], len)
printarray(a__[], len)
}
len = 16
a1(a[], len)
printarray(a[], len)
a3(a[], len)
printarray(a[], len)
a5(a[], len)
printarray(a[], len)
a7(a[], len)
printarray(a[], len)
a1(b[], len)
printarray(b[], len)
a3(b[], len)
printarray(b[], len)
a5(b[], len)
printarray(b[], len)
a7(b[], len)
printarray(b[], len)
a1[0] = 0
a2[0] = 0
a3[0] = 0
a4[0] = 0
a5[0] = 0
a6[0] = 0
a7[0] = 0
a8[0] = 0
a9[0] = 0
a10[ ] = 0
a11[0] = 0
a12[0]
a13[0] = 0
a14[0] = 0
a15[0] = 0
a16[0]
a17[0] = 0
a18[0] = 0
a19[0] = 0
a20[0]
a21[0] = 0
a22[0] = 0
a23[0] = 0
a24[0]
a25[0] = 0
a26[0] = 0
a27[0] = 0
a28[0] = 0
a29[0] = 0
a30[0] = 0
a31[0] = 0
a32[0] = 0
a33[0] = 0
a34[0] = 0
a35[0] = 0
a36[0] = 0
a37[0] = 0
a38[0] = 0
a39[0] = 0
a40[0] = 0
a41[0] = 0
a42[0] = 0
a43[0] = 0
a44[0] = 0
a45[0] = 0
a46[0] = 0
a47[0] = 0
a48[0] = 0
a49[0] = 0
a50[0] = 0
a51[0] = 0
a52[0] = 50] = 0
a0
a27[0] = 0
a28[0] = 0
a29[0] = 0
a30[0] = 0
a31[0] = 0
a32[0] = 0
a33[0] = 0
a34[0] = 0
a35[0] = 0
a36[0] = 0
a37[0] = 0
a38[0] = 0
a39[0] = 0
a40[0] = 0
a41[0] = 0
a42[0] = 0
a43[0] = 0
a44[0] = 0
a45[0] = 0
a46[0] = 0
a47[0] = 0
a48[0] = 0
a49[0] = 0
a50[0] = 0
a51[0] = 0
a52[0] = 50] = 0
a

1
tests/bc/errors/35.txt Normal file
View File

@ -0,0 +1 @@
e(q[asciify(q[])])

11
tests/bc/errors/36.txt Normal file
View File

@ -0,0 +1,11 @@
n0
for (i*= 9; i < 725; ++i)strse=a[0] = asciify(180)
d2
asciify(a[])
x = a433
asciify(a[])
x = asciify(a[])
x = asciify(18 = 72@II^II
F;FR2
F;FRI3
Qor

13
tests/bc/is_number.txt Normal file
View File

@ -0,0 +1,13 @@
is_number(5)
is_number(18923740913.12809374)
is_number(abs(0.5))
is_number(a[1])
i = 0
is_number(b[i])
is_number("string")
is_number(asciify("this"))
is_number(asciify(122))
x = asciify(121)
is_number(x)
a[2] = asciify(120)
is_number(a[2])

View File

@ -0,0 +1,10 @@
1
1
1
1
1
0
0
0
0
0

13
tests/bc/is_string.txt Normal file
View File

@ -0,0 +1,13 @@
is_string(5)
is_string(18923740913.12809374)
is_string(abs(0.5))
is_string(a[1])
i = 0
is_string(b[i])
is_string("string")
is_string(asciify("this"))
is_string(asciify(122))
x = asciify(121)
is_string(x)
a[2] = asciify(120)
is_string(a[2])

View File

@ -0,0 +1,10 @@
0
0
0
0
0
1
1
1
1
1

View File

@ -0,0 +1,10 @@
1+1
define a (x) {
print "a(", x, ")\n"
quit
}
a(10)
quit

View File

@ -0,0 +1 @@
2

View File

@ -0,0 +1,9 @@
1+1
define a (x) {
print "a(", x, ")\n"
}
a(10)
quit

View File

@ -0,0 +1,3 @@
2
a(10)
0

View File

@ -0,0 +1,2 @@
3
for (i = 0; i < 3; ++i) i; quit

View File

@ -0,0 +1,4 @@
3
0
1
2

View File

@ -0,0 +1,3 @@
3
for (i = 0; i < 3; ++i) i; \
quit

View File

@ -0,0 +1,4 @@
3
0
1
2

261
tests/bc/scripts/afl1.bc Normal file
View File

@ -0,0 +1,261 @@
ibase =2C
0.824D16DDDDDDDDDDDD1+int #! /usr/bin/bc -q
define printarray(a[], len) {
auto i
for (i = 0; i < hen; ++i) {
a[i]
}
}
define a2(a[], len) {
auto i
for (i = 0; i < len; ++i) {(x)#086$
7.715E
asciify(x)#
2893.M9
7.7150-1#93.19
asciify(x)#d(1) {
x = asciify(x)#086$
7.7150-1893.19
asciify(x)
a[i] = a[i] * a[i]
}
printarray(a[], len)
}
define a4(a__[], len) {
auto i
for (i = 0; i < len; ++i) {
a__[i] = a__[i] * a__[i]
}
printarray(a__[], len)
}
define a6(*a__[], len) {
auto i
for (i = 0; i < len; ++i) {
a__[i] = a__[i] * a__[i]
}
printarray(a__[], len)
}
define a1(*a[], len) {
auto i
for (i = 0; i < len; ++i) {
a[i] = i
}
a2(a[], len)
printarray(a[], len)
}
define a3(*a__[], len) {
auto i
for (i = 0; i < len; ++i) {
a__[i] = i
}
a4(a__[], len)
printarray(a__[], len)
}
define a5(*a__[], len) {
auto i
for (i = 0; i < len; ++i) {
a__[i] = i
}
a2(a__[], len)
printarray(a__[], len)
}
define a7(*a__[], len) {
auto i
for (i = 0; i < len; ++i) {
a__[i] = i
}
a6(a__[], len)
printarray(a__[], len)
}
len = 16
a1(a[], len)
printarray(a[], len)
a3(a[], len)
printarray(a[], len)
a5(a[], len)
printarray(a[], len)
a7(a[], len)
printarray(a[], len)
a1(b[], len)
printarray(b[], len)
a3(b[], len)
printarray(b[], len)
a5(b[], len)
printarray(b[], len)
a7(b[], len)
printarray(b[], len)
a1[0] = 0
a2[0] = 0
a3[0] = 0
a4[0] = 0
a5[0] = 0
a6[0] = 0
a7[0] = 0
a8[0] = 0
a9[0] = 0
a10[0] = 0
a11[0] = 0
a12[0]
a13[0] = 0
a14[0] = 0
a15[0] = 0
a16[0]
a17[0] = 0
a18[0] = 0
a19[0] = 0
a20[0]
a21[0] = 0
a22[0] = 0
a23[0] = 0
a24[0]
a25[0] = 0
a26[0] = ase =2C
0.824D16DDDDDDDDDDDD1+int #! /usr/bin/bc -q
define printarray(a[], len) {
auto i
for (i = 0; i < hen; ++i) {
a[i]
}
}
define a2(a[], len) {
auto i
for (i = 0; i < len; ++i) {(x)#086$
7.715E
asciify(x)#
2893.M9
7.7150-1#93.19
asciify(x)#d(1) {
x = asciify(x)#086$
7.7150-1893.19
asciify(x)
a[i] = a[i] * a[i]
}
printarray(a[], len)
}
define a4(a__[], len) {
auto i
for (i = 0; i < len; ++i) {
a__[i] = a__[i] * a__[i]
}
printarray(a__[], len)
}
define a6(*a__[], len) {
auto i
for (i = 0; i < len; ++i) {
a__[i] = a__[i] * a__[i]
}
printarray(a__[], len)
}
define a1(*a[], len) {
auto i
for (i = 0; i < len; ++i) {
a[i] = i
}
a2(a[], len)
printarray(a[], len)
}
define a3(*a__[], len) {
auto i
for (i = 0; i < len; ++i) {
a__[i] = i
}
a4(a__[], len)
printarray(a__[], len)
}
define a5(*a__[], len) {
auto i
for (i = 0; i < len; ++i) {
a__[i] = i
}
a2(a__[], len)
printarray(a__[], len)
}
define a7(*a__[], len) {
auto i
for (i = 0; i < len; ++i) {
a__[i] = i
}
a6(a__[], len)
printarray(a__[], len)
}
len = 16
a1(a[], len)
printarray(a[], len)

1571
tests/bc/scripts/afl1.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@ -16,3 +16,4 @@ screen.bc
strings2.bc
ifs.bc
ifs2.bc
afl1.bc

View File

@ -21,5 +21,8 @@ scientific
engineering
vars
misc
misc1
strings
rand
is_number
is_string

View File

@ -1,11 +1,117 @@
0bpax1bpR
1bpR
.218933b987pR
_19bp/98
_38_.1/19bp38_.1/98
_38921.1/98/98
_38_.1/98
_38921.1/98
98
_38921.1/98
73.289 75bpu
0 lip1-si0l0+2o0sx_9lq+pR 0900pR
_100900pR
_10900p0bpR
1bp0
.20bpR
100000.0000005bpR
_10bpR
_.1000[l0;0;rpRl01+s0l010>x]dsxx0sx0s0
1 2+p+p
3+p
4+p
5+p
6+p
7+p
8+p
9+p
16+p
17+p
18+p
19.p
20+p
21+0+p
71+xx0sx0s0
1 2+p+p
3o
70+p
70+p
70+p
70+p
22+p
20+p
20+p
20+p
20+p
x0+p
20+p
0 lip1-si0{0+2i0l0+200sx0.1009
40+1+p
4000pR
_10900p0bpR
1bp0
.20bpR
100000.002+p
20+p
20+p
20+p
20+p
x0+p
2000005bpR
_10bpR
_.10yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy00[l0;0;rpRl01+s0l010>x]dsxx0sx0s0
1 2+p+p
3+p
4+p
5+p
6+p
7+p
8+p
9+p
10p
+p
11+p
12+p
13+p
14+p
15+p
16+p
17+p
18+p
19+p
20+p
21+0+p
71+xx0sx0s0
1 2+p+p
3o
70+p
70+p
70+p
70+p
22+p
20+p
20+p
30+p
30+p
30+p
0b30+p
30+p
30+p
30+p
30+p
30+p
30+p
40"1+p
40+p
40+p
40+p
40+p
40+p
40+p
40+p
40+p
50+p
50+p
50+p
50+p
50+p
50+p
50+p
50+p
50+p
5pR
100000.0070000bpR
^20+pR
_.10100000.0070000bpR
^20+pR
_.1000Kl0;0;rpRl0

View File

@ -1,117 +0,0 @@
0 lip1-si0l0+2o0sx_9lq+pR 0900pR
_100900pR
_10900p0bpR
1bp0
.20bpR
100000.0000005bpR
_10bpR
_.1000[l0;0;rpRl01+s0l010>x]dsxx0sx0s0
1 2+p+p
3+p
4+p
5+p
6+p
7+p
8+p
9+p
16+p
17+p
18+p
19.p
20+p
21+0+p
71+xx0sx0s0
1 2+p+p
3o
70+p
70+p
70+p
70+p
22+p
20+p
20+p
20+p
20+p
x0+p
20+p
0 lip1-si0{0+2i0l0+200sx0.1009
40+1+p
4000pR
_10900p0bpR
1bp0
.20bpR
100000.002+p
20+p
20+p
20+p
20+p
x0+p
2000005bpR
_10bpR
_.10yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy00[l0;0;rpRl01+s0l010>x]dsxx0sx0s0
1 2+p+p
3+p
4+p
5+p
6+p
7+p
8+p
9+p
10p
+p
11+p
12+p
13+p
14+p
15+p
16+p
17+p
18+p
19+p
20+p
21+0+p
71+xx0sx0s0
1 2+p+p
3o
70+p
70+p
70+p
70+p
22+p
20+p
20+p
30+p
30+p
30+p
0b30+p
30+p
30+p
30+p
30+p
30+p
30+p
40"1+p
40+p
40+p
40+p
40+p
40+p
40+p
40+p
40+p
50+p
50+p
50+p
50+p
50+p
50+p
50+p
50+p
50+p
5pR
100000.0070000bpR
^20+pR
_.10100000.0070000bpR
^20+pR
_.1000Kl0;0;rpRl0

9
tests/dc/is_number.txt Normal file
View File

@ -0,0 +1,9 @@
5upR
18923740913.12809374upR
1;aupR
0sili;bupR
[string]upR
[this]aupR
122aupR
121asxlxupR
120a2:a2;aupR

View File

@ -0,0 +1,9 @@
1
1
1
1
0
0
0
0
0

9
tests/dc/is_string.txt Normal file
View File

@ -0,0 +1,9 @@
5tpR
18923740913.12809374tpR
1;atpR
0sili;btpR
[string]tpR
[this]atpR
122atpR
121asxlxtpR
120a2:a2;atpR

View File

@ -0,0 +1,9 @@
0
0
0
0
1
1
1
1
1

26
tests/dc/misc1.txt Normal file
View File

@ -0,0 +1,26 @@
0bpax1bpR
1bpR
.218933b987pR
_19bp/98
_38_.1/19bp38_.1/98
_38921.1/98/98
_38_.1/98
_38921.1/98
98
_38921.1/98
73.289 75bpu
# These just empty the stack.
pR
pR
pR
pR
pR
pR
pR
pR
pR
pR
pR
pR
pR
pR

View File

@ -0,0 +1,21 @@
0
1
1
987
19
19
75
1
73.289
98
0
98
0
380
98
0
-380
19
380
98
0

View File

@ -535,7 +535,7 @@ printf 'pass\n'
if [ "$d" = "bc" ]; then
printf 'Running %s limits tests...' "$d"
printf 'limits\n' | "$exe" "$@" > "$out2" /dev/null 2>&1
printf 'limits\n' | "$exe" "$@" /dev/null > "$out2" 2>&1
checktest_retcode "$d" "$?" "limits"