calc: Improve handling of invalid 'calc-string-maximum-character'

Previously, if 'calc-string-maximum-character' wasn't a valid
character 'math-vector-is-string' would throw an error in the
comparison, leading to an incomplete display of the stack and a
cryptic error message.  Instead, have 'math-vector-is-string'
return nil, which effectively disables the display of strings.
Refines feature introduced in bug#78528.
* doc/misc/calc.texi (Customizing Calc): Update description of
behavior for invalid 'calc-string-maximum-character'.
* lisp/calc/calccomp.el (math-vector-is-string): Return nil when
'calc-string-maximum-character' doesn't represent a character.
* test/lisp/calc/calc-tests.el (calc-math-vector-is-string): Correct
and simplify tests.
This commit is contained in:
Jacob S. Gordon
2026-01-09 16:20:00 -05:00
committed by Eli Zaretskii
parent 5020d89104
commit bd96450a09
3 changed files with 32 additions and 71 deletions

View File

@@ -35694,10 +35694,9 @@ The variable @code{calc-string-maximum-character} is the maximum value
of a vector's elements for @code{calc-display-strings}, @code{string},
and @code{bstring} to display the vector as a string. This maximum
@emph{must} represent a character, i.e. it's a non-negative integer less
than or equal to @code{(max-char)} or @code{0x3FFFFF}. Any negative
value effectively disables the display of strings, and for values larger
than @code{0x3FFFFF} the display acts as if the maximum were
@code{0x3FFFFF}. Some natural choices (and their resulting ranges) are:
than or equal to @code{(max-char)} or @code{0x3FFFFF}. Any value not
representing a character effectively disables the display of strings.
Some natural choices (and their resulting ranges) are:
@itemize
@item

View File

@@ -911,17 +911,19 @@
Elements of A must either be a character (see `characterp') or a complex
number with only a real character part, each with a value less than or
equal to the custom variable `calc-string-maximum-character'."
(while (and (setq a (cdr a))
(or (and (characterp (car a))
(<= (car a)
calc-string-maximum-character))
(and (eq (car-safe (car a)) 'cplx)
(characterp (nth 1 (car a)))
(eq (nth 2 (car a)) 0)
(<= (nth 1 (car a))
calc-string-maximum-character)))))
(null a))
equal to the value of `calc-string-maximum-character'. Return nil if
`calc-string-maximum-character' is not a character."
(when (characterp calc-string-maximum-character)
(while (and (setq a (cdr a))
(or (and (characterp (car a))
(<= (car a)
calc-string-maximum-character))
(and (eq (car-safe (car a)) 'cplx)
(characterp (nth 1 (car a)))
(eq (nth 2 (car a)) 0)
(<= (nth 1 (car a))
calc-string-maximum-character)))))
(null a)))
(defconst math-vector-to-string-chars '( ( ?\" . "\\\"" )
( ?\\ . "\\\\" )

View File

@@ -882,18 +882,8 @@ An existing calc stack is reused, otherwise a new one is created."
(ert-deftest calc-math-vector-is-string ()
"Test `math-vector-is-string' with varying `calc-string-maximum-character'.
All tests operate on both an integer vector and the corresponding
complex vector. The sets covered are:
1. `calc-string-maximum-character' is a valid character. The last case
with `0x3FFFFF' is borderline, as integers above it will not make it
past the `characterp' test.
2. `calc-string-maximum-character' is negative, so the test always fails.
3. `calc-string-maximum-character' is above `(max-char)', so only the
first `characterp' test is active.
4. `calc-string-maximum-character' has an invalid type, which triggers
an error in the comparison."
When `calc-string-maximum-character' isnt a valid character,
`math-vector-is-string' should return nil for all vectors."
(cl-flet* ((make-vec (lambda (contents) (append (list 'vec) contents)))
(make-cplx (lambda (x) (list 'cplx x 0)))
(make-cplx-vec (lambda (contents)
@@ -902,50 +892,20 @@ an error in the comparison."
(dolist (maxchar '(#x7F #xFF #x10FFFF #x3FFFFD #x3FFFFF))
(let* ((calc-string-maximum-character maxchar)
(small-chars (number-sequence (- maxchar 2) maxchar))
(large-chars (number-sequence maxchar (+ maxchar 2)))
(small-real-vec (make-vec small-chars))
(large-real-vec (make-vec large-chars))
(small-cplx-vec (make-cplx-vec small-chars))
(large-cplx-vec (make-cplx-vec large-chars)))
(should (math-vector-is-string small-real-vec))
(should-not (math-vector-is-string large-real-vec))
(should (math-vector-is-string small-cplx-vec))
(should-not (math-vector-is-string large-cplx-vec))))
;; 2: calc-string-maximum-character is negative
(let* ((maxchar -1)
(calc-string-maximum-character maxchar)
(valid-contents (number-sequence 0 2))
(invalid-contents (number-sequence (- maxchar 2) maxchar))
(valid-real-vec (make-vec valid-contents))
(invalid-real-vec (make-vec invalid-contents))
(valid-cplx-vec (make-cplx-vec valid-contents))
(invalid-cplx-vec (make-cplx-vec invalid-contents)))
(should-not (math-vector-is-string valid-real-vec))
(should-not (math-vector-is-string invalid-real-vec))
(should-not (math-vector-is-string valid-cplx-vec))
(should-not (math-vector-is-string invalid-cplx-vec)))
;; 3: calc-string-maximum-character is larger than (max-char)
(let* ((maxchar (+ (max-char) 3))
(calc-string-maximum-character maxchar)
(valid-chars (number-sequence (- (max-char) 2) (max-char)))
(invalid-chars (number-sequence (1+ (max-char)) maxchar))
(valid-real-vec (make-vec valid-chars))
(invalid-real-vec (make-vec invalid-chars))
(valid-cplx-vec (make-cplx-vec valid-chars))
(invalid-cplx-vec (make-cplx-vec invalid-chars)))
(should (math-vector-is-string valid-real-vec))
(should-not (math-vector-is-string invalid-real-vec))
(should (math-vector-is-string valid-cplx-vec))
(should-not (math-vector-is-string invalid-cplx-vec)))
;; 4: calc-string-maximum-character has the wrong type
(let* ((calc-string-maximum-character "wrong type")
(contents (number-sequence 0 2))
(real-vec (make-vec contents))
(cplx-vec (make-cplx-vec contents)))
(should-error (math-vector-is-string real-vec)
:type 'wrong-type-argument)
(should-error (math-vector-is-string cplx-vec)
:type 'wrong-type-argument))))
(large-chars (number-sequence maxchar (+ maxchar 2))))
(should (math-vector-is-string (make-vec small-chars)))
(should-not (math-vector-is-string (make-vec large-chars)))
(should (math-vector-is-string (make-cplx-vec small-chars)))
(should-not (math-vector-is-string (make-cplx-vec large-chars)))))
;; 2: calc-string-maximum-character is not a valid character
(dolist (maxchar (list -1 (1+ (max-char)) "wrong type"))
(let ((calc-string-maximum-character maxchar)
(valid-chars (number-sequence 0 2))
(invalid-chars (number-sequence -2 -1)))
(should-not (math-vector-is-string (make-vec valid-chars)))
(should-not (math-vector-is-string (make-vec invalid-chars)))
(should-not (math-vector-is-string (make-cplx-vec valid-chars)))
(should-not (math-vector-is-string (make-cplx-vec invalid-chars)))))))
(ert-deftest calc-inhibit-startup-message ()
"Test user option `calc-inhibit-startup-message'."