diff --git a/doc_src/math.txt b/doc_src/math.txt index 994f15152..a22b0e6ea 100644 --- a/doc_src/math.txt +++ b/doc_src/math.txt @@ -1,9 +1,8 @@ - \section math math - Perform mathematics calculations \subsection math-synopsis Synopsis \fish{synopsis} -math EXPRESSION +math [-sN] EXPRESSION \endfish \subsection math-description Description @@ -12,9 +11,26 @@ math EXPRESSION For a description of the syntax supported by math, see the manual for the bc program. Keep in mind that parameter expansion takes place on any expressions before they are evaluated. This can be very useful in order to perform calculations involving shell variables or the output of command substitutions, but it also means that parenthesis have to be escaped. +The following options are available: + +- `-sN` Sets the scale of the result. `N` must be an integer and defaults to zero. This simply sets bc's `scale` variable to the provided value. Note that you cannot put a space between `-s` and `N`. + +\subsection return-values Return Values + +If invalid options or no expression is provided the return `status` is two. If the expression is invalid the return `status` is three. If bc returns a result of `0` (literally, not `0.0` or similar variants) the return `status` is one otherwise it's zero. \subsection math-example Examples `math 1+1` outputs 2. `math $status-128` outputs the numerical exit status of the last command minus 128. + +`math 10 / 6` outputs `1`. + +`math -s0 10.0 / 6.0` outputs `1`. + +`math -s3 10 / 6` outputs `1.666`. + +\subsection math-cautions Cautions + +Note that the modulo operator (`x % y`) is not well defined for floating point arithmetic. The `bc` command produces a nonsensical result rather than emit an error and fail in that case. It doesn't matter if the arguments are integers; e.g., `10 % 4`. You'll still get an incorrect result. Do not use the `-sN` flag with N greater than zero if you want sensible answers when using the modulo operator. diff --git a/share/functions/math.fish b/share/functions/math.fish index c190ec631..ed638c695 100644 --- a/share/functions/math.fish +++ b/share/functions/math.fish @@ -1,23 +1,42 @@ - function math --description "Perform math calculations in bc" - if count $argv >/dev/null - switch $argv[1] - case -h --h --he --hel --help - __fish_print_help math - return 0 - end + set -l scale 0 # default is integer arithmetic - # Stitch lines together manually - # we can't rely on BC_LINE_LENGTH because some systems don't have a bc version "new" enough - set -l out (echo $argv | bc | string replace -r '\\\\$' '' | string join '') - test -z "$out"; and return 1 - echo $out - switch $out - case 0 - return 1 - end - return 0 - end - return 2 + if set -q argv[1] + switch $argv[1] + case '-s*' # user wants to specify the scale of the output + set scale (string replace -- '-s' '' $argv[1]) + if not string match -q -r '^\d+$' "$scale" + echo 'Expected an integer to follow -s' >&2 + return 2 # missing argument is an error + end + set -e argv[1] + case -h --h --he --hel --help + __fish_print_help math + return 0 + end + end + + if not set -q argv[1] + return 2 # no arguments is an error + end + + # Stitch lines together manually. We can't rely on BC_LINE_LENGTH because some systems don't + # have a new enough version of bc. + set -l out (echo "scale=$scale; $argv" | bc | string replace -r '\\\\$' '' | string join '') + switch "$out" + case '' + # No output indicates an error occurred. + return 3 + + case 0 + # For historical reasons a zero result translates to a failure status. + echo 0 + return 1 + + case '*' + # For historical reasons a non-zero result translates to a success status. + echo $out + return 0 + end end diff --git a/tests/math.err b/tests/math.err new file mode 100644 index 000000000..e69de29bb diff --git a/tests/math.in b/tests/math.in new file mode 100644 index 000000000..d8cb50922 --- /dev/null +++ b/tests/math.in @@ -0,0 +1,9 @@ +math 3 / 2 +math 10/6 +math -s0 10 / 6 +math -s3 10/6 +math '10 % 6' +math -s0 '10 % 6' +math '23 % 7' +math -s6 '5 / 3 * 0.3' +true diff --git a/tests/math.out b/tests/math.out new file mode 100644 index 000000000..0a46b6a56 --- /dev/null +++ b/tests/math.out @@ -0,0 +1,8 @@ +1 +1 +1 +1.666 +4 +4 +2 +.499999 diff --git a/tests/math.status b/tests/math.status new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/tests/math.status @@ -0,0 +1 @@ +0