changeset 29076:fa2cdef14442

maint: merge stable to default.
author Rik <rik@octave.org>
date Thu, 19 Nov 2020 13:08:00 -0800
parents a5e267bc2930 (diff) dc3ee9616267 (current diff)
children b85f72ec844a
files scripts/sparse/eigs.m
diffstat 1321 files changed, 32402 insertions(+), 14342 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Thu Nov 19 13:05:51 2020 -0800
+++ b/NEWS	Thu Nov 19 13:08:00 2020 -0800
@@ -1,269 +1,195 @@
-Summary of important user-visible changes for version 6.1.0 (2020-08-26):
-------------------------------------------------------------------------
+Summary of important user-visible changes for version 7 (yyyy-mm-dd):
+----------------------------------------------------------------------
 
 ### General improvements
 
-- The `intersect`, `setdiff`, `setxor`, `union`, and `unique` functions
-  accept a new sorting option `"stable"` which will return output values
-  in the same order as the input, rather than in ascending order.
+- Many functions in Octave can be called in a command form---no
+parentheses for invocation and no return argument assignment---or in a
+functional form---parentheses and '=' for assignment of return values.
 
-- Complex RESTful web services can now be accessed by the `webread` and
-  `webwrite` functions alongside with the `weboptions` structure.  One
-  major feature is the support for cookies to enable RESTful
-  communication with the web service.
+    **Command Form Example**
 
-  Additionally, the system web browser can be opened by the `web`
-  function.
+    `mkdir new_directory`
 
-- The `linspace` function now produces symmetrical sequences when the
-  endpoints are symmetric.  This is more intuitive and also compatible
-  with recent changes made in Matlab R2019b.
+    **Function Form Example**
 
-- The underlying algorithm of the `rand` function has been changed.
-  For single precision outputs, the algorithm has been fixed so that it
-  produces values strictly in the range (0, 1).  Previously, it could
-  occasionally generate the right endpoint value of 1 (See bug #41742).
-  In addition, the new implementation uses a uniform interval between
-  floating point values in the range (0, 1) rather than targeting a
-  uniform density (# of random integers / length along real number
-  line).
+    `status = mkdir ("new_directory")`
 
-- Numerical integration has been improved.  The `quadv` function has
-  been re-written so that it can compute integrands of periodic
-  functions.  At the same time, performance is better with ~3.5X fewer
-  function evaluations required.  A bug in `quadgk` that caused complex
-  path integrals specified with `"Waypoints"` to occasionally be
-  calculated in the opposite direction was fixed.
+    Octave now handles errors that occur in a consistent manner.  If
+    called in command form and there is a failure, an error is thrown
+    and a message printed.  If called in functional form, no error or
+    message is printed and the failure is communicated to the programmer
+    via the output status variable.
+
+    The following list of functions have been modified.
 
-- The `edit` function option `"editinplace"` now defaults to `true` and
-  the option `"home"` now defaults to the empty matrix `[]`.  Files will
-  no longer be copied to the user's HOME directory for editing.  The old
-  behavior can be restored by setting `"editinplace"` to `false` and
-  `"home"` to `"~/octave"`.
-
-- The `format` command supports two new options: `uppercase` and
-  `lowercase` (default).  With the default, print a lowercase 'e' for
-  the exponent character in scientific notation and lowercase 'a-f' for
-  the hex digits representing 10-15.  With `uppercase`, print 'E' and
-  'A-F' instead.  The previous uppercase formats, `E` and `G`, no longer
-  control the case of the output.
-
-  Additionally, the `format` command can be called with multiple options
-  for controlling the format, spacing, and case in arbitrary order.
-  For example:
-
-        format long e uppercase loose
+    * `copyfile`
+    * `fcntl`
+    * `fileattrib`
+    * `kill`
+    * `link`
+    * `mkfifo`
+    * `movefile`
+    * `rename`
+    * `rmdir`
+    * `symlink`
+    * `unlink`
 
-  Note, in the case of multiple competing format options the rightmost
-  one is used, and, in case of an error, the previous format remains
-  unchanged.
-
-- L-value references (e.g., increment (++), decrement (--), and all
-  in-place assignment operators (+=, -=, *=, /=, etc.)) are no longer
-  allowed in anonymous functions.
+- Calling a user-defined function with too many inputs or outputs is now
+an error.  The interpreter makes this check automatically.  If a
+function uses varargin then the check is skipped for function inputs,
+and if a function uses varargout then the check is skipped for function
+outputs.  Input validation for functions typically begins with checking
+the number of inputs and outputs match expectations.  Existing code can
+be simplified by removing these checks which are now done by the
+interpreter.  Typically, code blocks like the following can simply be
+deleted.
 
-- New warnings have been added about questionable uses of the colon ':'
-  range operator.  Each has a new warning ID so that it can be disabled
-  if desired.
+        ## Checking number of inputs
+        if (nargin > 2)
+          print_usage ();
+        endif
 
-  >  `Octave:colon-complex-argument`   : when any arg is complex
-  >  `Octave:colon-nonscalar-argument` : when any arg is non-scalar
-
-- The `regexp` and related functions now correctly handle and *require*
-  strings in UTF-8 encoding.  As with any other function that requires
-  strings to be encoded in Octave's native encoding, you can use
-  `native2unicode` to convert from your preferred locale.  For example,
-  the copyright symbol in UTF-8 is `native2unicode (169, "latin1")`.
+        ## Checking number of outputs
+        if (nargout > 1)
+          print_usage ();
+        endif
 
-- The startup file `octaverc` can now be located in the platform
-  dependent location for user local configuration files (e.g.,
-  ${XDG_CONFIG_HOME}/octave/octaverc on Unix-like operating systems or
-  %APPDATA%\octave\octaverc on Windows).
-
-- `pkg describe` now lists dependencies and inverse dependencies
-  (i.e., other installed packages that depend on the package in
-  question).
-
-- `pkg test` now tests all functions in a package.
-
-- When unloading a package, `pkg` now checks if any remaining loaded
-  packages depend on the one to be removed.  If this is the case `pkg`
-  aborts with an explanatory error message.  This behavior can be
-  overridden with the `-nodeps` option.
-
-- The command
+- Binary and hexadecimal constants like `0b101` and `0xDEADBEEF` now
+create integers (unsigned by default) with sizes determined from the
+number of digits present.  For example, `0xff` creates a `uint8` value
+and `0xDEADBEEF` creates a `uint64` value.  You may also use a suffix of
+the form `s8`, `s16`, `s32`, `s64`, `u8`, `u16`, `u32`, or `u64` to
+explicitly specify the data type to use (`u` or `s` to indicate signed
+or unsigned and the number to indicate the integer size).
 
-    dbstop in CLASS at METHOD
-
-  now works to set breakpoints in classdef constructors and methods.
-
-#### Graphics backend
+    Binary constants are limited to 64 binary digits and hexadecimal
+constants are limited to 16 hexadecimal digits with no automatic
+rounding or conversion to floating point values.  Note that this may
+cause problems in existing code.  For example, an expression like
+`[0x1; 0x100; 0x10000]` will be uint8 (because of the rules of
+concatenating integers of different sizes) with the larger values
+truncated (because of the saturation semantics of integer values).  To
+avoid these kinds of problems either: 1) declare the first integer to be
+of the desired size such as `[0x1u32; 0x100; 0x10000]`, or 2) pad
+constants in array expressions with leading zeros so that they use the
+same number of digits for each value such as
+`[0x00_00_01; 0x00_01_00; 0x01_00_00]`.
 
-- The use of Qt4 for graphics and the GUI is deprecated in Octave
-  version 6 and no further bug fixes will be made.  Qt4 support will be
-  removed completely in Octave version 7.
+- As part of GSoC 2020, Abdallah K. Elshamy implemented the
+`jsondecode` and `jsonencode` functions to read and write JSON data.
 
-- The `legend` function has been entirely rewritten.  This fixes a
-  number of historical bugs, and also implements new properties such as
-  `"AutoUpdate"` and `"NumColumns"`.  The gnuplot toolkit---which is no
-  longer actively maintained---still uses the old legend function.
-
-- The `axis` function was updated which resolved 10 bugs affecting
-  axes to which `"equal"` had been applied.
+- By default, the history file is now located at $DATA/octave/history,
+where $DATA is a platform dependent location for (roaming) user data
+files (e.g.  ${XDG_DATA_HOME} or, if that is not set, ~/.local/share on
+Unix-like operating systems or %APPDATA% on Windows).
 
-- Graphic primitives now accept a color property value of `"none"`
-  which is useful when a particular primitive needs to be hidden
-  (for example, the Y-axis of an axes object with `"ycolor" = "none"`)
-  without hiding the entire primitive `"visibility" = "off"`.
+- In debug mode, symbol values are now shown in tooltips when hovering
+variables in the editor panel.
+
+### Graphics backend
 
-- A new property `"FontSmoothing"` has been added to text and axes
-  objects that controls whether anti-aliasing is used during the
-  rendering of characters.  The default is `"on"` which produces smooth,
-  more visually appealing text.
+- Support for Qt4 for both graphics and the GUI has been removed.
 
-- The figure property `"windowscrollwheelfcn"`is now implemented.
-  This makes it possible to provide a callback function to be executed
-  when users manipulate the mouse wheel on a given figure.
-
-- The figure properties `"pointer"`, `"pointershapecdata"`, and
-  `"pointershapehotspot"` are now implemented.  This makes it possible
-  to change the shape of the cursor (pointer in Matlab-speak) displayed
-  in a plot window.
+- The additional property `"contextmenu"` has been added to all graphics
+objects.  It is equivalent to the previously used `"uicontextmenu"`
+property which is hidden now.
 
-- The figure property `"paperpositionmode"` now has the default `"auto"`
-  rather than `"manual"`.  This change is more intuitive and is
-  Matlab compatible.
-
-- The appearance of patterned lines `"LineStyle" = ":"|"--"|"-."` has
-  been improved for small widths (`"LineWidth"` less than 1.5 pixels)
-  which is a common scenario.
-
-- Printing to EPS files now uses a tight bounding box (`"-tight"`
-  argument to print) by default.  This makes more sense for EPS
-  files which are normally embedded within other documents, and is
-  Matlab compatible.  If necessary use the `"-loose"` option to
-  reproduce figures as they appeared in previous versions of Octave.
-
-- The following print devices are no longer officially supported: cdr,
-  corel, aifm, ill, cgm, hpgl, mf and dxf.  A warning will be thrown
-  when using those devices, and the code for supporting those formats
-  will eventually be removed from a future version of Octave.
-
-- The placement of text subscripts and superscripts has been
-  re-engineered and now produces visually attractive results similar to
-  Latex.
+- Additional properties have been added to the `axes` graphics object:
+    * `"alphamap"` (not yet implemented)
+    * `"alphascale"` (not yet implemented)
+    * `"colorscale"` (not yet implemented)
+    * `"fontsizemode"` (not yet implemented)
+    * `"innerposition"` (equivalent to `"position"`)
+    * `"interactions"` (not yet implemented)
+    * `"layout"` (not yet implemented)
+    * `"legend"` (not yet implemented)
+    * `"nextseriesindex"` (read-only, used by `scatter`
+      graphics objects)
+    * `"positionconstraint"` (replacement for `"activepositionproperty"`
+      which is now a hidden property.  No plans for removal.)
+    * `"toolbar"` (not yet implemented)
+    * `"xaxis"` (not yet implemented)
+    * `"yaxis"` (not yet implemented)
+    * `"zaxis"` (not yet implemented)
 
 ### Matlab compatibility
 
-- The function `unique` now returns column index vectors for the second
-  and third outputs.  When duplicate values are present, the default
-  index to return is now the `"first"` occurrence.  The previous Octave
-  behavior, or Matlab behavior from releases prior to R2012b, can be
-  obtained by using the `"legacy"` flag.
-
-- The function `setdiff` with the `"rows"` argument now returns Matlab
-  compatible results.  The previous Octave behavior, or Matlab behavior
-  from releases prior to R2012b, can be obtained by using the `"legacy"`
-  flag.
+- The function `griddata` now implements the "v4" Biharmonic Spline
+Interpolation method.  In adddition, the function now accepts 3-D inputs
+by passing the data to `griddata3`.
 
-- The functions `intersect`, `setxor`, and `union` now accept a
-  `"legacy"` flag which changes the index values (second and third
-  outputs) as well as the orientation of all outputs to match Matlab
-  releases prior to R2012b.
+- Coordinate transformation functions `cart2sph`, `sph2cart`,
+`cart2pol`, and `pol2cart` now accept either row or column vectors for
+coordinate inputs.  A single coordinate matrix with one variable per
+column can still be used as function input, but a single output variable
+will now contain just the first output coordinate, and will no longer
+return the full output coordinate matrix.  Output size matches the size
+of input vectors, or in the case of an input matrix will be column
+vectors with rows corresponding to the input coordinate matrix.
 
-- The function `streamtube` is Matlab compatible and plots tubes along
-  streamlines which are scaled by the vector field divergence. The
-  Octave-only extension `ostreamtube` can be used to visualize the flow
-  expansion and contraction of the vector field due to the local
-  crossflow divergence.
-
-- The interpreter now supports handles to nested functions.
+- The function `dec2bin` and `dec2hex` now support negative numbers.
 
-- The graphics properties `"LineWidth"` and `"MarkerSize"` are now
-  measured in points, *not* pixels.  Compared to previous versions
-  of Octave, some lines and markers will appear 4/3 larger.
-
-- The meta.class property "SuperClassList" has been renamed
-  "Superclasslist" for Matlab compatibility.  The original name will
-  exist as an alias until Octave version 8.1.
+- The function `importdata` now produces more compatible results when
+the file contains a 2-D text matrix.
 
-- Inline functions created by the function `inline` are now of type
-  "inline" when interrogated with the `class` function.  In previous
-  versions of Octave, the class returned was "function_handle".  This
-  change is Matlab compatible.  Inline functions are deprecated in
-  both Matlab and Octave and support may eventually be removed.
-  Anonymous functions can be used to replace all instances of inline
-  functions.
+- `uicontrol` objects now fully implement the "Off" and "Inactive"
+values of the "Enable" property.  When the value is "Off", no
+interaction with the object occurs and the `uicontrol` changes color
+(typically to gray) to indicate it is disabled.  When the value is
+"Inactive", the object appears normally (no change in color), but it is
+not possible to change the value of the object (such as modifying text
+in an `Edit` box or clicking on a `RadioButton`).
 
-- The function `javaaddpath` now prepends new directories to the
-  existing dynamic classpath by default.  To append them instead, use
-  the new `"-end"` argument.  Multiple directories may now be specified
-  in a cell array of strings.
-
-- An undocumented function `gui_mainfcn` has been added, for compatibility
-  with figures created with Matlab's GUIDE.
+- The functions `scatter` and `scatter3` now return a handle to a
+scatter graphics object.  For compatibility, they return an `hggroup` of
+patch graphics objects when the "gnuplot" graphics toolkit is used.  In
+previous versions of Octave, these functions returned an `hggroup` of
+patch graphics objects for all graphics toolkits.
 
-- Several validator functions of type `mustBe*` have been added.  See
-  the list of new functions below.
+- The function `saveas` now defaults to saving in Octave figure format
+(.ofig) rather than PDF (.pdf).
+
+- A new warning ID (`"Octave:unimplemented-matlab-functionality"`) has
+been added which prints a warning when Octave's parser recognizes valid
+Matlab code, but for which Octave does not yet implement the
+functionality.  By default, this warning is enabled.
 
-### Alphabetical list of new functions added in Octave 6
+- The functions `bar` and `barh` now handle stacked negative bar values
+in a Matlab-compatible manner.  Negative values now stack below the zero
+axis independently of a positive value bars in the same stack.
+Previously the negative bars could overlap positive bars depending on
+drawing order.
+
+### Alphabetical list of new functions added in Octave 7
 
-* `auto_repeat_debug_command`
-* `commandhistory`
-* `commandwindow`
-* `filebrowser`
-* `is_same_file`
-* `lightangle`
-* `mustBeFinite`
-* `mustBeGreaterThan`
-* `mustBeGreaterThanOrEqual`
-* `mustBeInteger`
-* `mustBeLessThan`
-* `mustBeLessThanOrEqual`
-* `mustBeMember`
-* `mustBeNegative`
-* `mustBeNonempty`
-* `mustBeNonNan`
-* `mustBeNonnegative`
-* `mustBeNonpositive`
-* `mustBeNonsparse`
-* `mustBeNonzero`
-* `mustBeNumeric`
-* `mustBeNumericOrLogical`
-* `mustBePositive`
-* `mustBeReal`
-* `namedargs2cell`
-* `newline`
-* `ode23s`
-* `ostreamtube`
-* `rescale`
-* `rotx`
-* `roty`
-* `rotz`
-* `stream2`
-* `stream3`
-* `streamline`
-* `streamtube`
-* `uisetfont`
-* `verLessThan`
-* `web`
-* `weboptions`
-* `webread`
-* `webwrite`
-* `workspace`
-
+* `getpixelposition`
+* `endsWith`
+* `jsondecode`
+* `jsonencode`
+* `listfonts`
+* `matlab.net.base64decode`
+* `matlab.net.base64encode`
+* `memory`
+* `ordqz`
+* `rng`
+* `startsWith`
+* `streamribbon`
+* `xtickangle`
+* `ytickangle`
+* `ztickangle`
 
 ### Deprecated functions and properties
 
-The following functions and properties have been deprecated in Octave 6
-and will be removed from Octave 8 (or whatever version is the second
-major release after 6):
+The following functions and properties have been deprecated in Octave 7
+and will be removed from Octave 9 (or whatever version is the second
+major release after 7):
 
 - Functions
 
   Function               | Replacement
   -----------------------|------------------
-  `runtests`             | `oruntests`
+                         |
 
 - Properties
 
@@ -271,51 +197,31 @@
   -----------------|---------------|------------
                    |               |
 
-- The environment variable used by `mkoctfile` for linker flags is now
-  `LDFLAGS` rather than `LFLAGS`.  `LFLAGS` is deprecated, and a warning
-  is emitted if it is used, but it will continue to work.
-
-
 ### Removed functions and properties
 
-The following functions and properties were deprecated in Octave 4.4
-and have been removed from Octave 6.
+The following functions and properties were deprecated in Octave 5
+and have been removed from Octave 7.
 
 - Functions
 
-  Function             | Replacement
-  ---------------------|------------------
-  `chop`               | `sprintf` for visual results
-  `desktop`            | `isguirunning`
-  `tmpnam`             | `tempname`
-  `toascii`            | `double`
-  `java2mat`           | `__java2mat__`
+  Function                 | Replacement
+  -------------------------|------------------
+  `output_max_field_width` | `output_precision`
+  `is_keyword`             | `iskeyword`
 
 - Properties
 
-  Object               | Property                  | Value
-  ---------------------|---------------------------|-----------------------
-  `annotation`         | `edgecolor ("rectangle")` |
-  `axes`               | `drawmode`                |
-  `figure`             | `doublebuffer`            |
-                       | `mincolormap`             |
-                       | `wvisual`                 |
-                       | `wvisualmode`             |
-                       | `xdisplay`                |
-                       | `xvisual`                 |
-                       | `xvisualmode`             |
-  `line`               | `interpreter`             |
-  `patch`              | `interpreter`             |
-  `surface`            | `interpreter`             |
-  `text`               | `fontweight`              | `"demi"` and `"light"`
-  `uibuttongroup`      | `fontweight`              | `"demi"` and `"light"`
-  `uicontrol`          | `fontweight`              | `"demi"` and `"light"`
-  `uipanel`            | `fontweight`              | `"demi"` and `"light"`
-  `uitable`            | `fontweight`              | `"demi"` and `"light"`
-
+  Object           | Property      | Value
+  -----------------|---------------|------------
+  `text`           | `fontangle`   | `"oblique"`
+  `uibuttongroup`  | `fontangle`   | `"oblique"`
+  `uicontrol`      | `fontangle`   | `"oblique"`
+  `uipanel`        | `fontangle`   | `"oblique"`
+  `uitable`        | `fontangle`   | `"oblique"`
 
 ### Old release news
 
+- [Octave 6.x](etc/NEWS.6)
 - [Octave 5.x](etc/NEWS.5)
 - [Octave 4.x](etc/NEWS.4)
 - [Octave 3.x](etc/NEWS.3)
--- a/bootstrap.conf	Thu Nov 19 13:05:51 2020 -0800
+++ b/bootstrap.conf	Thu Nov 19 13:08:00 2020 -0800
@@ -56,6 +56,7 @@
   getrusage
   gettimeofday
   glob
+  intprops
   isatty
   largefile
   link
@@ -117,9 +118,12 @@
   unictype/ctype-upper
   unictype/ctype-xdigit
   unistd
+  unistr/u16-to-u8
+  unistr/u32-to-u8
   unistr/u8-check
   unistr/u8-strmblen
   unistr/u8-strmbtouc
+  unistr/u8-to-u16
   unistr/u8-to-u32
   unlink
   unsetenv
--- a/build-aux/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/build-aux/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -35,6 +35,7 @@
 ### utility rules to aid development
 
 ALL_TEST_FILES = \
+  $(addprefix $(srcdir)/, $(LIBOCTAVE_TST_FILES_SRC)) \
   $(addprefix $(srcdir)/, $(LIBINTERP_TST_FILES_SRC)) \
   $(addprefix $(srcdir)/, $(FCN_FILES_WITH_TESTS)) \
   $(addprefix $(srcdir)/, $(TEST_FILES))
--- a/configure.ac	Thu Nov 19 13:05:51 2020 -0800
+++ b/configure.ac	Thu Nov 19 13:08:00 2020 -0800
@@ -27,7 +27,7 @@
 
 ### Initialize Autoconf
 AC_PREREQ([2.65])
-AC_INIT([GNU Octave], [6.0.93], [https://octave.org/bugs.html], [octave],
+AC_INIT([GNU Octave], [7.0.0], [https://octave.org/bugs.html], [octave],
         [https://www.gnu.org/software/octave/])
 
 ### Declare version numbers
@@ -39,16 +39,16 @@
 ## explains how to update these numbers for release and development
 ## versions.
 
-OCTAVE_MAJOR_VERSION=6
+OCTAVE_MAJOR_VERSION=7
 OCTAVE_MINOR_VERSION=0
-OCTAVE_PATCH_VERSION=93
+OCTAVE_PATCH_VERSION=0
 
 dnl PACKAGE_VERSION is set by the AC_INIT VERSION argument.
 OCTAVE_VERSION="$PACKAGE_VERSION"
 
 OCTAVE_COPYRIGHT="Copyright (C) 2020 The Octave Project Developers."
 
-OCTAVE_RELEASE_DATE="2020-10-23"
+OCTAVE_RELEASE_DATE="2020-08-26"
 
 ## The "API version" is used as a way of checking that interfaces in the
 ## liboctave and libinterp libraries haven't changed in a backwardly
@@ -63,7 +63,7 @@
 dnl FIXME: Since we also set libtool versions for liboctave and libinterp,
 dnl perhaps we should be computing the "api version" from those versions numbers
 dnl in some way instead of setting it independently here.
-OCTAVE_API_VERSION="api-v55"
+OCTAVE_API_VERSION="api-v55+"
 
 AC_SUBST(OCTAVE_MAJOR_VERSION)
 AC_SUBST(OCTAVE_MINOR_VERSION)
@@ -536,20 +536,6 @@
 AC_DEFINE_UNQUOTED(OCTAVE_IDX_TYPE, [$OCTAVE_IDX_TYPE],
   [Define to the type of octave_idx_type (64 or 32 bit signed integer).])
 
-### Enable bounds checking on element references within Octave's array and
-### matrix classes.
-dnl This slows down some operations a bit, so it is turned off by default.
-
-ENABLE_BOUNDS_CHECK=no
-AC_ARG_ENABLE([bounds-check],
-  [AS_HELP_STRING([--enable-bounds-check],
-    [OBSOLETE: use --enable-address-sanitizer-flags instead])],
-  [if test "$enableval" = yes; then ENABLE_BOUNDS_CHECK=yes; fi], [])
-if test $ENABLE_BOUNDS_CHECK = yes; then
-  warn_bounds_check="--enable-bounds-check is obsolete; use --enable-address-sanitizer-flags instead"
-  OCTAVE_CONFIGURE_WARNING([warn_bounds_check])
-fi
-
 ### Check for pthread library
 
 AX_PTHREAD
@@ -1352,6 +1338,39 @@
   ],
   [libpcre], [REQUIRED])
 
+### Check for RapidJSON header only library.
+
+AC_LANG_PUSH(C++)
+AC_CHECK_HEADER([rapidjson/rapidjson.h],
+                [have_rapidjson=yes], [have_rapidjson=no])
+
+if test $have_rapidjson = yes; then
+  AC_DEFINE(HAVE_RAPIDJSON, 1, [Define to 1 if RapidJSON is available.])
+
+  ## Additional check on RapidJSON library that was found
+  AC_CACHE_CHECK([for working PrettyWriter in RapidJSON],
+    [octave_cv_rapidjson_has_prettywriter],
+    [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+      #include <rapidjson/prettywriter.h>
+      ]], [[
+      rapidjson::StringBuffer json;
+      rapidjson::PrettyWriter<rapidjson::StringBuffer, rapidjson::UTF8<>,
+                              rapidjson::UTF8<>, rapidjson::CrtAllocator,
+                              rapidjson::kWriteNanAndInfFlag> writer (json);
+      ]])],
+      [octave_cv_rapidjson_has_prettywriter=yes],
+      [octave_cv_rapidjson_has_prettywriter=no])
+    ])
+  if test $octave_cv_rapidjson_has_prettywriter = yes; then
+    AC_DEFINE(HAVE_RAPIDJSON_PRETTYWRITER, 1,
+      [Define to 1 if the RapidJSON PrettyWriter function is available.])
+  else
+    rapid_json_warning='Older RapidJSON library found.  The "PrettyWriter" option in jsonencode will be disabled.'
+    OCTAVE_CONFIGURE_WARNING([rapid_json_warning])
+  fi
+fi
+AC_LANG_POP([C++])
+
 ### Check for readline library.
 
 OCTAVE_ENABLE_READLINE
@@ -1378,7 +1397,7 @@
   [zlib.h], [gzclearerr])
 
 ## Also define HAVE_ZLIB if libz is found.
-if test -z "$warn_z"; then
+if test -n "$Z_LIBS"; then
   AC_DEFINE(HAVE_ZLIB, 1, [Define to 1 if ZLIB is available.])
 fi
 
@@ -1617,7 +1636,7 @@
 OCTAVE_CHECK_LIB(curl, cURL,
   [cURL library not found.  The ftp objects, urlread, and urlwrite functions will be disabled.],
   [curl/curl.h], [curl_easy_escape])
-if test -z "$warn_curl"; then
+if test -n "$CURL_LIBS"; then
   ## Additional check on cURL library that was found
   AC_CACHE_CHECK([for CURLOPT_DIRLISTONLY in curl/curl.h],
     [octave_cv_curl_has_curlopt_dirlistonly],
@@ -1665,8 +1684,6 @@
     [select library to use for image I/O (options: GraphicsMagick(default) or ImageMagick)])],
   [if test x"$withval" = xno; then
      check_magick=no
-     warn_magick_disabled="--without-magick specified.  The imread, imwrite, and imfinfo functions for reading and writing image files will not be fully functional."
-     OCTAVE_CONFIGURE_WARNING([warn_magick_disabled])
    else
      magick="$withval"
    fi], [magick="GraphicsMagick"])
@@ -1778,8 +1795,6 @@
     [don't use OpenGL libraries, disable OpenGL graphics])],
   [if test x"$withval" = xno; then
      check_opengl=no
-     warn_opengl_disabled="--without-opengl specified.  OpenGL graphics will be disabled."
-     OCTAVE_CONFIGURE_WARNING([warn_opengl_disabled])
    fi])
 
 ## Check for OpenGL library
@@ -1800,7 +1815,6 @@
     [don't use FreeType library, OpenGL graphics will not be fully functional])],
   [if test x"$withval" = xno; then
      check_freetype=no
-     warn_freetype="--without-freetype specified.  OpenGL graphics will not be fully functional."
    fi])
 
 if test $check_freetype = yes; then
@@ -1841,26 +1855,9 @@
   [fontconfig.h fontconfig/fontconfig.h], [FcInit],
   [], [don't use fontconfig library, OpenGL graphics will not be fully functional])
 
-## Check for gl2ps which is required for printing with OpenGL graphics.
-
-AC_CHECK_HEADERS([gl2ps.h],
-  [GL2PS_LIBS="-lgl2ps"],
-  [warn_gl2ps="gl2ps library not found.  Printing of OpenGL graphics will be disabled."])
-
-if test -n "$warn_gl2ps"; then
-  OCTAVE_CONFIGURE_WARNING([warn_gl2ps])
-else
-  save_LIBS="$LIBS"
-  LIBS="$GL2PS_LIBS $LIBS"
-  AC_CHECK_FUNCS([gl2psLineJoin])
-  LIBS="$save_LIBS"
-fi
-
-AC_SUBST(GL2PS_LIBS)
-
 ### GUI/Qt related tests.
 
-QT_VERSIONS="5 4"
+QT_VERSIONS="5"
 
 AC_ARG_WITH([qt],
   [AS_HELP_STRING([--with-qt=VER], [use the Qt major version VER])
@@ -1871,8 +1868,6 @@
      ;;
      no)
        QT_VERSIONS=
-       warn_qt_disabled="--without-qt specified.  The Qt GUI will be disabled."
-       OCTAVE_CONFIGURE_WARNING([warn_qt_disabled])
      ;;
      *)
        QT_VERSIONS="$withval"
@@ -1884,8 +1879,6 @@
   [AS_HELP_STRING([--without-qscintilla], [disable QScintilla editor])],
   [if test x"$withval" = xno; then
      check_qscintilla=no
-     warn_qscintilla_disabled="--without-qscintilla specified.  The GUI editor will be disabled."
-     OCTAVE_CONFIGURE_WARNING([warn_qscintilla_disabled])
    fi])
 
 OCTAVE_CHECK_QT([$QT_VERSIONS])
@@ -2026,6 +2019,25 @@
   opengl_graphics=yes
 fi
 
+## Check for gl2ps which is required for printing with OpenGL graphics.
+
+if test $opengl_graphics = yes; then
+  AC_CHECK_HEADERS([gl2ps.h],
+    [GL2PS_LIBS="-lgl2ps"],
+    [warn_gl2ps="gl2ps library not found.  Printing of OpenGL graphics will be disabled."])
+
+  if test -n "$warn_gl2ps"; then
+    OCTAVE_CONFIGURE_WARNING([warn_gl2ps])
+  else
+    save_LIBS="$LIBS"
+    LIBS="$GL2PS_LIBS $LIBS"
+    AC_CHECK_FUNCS([gl2psLineJoin])
+    LIBS="$save_LIBS"
+  fi
+
+  AC_SUBST(GL2PS_LIBS)
+fi
+
 ### Check for the qrupdate library
 
 dnl No need to adjust FFLAGS because only link is attempted.
@@ -2039,7 +2051,7 @@
   [Fortran 77], [don't use qrupdate, disable QR & Cholesky updating functions])
 
 ## Additional check to see if qrupdate lib found supports LU updates
-if test -z "$warn_qrupdate"; then
+if test -n "$QRUPDATE_LIBS"; then
   AC_CACHE_CHECK([for slup1up in $QRUPDATE_LIBS],
     [octave_cv_func_slup1up],
     [LIBS="$LIBS $QRUPDATE_LIBS"
@@ -2137,7 +2149,7 @@
   [cs${CXSPARSE_TAG}sqr],
   [C++], [don't use CXSparse library, disable some sparse matrix functionality])
 
-if test -z "$warn_cxsparse"; then
+if test -n "$CXSPARSE_LIBS"; then
   ## Additional check for CXSparse version >= 2.2
   if test $octave_cv_lib_cxsparse = yes; then
     OCTAVE_CHECK_CXSPARSE_VERSION_OK
@@ -2230,50 +2242,56 @@
 
 ### Check for SUNDIALS IDA library and header.
 
-save_CPPFLAGS="$CPPFLAGS"
-save_LDFLAGS="$LDFLAGS"
-save_LIBS="$LIBS"
-LIBS="$SUNDIALS_NVECSERIAL_LIBS $KLU_LIBS $BLAS_LIBS $FLIBS $LIBS"
-LDFLAGS="$SUNDIALS_NVECSERIAL_LDFLAGS $KLU_LDFLAGS $BLAS_LDFLAGS $LDFLAGS"
-CPPFLAGS="$SUNDIALS_NVECSERIAL_CPPFLAGS $KLU_CPPFLAGS $BLAS_CPPFLAGS $CPPFLAGS"
-OCTAVE_CHECK_LIB(sundials_ida, [SUNDIALS IDA],
-  [SUNDIALS IDA library not found.  The solvers ode15i and ode15s will be disabled.],
-  [ida/ida.h ida.h], [IDAInit],
-  [], [don't use SUNDIALS IDA library, disable solvers ode15i and ode15s])
-CPPFLAGS="$save_CPPFLAGS"
-LDFLAGS="$save_LDFLAGS"
-LIBS="$save_LIBS"
+if test -n "$SUNDIALS_NVECSERIAL_LIBS"; then
+
+  save_CPPFLAGS="$CPPFLAGS"
+  save_LDFLAGS="$LDFLAGS"
+  save_LIBS="$LIBS"
+  LIBS="$SUNDIALS_NVECSERIAL_LIBS $KLU_LIBS $BLAS_LIBS $FLIBS $LIBS"
+  LDFLAGS="$SUNDIALS_NVECSERIAL_LDFLAGS $KLU_LDFLAGS $BLAS_LDFLAGS $LDFLAGS"
+  CPPFLAGS="$SUNDIALS_NVECSERIAL_CPPFLAGS $KLU_CPPFLAGS $BLAS_CPPFLAGS $CPPFLAGS"
+  OCTAVE_CHECK_LIB(sundials_ida, [SUNDIALS IDA],
+    [SUNDIALS IDA library not found.  The solvers ode15i and ode15s will be disabled.],
+    [ida/ida.h ida.h], [IDAInit],
+    [], [don't use SUNDIALS IDA library, disable solvers ode15i and ode15s])
+  CPPFLAGS="$save_CPPFLAGS"
+  LDFLAGS="$save_LDFLAGS"
+  LIBS="$save_LIBS"
+fi
 
 ### Check for SUNDIALS library features, some required, some optional.
 
-CPPFLAGS="$SUNDIALS_IDA_CPPFLAGS $SUNDIALS_NVECSERIAL_CPPFLAGS $KLU_CPPFLAGS $BLAS_CPPFLAGS $CPPFLAGS"
-LDFLAGS="$SUNDIALS_IDA_LDFLAGS $SUNDIALS_NVECSERIAL_LDFLAGS $KLU_LDFLAGS $BLAS_LDFLAGS $LDFLAGS"
-LIBS="$SUNDIALS_IDA_LIBS $SUNDIALS_NVECSERIAL_LIBS $KLU_LIBS $BLAS_LIBS $FLIBS $LIBS"
-if test -z "$warn_sundials_nvecserial" && test -z "$warn_sundials_ida"; then
-  dnl Any of the following tests could determine that SUNDIALS is incompatible
-  dnl and should be disabled. In that event, they all populate the same
-  dnl variable with appropriate warning messages, and further tests should be
-  dnl skipped if a warning message has already been generated that SUNDIALS is
-  dnl disabled.
-  warn_sundials_disabled=
-  if test -z "$warn_sundials_disabled"; then
-    OCTAVE_CHECK_SUNDIALS_COMPATIBLE_API
+if test -n "$SUNDIALS_IDA_LIBS" && test -n "$SUNDIALS_NVECSERIAL_LIBS"; then
+
+  CPPFLAGS="$SUNDIALS_IDA_CPPFLAGS $SUNDIALS_NVECSERIAL_CPPFLAGS $KLU_CPPFLAGS $BLAS_CPPFLAGS $CPPFLAGS"
+  LDFLAGS="$SUNDIALS_IDA_LDFLAGS $SUNDIALS_NVECSERIAL_LDFLAGS $KLU_LDFLAGS $BLAS_LDFLAGS $LDFLAGS"
+  LIBS="$SUNDIALS_IDA_LIBS $SUNDIALS_NVECSERIAL_LIBS $KLU_LIBS $BLAS_LIBS $FLIBS $LIBS"
+  if test -z "$warn_sundials_nvecserial" && test -z "$warn_sundials_ida"; then
+    dnl Any of the following tests could determine that SUNDIALS is incompatible
+    dnl and should be disabled. In that event, they all populate the same
+    dnl variable with appropriate warning messages, and further tests should be
+    dnl skipped if a warning message has already been generated that SUNDIALS is
+    dnl disabled.
+    warn_sundials_disabled=
+    if test -z "$warn_sundials_disabled"; then
+      OCTAVE_CHECK_SUNDIALS_COMPATIBLE_API
+    fi
+    if test -z "$warn_sundials_disabled"; then
+      OCTAVE_CHECK_SUNDIALS_SIZEOF_REALTYPE
+    fi
+    if test -z "$warn_sundials_disabled"; then
+      OCTAVE_CHECK_SUNDIALS_SUNLINSOL_DENSE
+    fi
+    dnl The following tests determine whether certain optional features are
+    dnl present in the SUNDIALS libraries, but will not disable using SUNDIALS.
+    if test -z "$warn_sundials_disabled"; then
+      OCTAVE_CHECK_SUNDIALS_SUNLINSOL_KLU
+    fi
   fi
-  if test -z "$warn_sundials_disabled"; then
-    OCTAVE_CHECK_SUNDIALS_SIZEOF_REALTYPE
-  fi
-  if test -z "$warn_sundials_disabled"; then
-    OCTAVE_CHECK_SUNDIALS_SUNLINSOL_DENSE
-  fi
-  dnl The following tests determine whether certain optional features are
-  dnl present in the SUNDIALS libraries, but will not disable using SUNDIALS.
-  if test -z "$warn_sundials_disabled"; then
-    OCTAVE_CHECK_SUNDIALS_SUNLINSOL_KLU
-  fi
+  CPPFLAGS="$save_CPPFLAGS"
+  LDFLAGS="$save_LDFLAGS"
+  LIBS="$save_LIBS"
 fi
-CPPFLAGS="$save_CPPFLAGS"
-LDFLAGS="$save_LDFLAGS"
-LIBS="$save_LIBS"
 
 dnl Define this way instead of with an #if in oct-conf-post.h so that
 dnl the build features script will get the correct value.
@@ -2282,36 +2300,36 @@
 dnl How can we do a better job here?  Do we need to disable sundials
 dnl any tests fail, or can we fix __ode15__.cc so that it still partially
 dnl works when some things are missing (for example, KLU)?
-if test -n "$SUNDIALS_IDA_LIBS" \
-    && test -n "$SUNDIALS_NVECSERIAL_LIBS" \
-    && test "x$octave_cv_sundials_sunlinsol_dense" = xyes \
-    && test "x$octave_cv_sundials_realtype_is_double" = xyes \
-    && test "x$octave_have_sundials_compatible_api" = xyes; then
-  AC_DEFINE(HAVE_SUNDIALS, 1, [Define to 1 if SUNDIALS is available.])
-
-  ## Collections of options needed to build with SUNDIALS and its dependencies.
-  SUNDIALS_XCPPFLAGS="$SUNDIALS_IDA_CPPFLAGS $SUNDIALS_SUNLINSOLKLU_CPPFLAGS $SUNDIALS_NVECSERIAL_CPPFLAGS $KLU_CPPFLAGS"
-  SUNDIALS_XLDFLAGS="$SUNDIALS_IDA_LDFLAGS $SUNDIALS_SUNLINSOLKLU_LDFLAGS $SUNDIALS_NVECSERIAL_LDFLAGS $KLU_LDFLAGS"
-  SUNDIALS_XLIBS="$SUNDIALS_IDA_LIBS $SUNDIALS_SUNLINSOLKLU_LIBS $SUNDIALS_NVECSERIAL_LIBS $KLU_LIBS"
-else
-  SUNDIALS_IDA_CPPFLAGS=
-  SUNDIALS_IDA_LDFLAGS=
-  SUNDIALS_IDA_LIBS=
-  SUNDIALS_SUNLINSOLKLU_CPPFLAGS=
-  SUNDIALS_SUNLINSOLKLU_LDFLAGS=
-  SUNDIALS_SUNLINSOLKLU_LIBS=
-  SUNDIALS_NVECSERIAL_CPPFLAGS=
-  SUNDIALS_NVECSERIAL_LDFLAGS=
-  SUNDIALS_NVECSERIAL_LIBS=
-  SUNDIALS_XCPPFLAGS=
-  SUNDIALS_XLDFLAGS=
-  SUNDIALS_XLIBS=
-  dnl Emit a fallback warning message in case SUNDIALS has been disabled for
-  dnl some reason that hasn't already generated one of these known warnings.
-  if test -z "$warn_sundials_nvecserial" && test -z "$warn_sundials_ida" \
-      && test -z "$warn_sundials_disabled"; then
-    warn_sundials_disabled="SUNDIALS libraries are missing some feature.  The solvers ode15i and ode15s will be disabled."
-    OCTAVE_CONFIGURE_WARNING([warn_sundials_disabled])
+if test -n "$SUNDIALS_IDA_LIBS" && test -n "$SUNDIALS_NVECSERIAL_LIBS"; then
+  if test "x$octave_cv_sundials_sunlinsol_dense" = xyes \
+      && test "x$octave_cv_sundials_realtype_is_double" = xyes \
+      && test "x$octave_have_sundials_compatible_api" = xyes; then
+    AC_DEFINE(HAVE_SUNDIALS, 1, [Define to 1 if SUNDIALS is available.])
+
+    ## Options needed to build with SUNDIALS and its dependencies.
+    SUNDIALS_XCPPFLAGS="$SUNDIALS_IDA_CPPFLAGS $SUNDIALS_SUNLINSOLKLU_CPPFLAGS $SUNDIALS_NVECSERIAL_CPPFLAGS $KLU_CPPFLAGS"
+    SUNDIALS_XLDFLAGS="$SUNDIALS_IDA_LDFLAGS $SUNDIALS_SUNLINSOLKLU_LDFLAGS $SUNDIALS_NVECSERIAL_LDFLAGS $KLU_LDFLAGS"
+    SUNDIALS_XLIBS="$SUNDIALS_IDA_LIBS $SUNDIALS_SUNLINSOLKLU_LIBS $SUNDIALS_NVECSERIAL_LIBS $KLU_LIBS"
+  else
+    SUNDIALS_IDA_CPPFLAGS=
+    SUNDIALS_IDA_LDFLAGS=
+    SUNDIALS_IDA_LIBS=
+    SUNDIALS_SUNLINSOLKLU_CPPFLAGS=
+    SUNDIALS_SUNLINSOLKLU_LDFLAGS=
+    SUNDIALS_SUNLINSOLKLU_LIBS=
+    SUNDIALS_NVECSERIAL_CPPFLAGS=
+    SUNDIALS_NVECSERIAL_LDFLAGS=
+    SUNDIALS_NVECSERIAL_LIBS=
+    SUNDIALS_XCPPFLAGS=
+    SUNDIALS_XLDFLAGS=
+    SUNDIALS_XLIBS=
+    dnl Emit a fallback warning message in case SUNDIALS has been disabled for
+    dnl some reason that hasn't already generated one of these known warnings.
+    if test -z "$warn_sundials_nvecserial" && test -z "$warn_sundials_ida" \
+        && test -z "$warn_sundials_disabled"; then
+      warn_sundials_disabled="SUNDIALS libraries are missing some feature.  The solvers ode15i and ode15s will be disabled."
+      OCTAVE_CONFIGURE_WARNING([warn_sundials_disabled])
+    fi
   fi
 fi
 
@@ -2332,7 +2350,7 @@
    OCTAVE_CHECK_LIB_ARPACK_OK_1(
      [AC_DEFINE(HAVE_ARPACK, 1, [Define to 1 if ARPACK is available.])],
      [warn_arpack="ARPACK library found, but does not seem to work properly; disabling eigs function"])
-   if test -z "$warn_arpack"; then
+   if test -n "$ARPACK_LIBS"; then
      OCTAVE_CHECK_LIB_ARPACK_OK_2([],
        [AC_MSG_WARN([ARPACK library found, but is buggy; upgrade library (>= v3.3.0) for better results])])
    fi
@@ -2609,6 +2627,7 @@
      warn_docs="building documentation disabled; make dist will fail."
      OCTAVE_CONFIGURE_WARNING([warn_docs])
    fi], [])
+
 if test $ENABLE_DOCS = yes; then
   if test $opengl_graphics = no || test "$have_qt_opengl_offscreen" = no; then
     if test -n "$warn_gnuplot"; then
@@ -2627,6 +2646,7 @@
   AC_DEFINE(ENABLE_DOCS, 1,
     [Define to 1 to build Octave documentation files.])
 fi
+
 AM_CONDITIONAL([AMCOND_BUILD_DOCS], [test $ENABLE_DOCS = yes])
 
 AM_CONDITIONAL([AMCOND_BUILD_QT_DOCS],
@@ -3010,7 +3030,7 @@
   libgui/mk-default-qt-settings.sh
   liboctave/external/mk-f77-def.sh
   liboctave/mk-version-h.sh
-  libinterp/corefcn/mk-mxarray-h.sh
+  libinterp/corefcn/mk-mxtypes-h.sh
   build-aux/subst-config-vals.sh
   build-aux/subst-cross-config-vals.sh
   build-aux/subst-script-vals.sh])
--- a/doc/interpreter/container.txi	Thu Nov 19 13:05:51 2020 -0800
+++ b/doc/interpreter/container.txi	Thu Nov 19 13:08:00 2020 -0800
@@ -914,11 +914,11 @@
 The following string functions support cell arrays of strings:
 @code{char}, @code{strvcat}, @code{strcat} (@pxref{Concatenating
 Strings}), @code{strcmp}, @code{strncmp}, @code{strcmpi},
-@code{strncmpi} (@pxref{Comparing Strings}), @code{str2double},
+@code{strncmpi} (@pxref{Searching in Strings}), @code{str2double},
 @code{deblank}, @code{strtrim}, @code{strtrunc}, @code{strfind},
 @code{strmatch}, , @code{regexp}, @code{regexpi}
-(@pxref{Manipulating Strings}) and @code{str2double}
-(@pxref{String Conversions}).
+(@pxref{String Operations}) and @code{str2double}
+(@pxref{Converting Strings}).
 
 The function @code{iscellstr} can be used to test if an object is a
 cell array of strings.
--- a/doc/interpreter/contributors.in	Thu Nov 19 13:05:51 2020 -0800
+++ b/doc/interpreter/contributors.in	Thu Nov 19 13:08:00 2020 -0800
@@ -89,6 +89,7 @@
 Paul Eggert
 Stephen Eglen
 Peter Ekberg
+Abdallah K. Elshamy
 Garrett Euler
 Edmund Grimley Evans
 Rolf Fabian
@@ -191,6 +192,7 @@
 Alexander Klein
 Lasse Kliemann
 Geoffrey Knauth
+Martin Köhler
 Heine Kolltveit
 Ken Kouno
 Kacper Kowalik
@@ -247,6 +249,7 @@
 Laurent Mazet
 G. D. McBain
 Ronald van der Meer
+Markus Meisinger
 Júlio Hoffimann Mendes
 Ed Meyer
 Thorsten Meyer
--- a/doc/interpreter/doccheck/README	Thu Nov 19 13:05:51 2020 -0800
+++ b/doc/interpreter/doccheck/README	Thu Nov 19 13:08:00 2020 -0800
@@ -78,7 +78,7 @@
 which can be added to the private dictionary.  Instead the source is marked up:
 Manchester @nospell{Centre} for Computational Mathematics.
 
-aspell will no longer reports any misspellings for linalg.texi.
+aspell will no longer report any misspellings for linalg.texi.
 
 GRAMMAR:
 
--- a/doc/interpreter/doccheck/aspell-octave.en.pws	Thu Nov 19 13:05:51 2020 -0800
+++ b/doc/interpreter/doccheck/aspell-octave.en.pws	Thu Nov 19 13:08:00 2020 -0800
@@ -1,13 +1,14 @@
 personal_ws-1.1 en 1
 AbsTol
 accumarray
+Acknowledgements
 acknowledgements
-Acknowledgements
 adams
 Affero
 afterwards
 al
 aleph
+allocatable
 amd
 amongst
 anisotropic
@@ -21,8 +22,6 @@
 arpack
 ArrayValued
 ascii
-Associativity
-associativity
 ast
 async
 atan
@@ -30,12 +29,11 @@
 audiodevinfo
 audioplayer
 audiorecorder
-AutoCAD
 Autoconf
 autocorrelated
 autocovariances
+autoload
 Autoload
-autoload
 autoloaded
 Autoloading
 Automake
@@ -52,29 +50,28 @@
 Barycentric
 basevalue
 BaseValue
+BDF
 bdf
-BDF
 benchmarking
 betacdf
 betainc
 betainv
 betaln
 betapdf
-betarnd
 BFGS
 BICG
 BiConjugate
+biharmonic
 bincoeff
 binocdf
 binoinv
 binopdf
-binornd
 Biomathematics
-bitmapped
 bitwise
 blas
 bmp
 boolean
+Booleans
 boolMatrix
 boxoff
 boxon
@@ -102,8 +99,8 @@
 cd
 cdata
 cdatamapping
+CDF
 cdf
-CDF
 cdot
 ceil
 cellstr
@@ -146,11 +143,11 @@
 colorcube
 colormap
 colormaps
+colororder
 ColorOrder
-colororder
 colperm
+CommentStyle
 commentstyle
-CommentStyle
 ComplexEqn
 cond
 condest
@@ -159,10 +156,10 @@
 const
 contextless
 contourc
+ConvertInfAndNaN
 convhull
 Convolve
 copyrightable
-CorelDraw
 corrcoef
 cosecant
 courseware
@@ -201,8 +198,8 @@
 daspk
 dasrt
 dassl
+DataAspectRatio
 dataset
-datasets
 datasource
 datenum
 datenums
@@ -221,17 +218,16 @@
 delaunay
 Delaunay
 delaunayn
+deletefcn
 DeleteFcn
-deletefcn
 delim
 deltaX
-demi
 det
 dggsvd
 diag
 diagcomp
+dialogs
 Dialogs
-dialogs
 diamondsuit
 differentiable
 digamma
@@ -254,7 +250,6 @@
 doublearrow
 downarrow
 downdate
-dpi
 droptol
 dt
 dx
@@ -273,31 +268,31 @@
 elementwise
 elseif
 emacs
+EmptyValue
 emptyvalue
-EmptyValue
 encodings
 endfunction
+Endian
 endian
-Endian
 endif
+EndOfLine
 endofline
-EndOfLine
 EOF
 EOLs
 eps
 eq
 equidistributed
+Equilibration
 equilibration
-Equilibration
 equispaced
 erf
 erfc
 erfi
 errno
+Errorbar
 errorbar
-Errorbar
+Errorbars
 errorbars
-Errorbars
 errordlg
 ErrorHandler
 ESC
@@ -312,11 +307,10 @@
 expcdf
 expinv
 exppdf
-exprnd
 extendedtext
 extrema
+FaceColor
 facecolor
-FaceColor
 FaceLighting
 FaceNormals
 FaceVertexCData
@@ -334,8 +328,8 @@
 fieldname
 fieldnames
 FIFOs
+filename
 FileName
-filename
 filenames
 filepaths
 Filesystem
@@ -346,11 +340,13 @@
 fitboxtotext
 FIXME
 flac
+fltk
 FLTK
-fltk
 fminsearch
 fminunc
+FontConfig
 fontconfig
+FontName
 fontname
 forall
 forcecelloutput
@@ -362,9 +358,8 @@
 FreeBSD
 FreeSans
 freespacing
+freetype
 FreeType
-freetype
-frnd
 Fs
 FSF
 fullpath
@@ -374,7 +369,6 @@
 gamcdf
 gaminv
 gampdf
-gamrnd
 gaussian
 gca
 gcbo
@@ -382,11 +376,9 @@
 gcd
 ge
 GECOS
-genvarname
 geocdf
 geoinv
 geopdf
-geornd
 geotagging
 geq
 gesdd
@@ -394,17 +386,17 @@
 gfortran
 Ghostscript
 Ghostscript's
+GIF
 gif
-GIF
 glibc
 globbing
 glpk
+GLS
 gls
-GLS
 glyphs
 GMRES
+gnuplot
 Gnuplot
-gnuplot
 GNUTERM
 Goto
 goto
@@ -428,13 +420,13 @@
 HandleVisibility
 handlevisibility
 Hankel
+Hanning
 hanning
-Hanning
 hardcode
 hardcoded
 hardcoding
+hdf
 HDF
-hdf
 HeaderLines
 headerlines
 headlength
@@ -451,20 +443,19 @@
 hggroups
 hgid
 hgload
+hh
 HH
-hh
 histc
 holomorphic
 horizontalalignment
 horzcat
 hostname
+HSV
 hsv
-HSV
 html
 hygecdf
 hygeinv
 hygepdf
-hygernd
 hypervolume
 ichol
 ict
@@ -476,6 +467,7 @@
 ifft
 ifftn
 ignorecase
+IgnoreCase
 ij
 ilu
 ilutp
@@ -492,7 +484,6 @@
 InitialStep
 InitialValue
 inline
-Inline
 inmax
 inmin
 inpolygon
@@ -545,12 +536,13 @@
 JConstant
 JDK
 JIS
+jit
 JIT
-jit
 JPattern
 jpeg
 JPEG
 jpg
+JSON
 jvm
 JVM's
 kendall
@@ -606,9 +598,8 @@
 logncdf
 logninv
 lognpdf
-lognrnd
+lookup
 Lookup
-lookup
 lookups
 lossless
 lsode
@@ -649,11 +640,10 @@
 meshgridded
 meshstyle
 metadata
+metafile
 Metafile
 MetaFile
-metafile
 metafiles
-Metafont
 mex
 mget
 michol
@@ -669,8 +659,8 @@
 mkoctfile
 mldivide
 mmd
+mmm
 MMM
-mmm
 mmmm
 mmmyy
 mmmyyyy
@@ -683,12 +673,12 @@
 MStateDependence
 MSYS
 mtimes
+Multi
 multi
-Multi
 multibyte
 multipage
+multipledelimsasone
 MultipleDelimsAsOne
-multipledelimsasone
 MultiSelect
 multistep
 MvPattern
@@ -696,8 +686,8 @@
 myclass
 myfun
 nabla
+namespace
 NAMESPACE
-namespace
 nan
 NaN
 nancond
@@ -705,10 +695,10 @@
 NaNs
 nargin
 nargout
+natively
 nbincdf
 nbininv
 nbinpdf
-nbinrnd
 ncols
 nd
 ndgrid
@@ -717,7 +707,6 @@
 neq
 NeXT
 NextPlot
-nfev
 nfft
 ni
 NLP
@@ -730,7 +719,6 @@
 nonconformant
 nondecreasing
 nonincreasing
-nonmodal
 nonnan
 NonNegative
 nonnegativity
@@ -747,7 +735,6 @@
 normest
 norminv
 normpdf
-normrnd
 northeastoutside
 northoutside
 NorthOutside
@@ -775,8 +762,8 @@
 onCleanup
 online
 OpenBLAS
+OpenGL
 opengl
-OpenGL
 OpenJDK
 oplus
 optimizations
@@ -796,8 +783,8 @@
 overdetermined
 overridable
 paperorientation
+paperposition
 PaperPosition
-paperposition
 paperpositionmode
 papersize
 paperunits
@@ -805,7 +792,6 @@
 parametrically
 parseparams
 pbm
-PBM
 PBMplus
 pc
 PCG
@@ -815,8 +801,8 @@
 pcre
 PCRE
 PCX
+PDF
 pdf
-PDF
 pdflatex
 pentadiagonal
 periodogram
@@ -825,16 +811,16 @@
 PGMRES
 PHP
 pict
+piecewise
 Piecewise
-piecewise
 pinv
 PixelRegion
+PlotBoxAspectRatio
+png
 PNG
-png
 poisscdf
 poissinv
 poisspdf
-poissrnd
 polyderiv
 polyeig
 polyfit
@@ -859,10 +845,11 @@
 prepended
 preselected
 presolver
+PrettyWriter
 printf
 priori
+Profiler
 profiler
-Profiler
 programmatically
 prolate
 PromptString
@@ -877,12 +864,12 @@
 pushbutton
 pushbuttons
 Pxx
+Qhull
 qhull
-Qhull
 QP
 QQ
+qrupdate
 QRUPDATE
-qrupdate
 QScintilla
 quadcc
 quadgk
@@ -897,8 +884,8 @@
 quartile
 questdlg
 Quickhull
+qz
 QZ
-qz
 radian
 radians
 radices
@@ -927,7 +914,6 @@
 relicensing
 RelTol
 renderer
-renderers
 repelems
 replacechildren
 ReplacementStyle
@@ -936,8 +922,8 @@
 reproducibility
 resampled
 resampling
+Resize
 resize
-Resize
 resized
 resizing
 Resizing
@@ -1029,8 +1015,8 @@
 ss
 sT
 stairstep
+Startup
 startup
-Startup
 statinfo
 stdin
 stdout
@@ -1038,9 +1024,12 @@
 STFT
 str
 strcmp
+streamribbon
+Streamribbons
+streamribbons
 streamtube
+Streamtubes
 streamtubes
-Streamtubes
 stringanchors
 strncmp
 strncmpi
@@ -1101,12 +1090,12 @@
 svd
 SVD
 svds
+svg
 SVG
-svg
+Sym
 sym
-Sym
+symamd
 SYMAMD
-symamd
 symbfact
 symrcm
 Syntaxes
@@ -1114,8 +1103,8 @@
 terminal's
 tex
 texi
+Texinfo
 texinfo
-Texinfo
 TextAlphaBits
 textarrow
 textbackgroundcolor
@@ -1140,7 +1129,6 @@
 togglebutton
 togglebuttons
 tokenExtents
-TolF
 TolFun
 TolX
 toolchain
@@ -1162,9 +1150,8 @@
 triplot
 trisurf
 trivariate
-trnd
+TrueColor
 truecolor
-TrueColor
 tuples
 txi
 typedefs
@@ -1174,37 +1161,36 @@
 uchar
 UHESS
 UI
+uibuttongroup
 Uibuttongroup
-uibuttongroup
-uibuttongroups
 Uicontextmenu
 uicontextmenu
+uicontrol
 Uicontrol
-uicontrol
 uicontrols
 UID
 uimenu
 uint
+Uipanel
 uipanel
-Uipanel
 uipanels
+Uipushtool
 uipushtool
-Uipushtool
 uipushtools
 uiputfile
 uitab
+Uitable
 uitable
-Uitable
 Uitoggletool
 uitoggletool
+Uitoolbar
 uitoolbar
-Uitoolbar
 ulong
 Ultrix
 umfpack
 uminus
+Unary
 unary
-Unary
 unconvertible
 undirected
 unifcdf
@@ -1212,7 +1198,6 @@
 UniformOutput
 UniformValues
 unifpdf
-unifrnd
 unimodal
 Uninstall
 uninstalled
@@ -1249,8 +1234,8 @@
 vech
 vectorization
 vectorize
+Vectorized
 vectorized
-Vectorized
 vectorizing
 vee
 versa
@@ -1266,31 +1251,28 @@
 Voronoi
 waitbar
 waitbars
-warndlg
 wav
 WAV
-WayPoints
 Waypoints
 waypoints
+WayPoints
 wblcdf
 wblinv
 wblpdf
-wblrnd
 westoutside
 WestOutside
+whitespace
 Whitespace
-whitespace
 whos
-wienrnd
 Wikipedia
 wildcard
+wildcards
 Wildcards
-wildcards
 windowbuttondownfcn
 windowbuttonmotionfcn
 windowbuttonupfcn
+WindowStyle
 windowstyle
-WindowStyle
 WIPO
 wireframe
 wlen
@@ -1346,8 +1328,8 @@
 ypos
 yticklabels
 yticks
+YY
 yy
-YY
 YYYY
 yyyy
 yyyymmddTHHMMSS
--- a/doc/interpreter/doccheck/mk_undocumented_list	Thu Nov 19 13:05:51 2020 -0800
+++ b/doc/interpreter/doccheck/mk_undocumented_list	Thu Nov 19 13:08:00 2020 -0800
@@ -64,10 +64,12 @@
 }
 
 # Second, remove functions based on directory location
-# deprecated directory, doc/interpreter directory, test/ directory
+# deprecated directory, legacy directory, doc/interpreter directory,
+# test/ directory
 FUNC: foreach $idx (0 .. $#where)
 {
   next FUNC if ($where[$idx] =~ /deprecated/i);
+  next FUNC if ($where[$idx] =~ /legacy/i);
   next FUNC if ($where[$idx] =~ /interpreter/i);
   next FUNC if ($where[$idx] =~ m#test/#i);
 
@@ -81,7 +83,8 @@
 # Fourth, remove exceptions based on name that do not require documentation
 # Load list of function exceptions not requiring a DOCSTRING
 # Exception data is stored at the bottom of this script
-map { chomp, $exceptions{$_}=1; } <DATA>;
+foreach $_ (<DATA>)
+{ chomp, $exceptions{$_}=1; }
 
 # Remove exception data from the list
 @functions = grep (! $exceptions{$_}, @functions);
@@ -135,6 +138,7 @@
 flipdim
 fmod
 gammaln
+gui_mainfcn
 home
 i
 ifelse
--- a/doc/interpreter/func.txi	Thu Nov 19 13:05:51 2020 -0800
+++ b/doc/interpreter/func.txi	Thu Nov 19 13:08:00 2020 -0800
@@ -924,6 +924,8 @@
 
 @DOCSTRING(dir_in_loadpath)
 
+@DOCSTRING(dir_encoding)
+
 @node Subfunctions
 @subsection Subfunctions
 
@@ -1804,6 +1806,8 @@
 
 @DOCSTRING(str2func)
 
+@DOCSTRING(symvar)
+
 @node Anonymous Functions
 @subsection Anonymous Functions
 
--- a/doc/interpreter/genpropdoc.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/doc/interpreter/genpropdoc.m	Thu Nov 19 13:08:00 2020 -0800
@@ -39,9 +39,10 @@
 
 function genpropdoc (objname, fname = "", props = {})
   objnames = {"root", "figure", "axes", "legend", ...
-              "image", "light", "line", "patch", "surface", "text", ...
-              "uibuttongroup", "uicontextmenu", "uicontrol", "uipanel", ...
-              "uimenu", "uipushtool", "uitable", "uitoggletool", "uitoolbar"
+              "image", "light", "line", "patch", "scatter", "surface", ...
+              "text", "uibuttongroup", "uicontextmenu", "uicontrol", ...
+              "uipanel", "uimenu", "uipushtool", "uitable", ...
+              "uitoggletool", "uitoolbar"
              };
 
   ## Base properties
@@ -169,6 +170,11 @@
         s.doc = "If __prop__ is @qcode{\"on\"}, the __objname__ is \
 clipped in its parent axes limits.";
 
+      case "contextmenu"
+        s.doc = "Graphics handle of the uicontextmenu object that is \
+currently associated to this __objname__ object.";
+        s.valid = valid_handle;
+
       case "createfcn"
         s.doc = "Callback function executed immediately after __objname__ \
 has been created.  Function is set by using default property on root object, \
@@ -228,11 +234,6 @@
         s.valid = valid_string;
         s.printdefault = false;
 
-      case "uicontextmenu"
-        s.doc = "Graphics handle of the uicontextmenu object that is \
-currently associated to this __objname__ object.";
-        s.valid = valid_handle;
-
       case "userdata"
         s.doc = "User-defined data to associate with the graphics object.";
         s.valid = "Any Octave data";
@@ -656,12 +657,6 @@
         s.doc = doc_unused;
 
       ## Specific properties
-      case "activepositionproperty"
-        s.doc = "Specify which of @qcode{\"position\"} or \
-@qcode{\"outerposition\"} properties takes precedence when axes \
-annotations extent changes.  @xref{XREFaxesposition, , @w{position property}}, \
-and @ref{XREFaxesposition, , @w{outerposition property}}.";
-
       case "alim"
         s.doc = sprintf (doc_notimpl, "Transparency");
 
@@ -769,6 +764,11 @@
 
       case "gridlinestyle"
 
+      case "innerposition"
+        s.doc = "The @qcode{\"innerposition\"} property is the same as the \
+@ref{XREFaxesposition, , @w{@qcode{\"position\"} property}}.";
+        s.valid = valid_4elvec;
+
       case "labelfontsizemultiplier"
         s.doc = "Ratio between the x/y/zlabel fontsize and the tick \
 label fontsize";
@@ -844,6 +844,13 @@
         endif
         s.valid = valid_4elvec;
 
+      case "positionconstraint"
+        s.doc = "Specify which of @qcode{\"innerposition\"} or \
+@qcode{\"outerposition\"} properties takes precedence when axes \
+annotations extent changes.  \
+@xref{XREFaxesinnerposition, , @w{@qcode{\"innerposition\"} property}}, \
+and @ref{XREFaxesouterposition, , @w{@qcode{\"outerposition\"} property}}.";
+
       case "projection"
         s.doc = doc_unused;
 
@@ -1621,6 +1628,117 @@
 
     endswitch
 
+  ## Scatter properties
+  elseif (strcmp (objname, "scatter"))
+    switch (field)
+      ## Overridden shared properties
+      case "children"
+        s.doc = doc_unused;
+
+      ## Specific properties
+      case "cdatamode"
+        s.doc = "If @code{cdatamode} is @qcode{\"auto\"}, @code{cdata} is set \
+to the color from the @code{colororder} of the ancestor axes corresponding to \
+the @code{seriesindex}.";
+
+      case "cdatasource"
+        s.doc = sprintf (doc_notimpl, "Data from workspace variables");
+
+      case "cdata"
+        s.doc = "Data defining the scatter object color.\n\
+\n\
+If @code{cdata} is a scalar index into the current colormap or a RGB triplet, \
+it defines the color of all scatter markers.\n\
+\n\
+If @code{cdata} is an N-by-1 vector of indices or an N-by-3 (RGB) matrix, \
+it defines the color of each one of the N scatter markers.";
+        s.valid = valid_scalmat;
+
+
+      case "displayname"
+        s.doc = "Text of the legend entry corresponding to this scatter object.";
+
+      case "linewidth"
+        s.doc = "Line width of the edge of the markers.";
+
+      case "marker"
+        s.doc = "@xref{XREFlinemarker, , @w{line marker property}}.";
+
+      case "markeredgealpha"
+        s.doc = "Transparency level of the faces of the markers where a \
+value of 0 means complete transparency and a value of 1 means solid faces \
+without transparency.  Note that the markers are not sorted from back to \
+front which might lead to unexpected results when rendering layered \
+transparent markers or in combination with other transparent objects.";
+        s.valid = "scalar";
+
+      case "markeredgecolor"
+        s.doc = "Color of the edge of the markers.  @qcode{\"none\"} means \
+that the edges are transparent and @qcode{\"flat\"} means that the value \
+from @code{cdata} is used.  @xref{XREFlinemarkeredgecolor, , \
+@w{line markeredgecolor property}}.";
+        s.valid = packopt ({markdef("@qcode{\"none\"}"), ...
+                            "@qcode{\"flat\"}", ...
+                            valid_color});
+
+      case "markerfacealpha"
+        s.doc = "Transparency level of the faces of the markers where a \
+value of 0 means complete transparency and a value of 1 means solid faces \
+without transparency.  Note that the markers are not sorted from back to \
+front which might lead to unexpected results when rendering layered \
+transparent markers or in combination with other transparent objects.";
+        s.valid = "scalar";
+
+      case "markerfacecolor"
+        s.doc = "Color of the face of the markers.  @qcode{\"none\"} means \
+that the faces are transparent, @qcode{\"flat\"} means that the value from \
+@code{cdata} is used, and @qcode{\"auto\"} uses the @code{color} property of \
+the ancestor axes. @xref{XREFlinemarkerfacecolor, , \
+@w{line markerfacecolor property}}.";
+        s.valid = packopt ({markdef("@qcode{\"none\"}"), ...
+                            "@qcode{\"flat\"}", ...
+                            "@qcode{\"auto\"}", ...
+                            valid_color});
+
+      case "seriesindex"
+        s.doc = "Each scatter object in the same axes is asigned an \
+incrementing integer.  This corresponds to the index into the \
+@code{colororder} of the ancestor axes that is used if @code{cdatamode} is \
+set to @qcode{\"auto\"}.";
+
+      case "sizedatasource"
+        s.doc = sprintf (doc_notimpl, "Data from workspace variables");
+
+      case "sizedata"
+        s.doc = "Size of the area of the marker. A scalar value applies to \
+all markers.  If @code{cdata} is an N-by-1 vector, it defines the color of \
+each one of the N scatter markers.";
+        s.valid =  packopt ({"[]", "scalar", "vector"});
+
+      case "xdatasource"
+        s.doc = sprintf (doc_notimpl, "Data from workspace variables");
+
+      case "xdata"
+        s.doc = "Vector with the x coordinates of the scatter object.";
+        s.valid = "vector";
+
+      case "ydatasource"
+        s.doc = sprintf (doc_notimpl, "Data from workspace variables");
+
+      case "ydata"
+        s.doc = "Vector with the y coordinates of the scatter object.";
+        s.valid = "vector";
+
+      case "zdatasource"
+        s.doc = sprintf (doc_notimpl, "Data from workspace variables");
+
+      case "zdata"
+        s.doc = "For 3D data, vector with the y coordinates of the scatter \
+object.";
+        s.valid = packopt ({"[]", "vector"});
+
+    endswitch
+
   ## Light properties
   elseif (strcmp (objname, "light"))
     switch (field)
@@ -1962,6 +2080,10 @@
                  "location", "numcolumns", "orientation", "position", ...
                  "string", "textcolor", "title", "units"};
     endif
+  elseif (strcmp (objname, "scatter"))
+    ## Make sure to get a scatter object independent of graphics toolkit
+    hax = axes (hf);
+    h = __go_scatter__ (hax);
   else
     eval (["h = " objname " ();"]);
   endif
--- a/doc/interpreter/graphics_properties.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/doc/interpreter/graphics_properties.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -5,6 +5,7 @@
   interpreter/plot-lineproperties.texi \
   interpreter/plot-patchproperties.texi \
   interpreter/plot-rootproperties.texi \
+  interpreter/plot-scatterproperties.texi \
   interpreter/plot-surfaceproperties.texi \
   interpreter/plot-textproperties.texi
 
@@ -35,5 +36,8 @@
 interpreter/plot-surfaceproperties.texi: interpreter/genpropdoc.m
 	$(AM_V_GEN)$(call gen-propdoc-texi,surface)
 
+interpreter/plot-scatterproperties.texi: interpreter/genpropdoc.m
+	$(AM_V_GEN)$(call gen-propdoc-texi,scatter)
+
 interpreter/plot-textproperties.texi: interpreter/genpropdoc.m
 	$(AM_V_GEN)$(call gen-propdoc-texi,text)
--- a/doc/interpreter/gui.txi	Thu Nov 19 13:05:51 2020 -0800
+++ b/doc/interpreter/gui.txi	Thu Nov 19 13:08:00 2020 -0800
@@ -141,6 +141,10 @@
 
 @DOCSTRING(isguirunning)
 
+@DOCSTRING(getpixelposition)
+
+@DOCSTRING(listfonts)
+
 @DOCSTRING(movegui)
 
 @DOCSTRING(openvar)
--- a/doc/interpreter/linalg.txi	Thu Nov 19 13:05:51 2020 -0800
+++ b/doc/interpreter/linalg.txi	Thu Nov 19 13:08:00 2020 -0800
@@ -183,6 +183,8 @@
 
 @DOCSTRING(ordschur)
 
+@DOCSTRING(ordqz)
+
 @DOCSTRING(ordeig)
 
 @DOCSTRING(subspace)
--- a/doc/interpreter/matrix.txi	Thu Nov 19 13:05:51 2020 -0800
+++ b/doc/interpreter/matrix.txi	Thu Nov 19 13:08:00 2020 -0800
@@ -175,6 +175,8 @@
 
 @DOCSTRING(randg)
 
+@DOCSTRING(rng)
+
 The generators operate in the new or old style together, it is not
 possible to mix the two.  Initializing any generator with
 @qcode{"state"} or @qcode{"seed"} causes the others to switch to the
--- a/doc/interpreter/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/doc/interpreter/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -9,6 +9,7 @@
   %reldir%/plot-lineproperties.texi \
   %reldir%/plot-patchproperties.texi \
   %reldir%/plot-rootproperties.texi \
+  %reldir%/plot-scatterproperties.texi \
   %reldir%/plot-surfaceproperties.texi \
   %reldir%/plot-textproperties.texi \
   %reldir%/plot-uimenuproperties.texi \
@@ -55,6 +56,9 @@
 %reldir%/plot-rootproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
 	$(AM_V_GEN)$(call gen-propdoc-texi,root)
 
+%reldir%/plot-scatterproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
+	$(AM_V_GEN)$(call gen-propdoc-texi,scatter)
+
 %reldir%/plot-surfaceproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
 	$(AM_V_GEN)$(call gen-propdoc-texi,surface)
 
--- a/doc/interpreter/octave.texi	Thu Nov 19 13:05:51 2020 -0800
+++ b/doc/interpreter/octave.texi	Thu Nov 19 13:08:00 2020 -0800
@@ -302,16 +302,23 @@
 
 * Escape Sequences in String Constants::
 * Character Arrays::
-* Creating Strings::
-* Comparing Strings::
-* Manipulating Strings::
-* String Conversions::
+* String Operations::
+* Converting Strings::
 * Character Class Functions::
 
-Creating Strings
+String Operations
 
+* Common String Operations::
 * Concatenating Strings::
-* Converting Numerical Data to Strings::
+* Splitting and Joining Strings::
+* Searching in Strings::
+* Searching and Replacing in Strings::
+
+Converting Strings
+
+* String encoding::
+* Numerical Data and Strings::
+* JSON data encoding/decoding::
 
 Data Containers
 
@@ -576,6 +583,7 @@
 * Text Properties::
 * Image Properties::
 * Patch Properties::
+* Scatter Properties::
 * Surface Properties::
 * Light Properties::
 * Uimenu Properties::
@@ -608,7 +616,6 @@
 * Error Bar Series::
 * Line Series::
 * Quiver Group::
-* Scatter Group::
 * Stair Group::
 * Stem Series::
 * Surface Group::
--- a/doc/interpreter/plot.txi	Thu Nov 19 13:05:51 2020 -0800
+++ b/doc/interpreter/plot.txi	Thu Nov 19 13:08:00 2020 -0800
@@ -259,6 +259,8 @@
 
 @DOCSTRING(quiver3)
 
+@DOCSTRING(streamribbon)
+
 @DOCSTRING(streamtube)
 
 @DOCSTRING(ostreamtube)
@@ -340,6 +342,16 @@
 @findex zticklabels
 @DOCSTRING(xticklabels)
 
+The @code{xtickangle}, @code{ytickangle}, and @code{ztickangle} functions
+may be used to get or set the rotation angle of labels for the respective axis.
+Each has the same form.
+
+@anchor{XREFytickangle}
+@anchor{XREFztickangle}
+@findex ytickangle
+@findex ztickangle
+@DOCSTRING(xtickangle)
+
 @node Two-dimensional Function Plotting
 @subsubsection Two-dimensional Function Plotting
 @cindex plotting, two-dimensional functions
@@ -1182,24 +1194,30 @@
 The graphics functions use pointers, which are of class graphics_handle, in
 order to address the data structures which control visual display.  A
 graphics handle may point to any one of a number of different base object
-types and these objects are the graphics data structures themselves.  The
+types.  These objects are the graphics data structures themselves.  The
 primitive graphic object types are: @code{figure}, @code{axes}, @code{line},
-@code{text}, @code{patch}, @code{surface}, @code{text}, @code{image}, and
-@code{light}.
-
-Each of these objects has a function by the same name, and, each of these
+@code{text}, @code{patch}, @code{scatter}, @code{surface}, @code{text},
+@code{image}, and @code{light}.
+
+Each of these objects has a function by the same name, and each of these
 functions returns a graphics handle pointing to an object of the corresponding
-type.  In addition there are several functions which operate on properties of
-the graphics objects and which also return handles: the functions @code{plot}
-and @code{plot3} return a handle pointing to an object of type line, the
-function @code{subplot} returns a handle pointing to an object of type axes,
-the function @code{fill} returns a handle pointing to an object of type patch,
-the functions @code{area}, @code{bar}, @code{barh}, @code{contour},
-@code{contourf}, @code{contour3}, @code{surf}, @code{mesh}, @code{surfc},
-@code{meshc}, @code{errorbar}, @code{quiver}, @code{quiver3}, @code{scatter},
-@code{scatter3}, @code{stair}, @code{stem}, @code{stem3} each return a handle
-to a complex data structure as documented in
-@ref{XREFdatasources,,Data Sources}.
+type.
+
+In addition, there are several functions which operate on properties of the
+graphics objects and which also return handles.  This includes but is not
+limited to the following functions: The functions @code{plot} and @code{plot3}
+return a handle pointing to an object of type @code{line}.  The function
+@code{subplot} returns a handle pointing to an object of type @code{axes}.
+The functions @code{fill}, @code{trimesh}, and @code{trisurf} return a handle
+pointing to an object of type patch.  The function @code{scatter3} returns a
+handle to an object of type scatter.  The functions @code{slice}, @code{surf},
+@code{surfl}, @code{mesh}, @code{meshz}, @code{pcolor}, and @code{waterfall}
+each return a handle of type surface.  The function @code{camlight} returns a
+handle to an object of type light.  The functions @code{area}, @code{bar},
+@code{barh}, @code{contour}, @code{contourf}, @code{contour3}, @code{surfc},
+@code{meshc}, @code{errorbar}, @code{quiver}, @code{quiver3}, @code{stair},
+@code{stem}, @code{stem3} each return a handle to a complex data structure as
+documented in @ref{XREFdatasources,,Data Sources}.
 
 The graphics objects are arranged in a hierarchy:
 
@@ -1211,8 +1229,12 @@
 
 3. Below the @code{figure} objects are @code{axes} or @code{hggroup} objects.
 
-4. Below the @code{axes} objects are @code{line}, @code{text}, @code{patch},
-@code{surface}, @code{image}, and @code{light} objects.
+4. Below the @code{axes} or @code{hggroup} objects are @code{line},
+@code{text}, @code{patch}, @code{scatter}, @code{surface}, @code{image}, and
+@code{light} objects.
+
+It is possible to walk this hierarchical tree by querying the @qcode{"parent"}
+and @qcode{"children"} properties of the graphics objects.
 
 Graphics handles may be distinguished from function handles
 (@pxref{Function Handles}) by means of the function @code{ishghandle}.
@@ -1502,6 +1524,7 @@
 * Text Properties::
 * Image Properties::
 * Patch Properties::
+* Scatter Properties::
 * Surface Properties::
 * Light Properties::
 * Uimenu Properties::
@@ -1583,6 +1606,13 @@
 @include plot-patchproperties.texi
 
 
+@node Scatter Properties
+@subsubsection Scatter Properties
+@prindex @sortas{@ Scatter Properties} Scatter Properties
+
+@include plot-scatterproperties.texi
+
+
 @node Surface Properties
 @subsubsection Surface Properties
 @prindex @sortas{@ Surface Properties} Surface Properties
@@ -2149,7 +2179,6 @@
 * Error Bar Series::
 * Line Series::
 * Quiver Group::
-* Scatter Group::
 * Stair Group::
 * Stem Series::
 * Surface Group::
@@ -2475,46 +2504,6 @@
 Data source variables.
 @end table
 
-@node Scatter Group
-@subsubsection Scatter Group
-@cindex group objects
-@cindex scatter group
-
-Scatter series objects are created by the @code{scatter} or @code{scatter3}
-functions.  A single hggroup element contains as many children as there are
-points in the scatter plot, with each child representing one of the points.
-The properties of the stem series are
-
-@table @code
-@item linewidth
-The line width of the line objects of the points.  @xref{Line Styles}.
-
-@item  marker
-@itemx markeredgecolor
-@itemx markerfacecolor
-The line and fill color of the markers of the points.  @xref{Colors}.
-
-@item  xdata
-@itemx ydata
-@itemx zdata
-The original x, y and z data of the stems.
-
-@item cdata
-The color data for the points of the plot.  Each point can have a separate
-color, or a unique color can be specified.
-
-@item sizedata
-The size data for the points of the plot.  Each point can its own size or a
-unique size can be specified.
-
-@item  xdatasource
-@itemx ydatasource
-@itemx zdatasource
-@itemx cdatasource
-@itemx sizedatasource
-Data source variables.
-@end table
-
 @node Stair Group
 @subsubsection Stair Group
 @cindex group objects
--- a/doc/interpreter/strings.txi	Thu Nov 19 13:05:51 2020 -0800
+++ b/doc/interpreter/strings.txi	Thu Nov 19 13:08:00 2020 -0800
@@ -56,13 +56,17 @@
 While strings can in principle store arbitrary content, most functions expect
 them to be UTF-8 encoded Unicode strings.
 
+Furthermore, it is possible to create a string without actually writing a text.
+The function @code{blanks} creates a string of a given length consisting only
+of blank characters (ASCII code 32).
+
+@DOCSTRING(blanks)
+
 @menu
 * Escape Sequences in String Constants::
 * Character Arrays::
-* Creating Strings::
-* Comparing Strings::
-* Manipulating Strings::
-* String Conversions::
+* String Operations::
+* Converting Strings::
 * Character Class Functions::
 @end menu
 
@@ -207,26 +211,65 @@
 
 @DOCSTRING(string_fill_char)
 
+Another useful function to control the text justification in this case is
+the @code{strjust} function.
+
+@DOCSTRING(strjust)
+
 This shows a problem with character matrices.  It simply isn't possible to
 represent strings of different lengths.  The solution is to use a cell array of
 strings, which is described in @ref{Cell Arrays of Strings}.
 
-@node Creating Strings
-@section Creating Strings
+@node String Operations
+@section String Operations
+
+Octave supports a wide range of functions for manipulating strings.
+Since a string is just a matrix, simple manipulations can be accomplished
+using standard operators.  The following example shows how to replace
+all blank characters with underscores.
 
-The easiest way to create a string is, as illustrated in the introduction,
-to enclose a text in double-quotes or single-quotes.  It is however
-possible to create a string without actually writing a text.  The
-function @code{blanks} creates a string of a given length consisting
-only of blank characters (ASCII code 32).
+@example
+@group
+quote = ...
+  "First things first, but not necessarily in that order";
+quote( quote == " " ) = "_"
+@result{} quote =
+    First_things_first,_but_not_necessarily_in_that_order
+@end group
+@end example
 
-@DOCSTRING(blanks)
+For more complex manipulations, such as searching, replacing, and
+general regular expressions, the following functions come with Octave.
 
 @menu
+* Common String Operations::
 * Concatenating Strings::
-* Converting Numerical Data to Strings::
+* Splitting and Joining Strings::
+* Searching in Strings::
+* Searching and Replacing in Strings::
 @end menu
 
+@node Common String Operations
+@subsection Common String Operations
+
+The following functions are useful to perform common String operations.
+
+@DOCSTRING(tolower)
+
+@DOCSTRING(toupper)
+
+@DOCSTRING(deblank)
+
+@DOCSTRING(strtrim)
+
+@DOCSTRING(strtrunc)
+
+@DOCSTRING(untabify)
+
+@DOCSTRING(do_string_escapes)
+
+@DOCSTRING(undo_string_escapes)
+
 @node Concatenating Strings
 @subsection Concatenating Strings
 
@@ -370,25 +413,21 @@
 
 @DOCSTRING(cstrcat)
 
-@node Converting Numerical Data to Strings
-@subsection Converting Numerical Data to Strings
-Apart from the string concatenation functions (@pxref{Concatenating Strings})
-which cast numerical data to the corresponding UTF-8 encoded characters, there
-are several functions that format numerical data as strings.  @code{mat2str}
-and @code{num2str} convert real or complex matrices, while @code{int2str}
-converts integer matrices.  @code{int2str} takes the real part of complex
-values and round fractional values to integer.  A more flexible way to format
-numerical data as strings is the @code{sprintf} function
-(@pxref{Formatted Output}, @ref{XREFsprintf,,sprintf}).
+@node Splitting and Joining Strings
+@subsection Splitting and Joining Strings
+
+@DOCSTRING(substr)
+
+@DOCSTRING(strtok)
 
-@DOCSTRING(mat2str)
+@DOCSTRING(strsplit)
 
-@DOCSTRING(num2str)
+@DOCSTRING(ostrsplit)
 
-@DOCSTRING(int2str)
+@DOCSTRING(strjoin)
 
-@node Comparing Strings
-@section Comparing Strings
+@node Searching in Strings
+@subsection Searching in Strings
 
 Since a string is a character array, comparisons between strings work
 element by element as the following example shows:
@@ -416,32 +455,12 @@
 
 @DOCSTRING(strncmpi)
 
-@node Manipulating Strings
-@section Manipulating Strings
-
-Octave supports a wide range of functions for manipulating strings.
-Since a string is just a matrix, simple manipulations can be accomplished
-using standard operators.  The following example shows how to replace
-all blank characters with underscores.
+Despite those comparison functions, there are more specialized function to
+find the index position of a search pattern within a string.
 
-@example
-@group
-quote = ...
-  "First things first, but not necessarily in that order";
-quote( quote == " " ) = "_"
-@result{} quote =
-    First_things_first,_but_not_necessarily_in_that_order
-@end group
-@end example
+@DOCSTRING(startsWith)
 
-For more complex manipulations, such as searching, replacing, and
-general regular expressions, the following functions come with Octave.
-
-@DOCSTRING(deblank)
-
-@DOCSTRING(strtrim)
-
-@DOCSTRING(strtrunc)
+@DOCSTRING(endsWith)
 
 @DOCSTRING(findstr)
 
@@ -451,26 +470,19 @@
 
 @DOCSTRING(rindex)
 
-@DOCSTRING(strfind)
+@DOCSTRING(unicode_idx)
 
-@DOCSTRING(strjoin)
+@DOCSTRING(strfind)
 
 @DOCSTRING(strmatch)
 
-@DOCSTRING(strtok)
-
-@DOCSTRING(strsplit)
-
-@DOCSTRING(ostrsplit)
-
-@DOCSTRING(strread)
+@node Searching and Replacing in Strings
+@subsection Searching and Replacing in Strings
 
 @DOCSTRING(strrep)
 
 @DOCSTRING(erase)
 
-@DOCSTRING(substr)
-
 @DOCSTRING(regexp)
 
 @DOCSTRING(regexpi)
@@ -479,23 +491,45 @@
 
 @DOCSTRING(regexptranslate)
 
-@DOCSTRING(untabify)
+@node Converting Strings
+@section Converting Strings
+
+Octave offers several kinds of conversion functions for Strings.
 
-@DOCSTRING(unicode_idx)
+@menu
+* String encoding::
+* Numerical Data and Strings::
+* JSON data encoding/decoding::
+@end menu
 
-@node String Conversions
-@section String Conversions
+@node String encoding
+@subsection String encoding
+
+@DOCSTRING(unicode2native)
+
+@DOCSTRING(native2unicode)
 
-Octave supports various kinds of conversions between strings and
-numbers.  As an example, it is possible to convert a string containing
-a hexadecimal number to a floating point number.
+@node Numerical Data and Strings
+@subsection Numerical Data and Strings
 
-@example
-@group
-hex2dec ("FF")
-      @result{} 255
-@end group
-@end example
+Apart from the string concatenation functions (@pxref{Concatenating Strings})
+which cast numerical data to the corresponding UTF-8 encoded characters, there
+are several functions that format numerical data as strings.  @code{mat2str}
+and @code{num2str} convert real or complex matrices, while @code{int2str}
+converts integer matrices.  @code{int2str} takes the real part of complex
+values and round fractional values to integer.  A more flexible way to format
+numerical data as strings is the @code{sprintf} function
+(@pxref{Formatted Output}, @ref{XREFsprintf,,sprintf}).
+
+@DOCSTRING(mat2str)
+
+@DOCSTRING(num2str)
+
+@DOCSTRING(int2str)
+
+@DOCSTRING(str2double)
+
+@DOCSTRING(str2num)
 
 @DOCSTRING(bin2dec)
 
@@ -513,23 +547,18 @@
 
 @DOCSTRING(hex2num)
 
-@DOCSTRING(str2double)
-
-@DOCSTRING(strjust)
+@DOCSTRING(strread)
 
-@DOCSTRING(str2num)
-
-@DOCSTRING(tolower)
+@node JSON data encoding/decoding
+@subsection JSON data encoding/decoding
 
-@DOCSTRING(toupper)
-
-@DOCSTRING(unicode2native)
+JavaScript Object Notation, in short JSON, is a very common human readable
+and structured data format.  GNU Octave supports encoding and decoding this
+format with the following two functions.
 
-@DOCSTRING(native2unicode)
+@DOCSTRING(jsonencode)
 
-@DOCSTRING(do_string_escapes)
-
-@DOCSTRING(undo_string_escapes)
+@DOCSTRING(jsondecode)
 
 @node Character Class Functions
 @section Character Class Functions
--- a/doc/interpreter/system.txi	Thu Nov 19 13:05:51 2020 -0800
+++ b/doc/interpreter/system.txi	Thu Nov 19 13:08:00 2020 -0800
@@ -324,6 +324,10 @@
 
 @DOCSTRING(base64_decode)
 
+@DOCSTRING(matlab.net.base64encode)
+
+@DOCSTRING(matlab.net.base64decode)
+
 @node Controlling Subprocesses
 @section Controlling Subprocesses
 
@@ -554,6 +558,8 @@
 
 @DOCSTRING(license)
 
+@DOCSTRING(memory)
+
 @DOCSTRING(getrusage)
 
 @DOCSTRING(winqueryreg)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/etc/NEWS.6	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,323 @@
+Summary of important user-visible changes for version 6.1.0 (2020-08-26):
+------------------------------------------------------------------------
+
+### General improvements
+
+- The `intersect`, `setdiff`, `setxor`, `union`, and `unique` functions
+  accept a new sorting option `"stable"` which will return output values
+  in the same order as the input, rather than in ascending order.
+
+- Complex RESTful web services can now be accessed by the `webread` and
+  `webwrite` functions alongside with the `weboptions` structure.  One
+  major feature is the support for cookies to enable RESTful
+  communication with the web service.
+
+  Additionally, the system web browser can be opened by the `web`
+  function.
+
+- The `linspace` function now produces symmetrical sequences when the
+  endpoints are symmetric.  This is more intuitive and also compatible
+  with recent changes made in Matlab R2019b.
+
+- The underlying algorithm of the `rand` function has been changed.
+  For single precision outputs, the algorithm has been fixed so that it
+  produces values strictly in the range (0, 1).  Previously, it could
+  occasionally generate the right endpoint value of 1 (See bug #41742).
+  In addition, the new implementation uses a uniform interval between
+  floating point values in the range (0, 1) rather than targeting a
+  uniform density (# of random integers / length along real number
+  line).
+
+- Numerical integration has been improved.  The `quadv` function has
+  been re-written so that it can compute integrands of periodic
+  functions.  At the same time, performance is better with ~3.5X fewer
+  function evaluations required.  A bug in `quadgk` that caused complex
+  path integrals specified with `"Waypoints"` to occasionally be
+  calculated in the opposite direction was fixed.
+
+- The `edit` function option `"editinplace"` now defaults to `true` and
+  the option `"home"` now defaults to the empty matrix `[]`.  Files will
+  no longer be copied to the user's HOME directory for editing.  The old
+  behavior can be restored by setting `"editinplace"` to `false` and
+  `"home"` to `"~/octave"`.
+
+- The `format` command supports two new options: `uppercase` and
+  `lowercase` (default).  With the default, print a lowercase 'e' for
+  the exponent character in scientific notation and lowercase 'a-f' for
+  the hex digits representing 10-15.  With `uppercase`, print 'E' and
+  'A-F' instead.  The previous uppercase formats, `E` and `G`, no longer
+  control the case of the output.
+
+  Additionally, the `format` command can be called with multiple options
+  for controlling the format, spacing, and case in arbitrary order.
+  For example:
+
+        format long e uppercase loose
+
+  Note, in the case of multiple competing format options the rightmost
+  one is used, and, in case of an error, the previous format remains
+  unchanged.
+
+- L-value references (e.g., increment (++), decrement (--), and all
+  in-place assignment operators (+=, -=, *=, /=, etc.)) are no longer
+  allowed in anonymous functions.
+
+- New warnings have been added about questionable uses of the colon ':'
+  range operator.  Each has a new warning ID so that it can be disabled
+  if desired.
+
+  >  `Octave:colon-complex-argument`   : when any arg is complex
+  >  `Octave:colon-nonscalar-argument` : when any arg is non-scalar
+
+- The `regexp` and related functions now correctly handle and *require*
+  strings in UTF-8 encoding.  As with any other function that requires
+  strings to be encoded in Octave's native encoding, you can use
+  `native2unicode` to convert from your preferred locale.  For example,
+  the copyright symbol in UTF-8 is `native2unicode (169, "latin1")`.
+
+- The startup file `octaverc` can now be located in the platform
+  dependent location for user local configuration files (e.g.,
+  ${XDG_CONFIG_HOME}/octave/octaverc on Unix-like operating systems or
+  %APPDATA%\octave\octaverc on Windows).
+
+- `pkg describe` now lists dependencies and inverse dependencies
+  (i.e., other installed packages that depend on the package in
+  question).
+
+- `pkg test` now tests all functions in a package.
+
+- When unloading a package, `pkg` now checks if any remaining loaded
+  packages depend on the one to be removed.  If this is the case `pkg`
+  aborts with an explanatory error message.  This behavior can be
+  overridden with the `-nodeps` option.
+
+- The command
+
+    dbstop in CLASS at METHOD
+
+  now works to set breakpoints in classdef constructors and methods.
+
+#### Graphics backend
+
+- The use of Qt4 for graphics and the GUI is deprecated in Octave
+  version 6 and no further bug fixes will be made.  Qt4 support will be
+  removed completely in Octave version 7.
+
+- The `legend` function has been entirely rewritten.  This fixes a
+  number of historical bugs, and also implements new properties such as
+  `"AutoUpdate"` and `"NumColumns"`.  The gnuplot toolkit---which is no
+  longer actively maintained---still uses the old legend function.
+
+- The `axis` function was updated which resolved 10 bugs affecting
+  axes to which `"equal"` had been applied.
+
+- Graphic primitives now accept a color property value of `"none"`
+  which is useful when a particular primitive needs to be hidden
+  (for example, the Y-axis of an axes object with `"ycolor" = "none"`)
+  without hiding the entire primitive `"visibility" = "off"`.
+
+- A new property `"FontSmoothing"` has been added to text and axes
+  objects that controls whether anti-aliasing is used during the
+  rendering of characters.  The default is `"on"` which produces smooth,
+  more visually appealing text.
+
+- The figure property `"windowscrollwheelfcn"`is now implemented.
+  This makes it possible to provide a callback function to be executed
+  when users manipulate the mouse wheel on a given figure.
+
+- The figure properties `"pointer"`, `"pointershapecdata"`, and
+  `"pointershapehotspot"` are now implemented.  This makes it possible
+  to change the shape of the cursor (pointer in Matlab-speak) displayed
+  in a plot window.
+
+- The figure property `"paperpositionmode"` now has the default `"auto"`
+  rather than `"manual"`.  This change is more intuitive and is
+  Matlab compatible.
+
+- The appearance of patterned lines `"LineStyle" = ":"|"--"|"-."` has
+  been improved for small widths (`"LineWidth"` less than 1.5 pixels)
+  which is a common scenario.
+
+- Printing to EPS files now uses a tight bounding box (`"-tight"`
+  argument to print) by default.  This makes more sense for EPS
+  files which are normally embedded within other documents, and is
+  Matlab compatible.  If necessary use the `"-loose"` option to
+  reproduce figures as they appeared in previous versions of Octave.
+
+- The following print devices are no longer officially supported: cdr,
+  corel, aifm, ill, cgm, hpgl, mf and dxf.  A warning will be thrown
+  when using those devices, and the code for supporting those formats
+  will eventually be removed from a future version of Octave.
+
+- The placement of text subscripts and superscripts has been
+  re-engineered and now produces visually attractive results similar to
+  Latex.
+
+### Matlab compatibility
+
+- The function `unique` now returns column index vectors for the second
+  and third outputs.  When duplicate values are present, the default
+  index to return is now the `"first"` occurrence.  The previous Octave
+  behavior, or Matlab behavior from releases prior to R2012b, can be
+  obtained by using the `"legacy"` flag.
+
+- The function `setdiff` with the `"rows"` argument now returns Matlab
+  compatible results.  The previous Octave behavior, or Matlab behavior
+  from releases prior to R2012b, can be obtained by using the `"legacy"`
+  flag.
+
+- The functions `intersect`, `setxor`, and `union` now accept a
+  `"legacy"` flag which changes the index values (second and third
+  outputs) as well as the orientation of all outputs to match Matlab
+  releases prior to R2012b.
+
+- The function `streamtube` is Matlab compatible and plots tubes along
+  streamlines which are scaled by the vector field divergence. The
+  Octave-only extension `ostreamtube` can be used to visualize the flow
+  expansion and contraction of the vector field due to the local
+  crossflow divergence.
+
+- The interpreter now supports handles to nested functions.
+
+- The graphics properties `"LineWidth"` and `"MarkerSize"` are now
+  measured in points, *not* pixels.  Compared to previous versions
+  of Octave, some lines and markers will appear 4/3 larger.
+
+- The meta.class property "SuperClassList" has been renamed
+  "Superclasslist" for Matlab compatibility.  The original name will
+  exist as an alias until Octave version 8.1.
+
+- Inline functions created by the function `inline` are now of type
+  "inline" when interrogated with the `class` function.  In previous
+  versions of Octave, the class returned was "function_handle".  This
+  change is Matlab compatible.  Inline functions are deprecated in
+  both Matlab and Octave and support may eventually be removed.
+  Anonymous functions can be used to replace all instances of inline
+  functions.
+
+- The function `javaaddpath` now prepends new directories to the
+  existing dynamic classpath by default.  To append them instead, use
+  the new `"-end"` argument.  Multiple directories may now be specified
+  in a cell array of strings.
+
+- An undocumented function `gui_mainfcn` has been added, for compatibility
+  with figures created with Matlab's GUIDE.
+
+- Several validator functions of type `mustBe*` have been added.  See
+  the list of new functions below.
+
+### Alphabetical list of new functions added in Octave 6
+
+* `auto_repeat_debug_command`
+* `commandhistory`
+* `commandwindow`
+* `filebrowser`
+* `is_same_file`
+* `lightangle`
+* `mustBeFinite`
+* `mustBeGreaterThan`
+* `mustBeGreaterThanOrEqual`
+* `mustBeInteger`
+* `mustBeLessThan`
+* `mustBeLessThanOrEqual`
+* `mustBeMember`
+* `mustBeNegative`
+* `mustBeNonempty`
+* `mustBeNonNan`
+* `mustBeNonnegative`
+* `mustBeNonpositive`
+* `mustBeNonsparse`
+* `mustBeNonzero`
+* `mustBeNumeric`
+* `mustBeNumericOrLogical`
+* `mustBePositive`
+* `mustBeReal`
+* `namedargs2cell`
+* `newline`
+* `ode23s`
+* `ostreamtube`
+* `rescale`
+* `rotx`
+* `roty`
+* `rotz`
+* `stream2`
+* `stream3`
+* `streamline`
+* `streamtube`
+* `uisetfont`
+* `verLessThan`
+* `web`
+* `weboptions`
+* `webread`
+* `webwrite`
+* `workspace`
+
+
+### Deprecated functions and properties
+
+The following functions and properties have been deprecated in Octave 6
+and will be removed from Octave 8 (or whatever version is the second
+major release after 6):
+
+- Functions
+
+  Function               | Replacement
+  -----------------------|------------------
+  `runtests`             | `oruntests`
+
+- Properties
+
+  Object           | Property      | Value
+  -----------------|---------------|------------
+                   |               |
+
+- The environment variable used by `mkoctfile` for linker flags is now
+  `LDFLAGS` rather than `LFLAGS`.  `LFLAGS` is deprecated, and a warning
+  is emitted if it is used, but it will continue to work.
+
+
+### Removed functions and properties
+
+The following functions and properties were deprecated in Octave 4.4
+and have been removed from Octave 6.
+
+- Functions
+
+  Function             | Replacement
+  ---------------------|------------------
+  `chop`               | `sprintf` for visual results
+  `desktop`            | `isguirunning`
+  `tmpnam`             | `tempname`
+  `toascii`            | `double`
+  `java2mat`           | `__java2mat__`
+
+- Properties
+
+  Object               | Property                  | Value
+  ---------------------|---------------------------|-----------------------
+  `annotation`         | `edgecolor ("rectangle")` |
+  `axes`               | `drawmode`                |
+  `figure`             | `doublebuffer`            |
+                       | `mincolormap`             |
+                       | `wvisual`                 |
+                       | `wvisualmode`             |
+                       | `xdisplay`                |
+                       | `xvisual`                 |
+                       | `xvisualmode`             |
+  `line`               | `interpreter`             |
+  `patch`              | `interpreter`             |
+  `surface`            | `interpreter`             |
+  `text`               | `fontweight`              | `"demi"` and `"light"`
+  `uibuttongroup`      | `fontweight`              | `"demi"` and `"light"`
+  `uicontrol`          | `fontweight`              | `"demi"` and `"light"`
+  `uipanel`            | `fontweight`              | `"demi"` and `"light"`
+  `uitable`            | `fontweight`              | `"demi"` and `"light"`
+
+
+### Old release news
+
+- [Octave 5.x](etc/NEWS.5)
+- [Octave 4.x](etc/NEWS.4)
+- [Octave 3.x](etc/NEWS.3)
+- [Octave 2.x](etc/NEWS.2)
+- [Octave 1.x](etc/NEWS.1)
--- a/examples/code/@FIRfilter/FIRfilter.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/examples/code/@FIRfilter/FIRfilter.m	Thu Nov 19 13:08:00 2020 -0800
@@ -6,10 +6,6 @@
 
 function f = FIRfilter (p)
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   if (nargin == 0)
     p = @polynomial ([1]);
   elseif (! isa (p, "polynomial"))
--- a/examples/code/@FIRfilter/FIRfilter_aggregation.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/examples/code/@FIRfilter/FIRfilter_aggregation.m	Thu Nov 19 13:08:00 2020 -0800
@@ -6,10 +6,6 @@
 
 function f = FIRfilter (p)
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   if (nargin == 0)
     f.polynomial = @polynomial ([1]);
   else
--- a/examples/code/@polynomial/get.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/examples/code/@polynomial/get.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,6 +1,6 @@
 function val = get (p, prop)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/examples/code/@polynomial/polynomial.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/examples/code/@polynomial/polynomial.m	Thu Nov 19 13:08:00 2020 -0800
@@ -13,10 +13,6 @@
 
 function p = polynomial (a)
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   if (nargin == 0)
     p.poly = 0;
     p = class (p, "polynomial");
--- a/examples/code/@polynomial/polynomial_superiorto.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/examples/code/@polynomial/polynomial_superiorto.m	Thu Nov 19 13:08:00 2020 -0800
@@ -13,10 +13,6 @@
 
 function p = polynomial (a)
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   if (nargin == 0)
     p.poly = [0];
     p = class (p, "polynomial");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/code/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,75 @@
+%canon_reldir%_EXTRA_DIST =
+
+%canon_reldir%_CLEANFILES =
+%canon_reldir%_DISTCLEANFILES =
+%canon_reldir%_MAINTAINERCLEANFILES =
+
+%canon_reldir%_SRC = \
+  %reldir%/@FIRfilter/FIRfilter.m \
+  %reldir%/@FIRfilter/FIRfilter_aggregation.m \
+  %reldir%/@FIRfilter/display.m \
+  %reldir%/@FIRfilter/subsasgn.m \
+  %reldir%/@FIRfilter/subsref.m \
+  %reldir%/@polynomial/disp.m \
+  %reldir%/@polynomial/double.m \
+  %reldir%/@polynomial/end.m \
+  %reldir%/@polynomial/get.m \
+  %reldir%/@polynomial/mtimes.m \
+  %reldir%/@polynomial/numel.m \
+  %reldir%/@polynomial/plot.m \
+  %reldir%/@polynomial/polynomial.m \
+  %reldir%/@polynomial/polynomial_superiorto.m \
+  %reldir%/@polynomial/polyval.m \
+  %reldir%/@polynomial/roots.m \
+  %reldir%/@polynomial/set.m \
+  %reldir%/@polynomial/subsasgn.m \
+  %reldir%/@polynomial/subsref.m \
+  %reldir%/addtwomatrices.cc \
+  %reldir%/celldemo.cc \
+  %reldir%/embedded.cc \
+  %reldir%/fortrandemo.cc \
+  %reldir%/fortransub.f \
+  %reldir%/funcdemo.cc \
+  %reldir%/globaldemo.cc \
+  %reldir%/helloworld.cc \
+  %reldir%/make_int.cc \
+  %reldir%/mex_demo.c \
+  %reldir%/mycell.c \
+  %reldir%/myfeval.c \
+  %reldir%/myfevalf.f \
+  %reldir%/myfunc.c \
+  %reldir%/myhello.c \
+  %reldir%/mypow2.c \
+  %reldir%/myprop.c \
+  %reldir%/myset.c \
+  %reldir%/mysparse.c \
+  %reldir%/mystring.c \
+  %reldir%/mystruct.c \
+  %reldir%/oct_demo.cc \
+  %reldir%/oregonator.cc \
+  %reldir%/oregonator.m \
+  %reldir%/paramdemo.cc \
+  %reldir%/polynomial2.m \
+  %reldir%/standalone.cc \
+  %reldir%/standalonebuiltin.cc \
+  %reldir%/stringdemo.cc \
+  %reldir%/structdemo.cc \
+  %reldir%/unwinddemo.cc
+
+%canon_reldir%_EXTRA_DIST += \
+  $(%canon_reldir%_SRC)
+
+EXTRA_DIST += $(%canon_reldir%_EXTRA_DIST)
+
+CLEANFILES += $(%canon_reldir%_CLEANFILES)
+DISTCLEANFILES += $(%canon_reldir%_DISTCLEANFILES)
+MAINTAINERCLEANFILES += $(%canon_reldir%_MAINTAINERCLEANFILES)
+
+examples-clean:
+	rm -f $(%canon_reldir%_CLEANFILES)
+
+examples-distclean: examples-clean
+	rm -f $(%canon_reldir%_DISTCLEANFILES)
+
+examples-maintainer-clean: examples-distclean
+	rm -f $(%canon_reldir%_MAINTAINERCLEANFILES)
--- a/examples/code/polynomial2.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/examples/code/polynomial2.m	Thu Nov 19 13:08:00 2020 -0800
@@ -5,10 +5,6 @@
 
   methods
     function p = polynomial2 (a)
-      if (nargin > 1)
-        print_usage ();
-      endif
-
       if (nargin == 1)
         if (isa (a, "polynomial2"))
           p.poly = a.poly;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/data/README	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,51 @@
+* penny data file:
+
+  See the discussion here:
+  https://savannah.gnu.org/patch/?func=detailitem&item_id=8472
+
+* west0479 data file:
+
+  Chemical engineering plant models Eight stage column section, all
+  rigorous from set CHEMWEST, from the Harwell-Boeing Collection.
+
+  west0479.mtx: original file obtained from from
+  https://math.nist.gov/MatrixMarket/data/Harwell-Boeing/chemwest/west0479.html
+
+  west0479.mat: generated from west0479.mtx as follows:
+
+    x = load ("west0479.mtx");
+    nr = x(1,1);
+    nc = x(1,2);
+    i = x(2:end,1);
+    j = x(2:end,2);
+    sv = x(2:end,3);
+    west0479 = sparse(i, j, sv, nr, nc);
+    save -text west0479.mat west0479
+
+  Note that the original file has 1910 entries but 22 of them are exact
+  zeros:
+
+    384 86  0.0000000000000e+00
+    360 116  0.0000000000000e+00
+    361 117  0.0000000000000e+00
+    362 118  0.0000000000000e+00
+    238 224  0.0000000000000e+00
+    239 225  0.0000000000000e+00
+    240 226  0.0000000000000e+00
+    250 240  0.0000000000000e+00
+    251 241  0.0000000000000e+00
+    252 242  0.0000000000000e+00
+    272 259  0.0000000000000e+00
+    273 260  0.0000000000000e+00
+    274 261  0.0000000000000e+00
+    294 278  0.0000000000000e+00
+    295 279  0.0000000000000e+00
+    296 280  0.0000000000000e+00
+    316 297  0.0000000000000e+00
+    317 298  0.0000000000000e+00
+    318 299  0.0000000000000e+00
+    338 316  0.0000000000000e+00
+    339 317  0.0000000000000e+00
+    340 318  0.0000000000000e+00
+
+  These are not explicitly included in the west0479.mat file.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/data/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,15 @@
+%canon_reldir%_EXTRA_DIST =
+
+%canon_reldir%_DAT = \
+  %reldir%/penny.mat \
+  %reldir%/west0479.mat
+
+%canon_reldir%_EXTRA_DIST += \
+  $(%canon_reldir%_DAT) \
+  %reldir%/README \
+  %reldir%/west0479.mtx
+
+octdata_DATA += \
+  $(%canon_reldir%_DAT)
+
+EXTRA_DIST += $(%canon_reldir%_EXTRA_DIST)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/data/west0479.mat	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1896 @@
+# Created by Octave 5.2.0, Thu Jun 04 22:49:15 2020 EDT <jwe@devnull>
+# name: west0479
+# type: sparse matrix
+# nnz: 1888
+# rows: 479
+# columns: 479
+25 1 1
+31 1 -0.037648130000000002
+87 1 -0.34423959999999998
+26 2 1
+31 2 -0.024522619999999998
+88 2 -0.3737086
+27 3 1
+31 3 -0.036613039999999999
+89 3 -0.83693790000000001
+28 4 130
+29 4 -2.433767
+29 5 1
+30 5 -1.6140909999999999
+30 6 1.6140909999999999
+31 6 -0.21873210000000001
+87 6 -1
+88 6 -1
+89 6 -1
+32 7 -1.138352
+43 7 0.036694280000000003
+111 7 0.099316360000000006
+112 7 0.099316360000000006
+113 7 0.099316360000000006
+33 8 -0.5
+43 8 0.016117289999999999
+111 8 0.087245760000000006
+34 9 -0.36119180000000001
+43 9 0.01164286
+112 9 0.1050415
+35 10 -0.3218876
+43 10 0.01037591
+113 10 0.1404166
+36 11 -0.43624160000000001
+37 11 -0.76804249999999996
+38 11 -0.14302790000000001
+39 11 -0.15938859999999999
+37 12 1
+43 12 -0.048560819999999998
+111 12 -0.2628684
+38 13 1
+43 13 -0.030925950000000001
+112 13 -0.27901280000000001
+39 14 1
+43 14 -0.046123589999999999
+113 14 -0.62418819999999997
+40 15 5.2824359999999997
+42 15 -0.61239209999999999
+41 16 0.2886822
+42 16 -0.2163815
+42 17 1.3287739999999999
+43 17 -0.36946859999999998
+111 17 -1
+112 17 -1
+113 17 -1
+2 18 48.176470000000002
+8 18 -1
+11 18 -3.3474840000000003e-05
+3 19 83.5
+9 19 -1
+12 19 -4.1365390000000001e-05
+4 20 171.94120000000001
+10 20 -1
+13 20 -8.4843450000000005e-05
+5 21 96.651380000000003
+8 21 2.5
+11 21 3.3474840000000003e-05
+6 22 168.2706
+9 22 2.5
+12 22 4.1365390000000001e-05
+7 23 347.5872
+10 23 2.5
+13 23 8.4843450000000005e-05
+8 24 1
+17 24 -0.1106967
+27 24 1.605232
+9 25 1
+17 25 -0.089808520000000003
+10 26 1
+17 26 -0.15173690000000001
+11 27 1.0104550000000001
+18 27 -0.5
+12 28 1.005978
+18 28 -0.29999999999999999
+13 29 1.002885
+18 29 -0.20000000000000001
+14 30 1
+17 30 -0.1811855
+15 31 1
+17 31 -0.24002390000000001
+16 32 1
+17 32 -0.22654840000000001
+17 33 1
+19 33 -1
+30 33 1.5
+42 33 0.5
+18 34 1
+20 34 -316220
+23 34 -12323.690000000001
+24 34 -1
+30 34 -35226.800000000003
+41 34 18449.02
+19 35 5.2983390000000004
+21 35 0.0024526869999999998
+20 36 1080.8589999999999
+21 36 -0.2050215
+21 37 0.14419199999999999
+22 37 63.05986
+30 37 -0.1159299
+22 38 -18449.02
+24 38 0.84533389999999997
+40 38 -18449.02
+41 38 -15595.58
+23 39 1
+30 39 0.20204929999999999
+42 39 -0.88547100000000001
+24 40 0.0001000234
+30 40 2.4483389999999998
+42 40 0.81611299999999998
+68 41 1
+74 41 -0.0002278669
+99 41 -0.26243949999999999
+69 42 1
+74 42 -0.00041887629999999999
+100 42 -0.32161960000000001
+70 43 1
+74 43 -0.001576933
+101 43 -0.72647609999999996
+71 44 300
+72 44 -2.8518910000000002
+72 45 1
+73 45 -0.28701589999999999
+73 46 0.28701589999999999
+74 46 -0.0043413219999999999
+99 46 -1
+100 46 -1
+101 46 -1
+75 47 -1.138352
+86 47 0.042002860000000003
+123 47 0.9414806
+124 47 0.9414806
+125 47 0.9414806
+76 48 -0.3218876
+86 48 0.011877
+123 48 1.3310949999999999
+77 49 -0.36119180000000001
+86 49 0.013327240000000001
+124 49 0.99575290000000005
+78 50 -0.5
+86 50 0.01844898
+125 50 0.82705600000000001
+79 51 -1
+80 51 -19.239999999999998
+81 51 -3.8029999999999999
+82 51 -9.4809999999999999
+80 52 1
+86 52 -0.00088757840000000001
+123 52 -0.099473919999999993
+81 53 1
+86 53 -0.0013313680000000001
+124 53 -0.099473919999999993
+82 54 1
+86 54 -0.0022189459999999999
+125 54 -0.099473919999999993
+83 55 1.177613
+85 55 -3.1089630000000001
+84 56 0.99194249999999995
+85 56 -2.640056
+85 57 3.1921119999999998
+86 57 -0.044613630000000001
+123 57 -1
+124 57 -1
+125 57 -1
+45 58 109.86879999999999
+51 58 -1
+54 58 -3.3081099999999997e-05
+46 59 191.38460000000001
+52 59 -1
+55 59 -4.1084670000000001e-05
+47 60 395.4796
+53 60 -1
+56 60 -8.456383e-05
+48 61 221.73390000000001
+51 61 2.5
+54 61 3.3081099999999997e-05
+49 62 387.00920000000002
+52 62 2.5
+55 62 4.1084670000000001e-05
+50 63 800.81650000000002
+53 63 2.5
+56 63 8.456383e-05
+51 64 1
+60 64 -0.0091702290000000002
+52 65 1
+60 65 -0.046441099999999999
+53 66 1
+60 66 -0.48999189999999998
+54 67 1.0045299999999999
+61 67 -0.20000000000000001
+55 68 1.002591
+61 68 -0.29999999999999999
+56 69 1.00125
+61 69 -0.5
+57 70 1
+60 70 -0.037500529999999997
+58 71 1
+60 71 -0.124143
+59 72 1
+60 72 -0.29275319999999999
+60 73 1
+62 73 -1
+73 73 0.18537329999999999
+85 73 0.06179109
+61 74 1
+63 74 -316220
+66 74 -16364.190000000001
+67 74 -1
+73 74 -4696.7820000000002
+84 74 131.85400000000001
+62 75 22.12913
+64 75 0.95375259999999995
+63 76 2494.29
+64 76 -1.021587
+64 77 0.88782810000000001
+65 77 1.0400419999999999
+73 77 -2.640056
+65 78 -131.85400000000001
+67 78 0.0080574700000000006
+83 78 -131.85400000000001
+84 78 -1.0624089999999999
+66 79 1
+73 79 0.1016426
+85 79 -0.06179109
+67 80 0.0076452569999999999
+73 80 23.098949999999999
+85 80 7.699649
+31 81 1
+244 81 1
+43 82 1
+1 83 1
+17 83 -3.850231
+18 83 -8.4599350000000005e-05
+31 83 2.0159099999999999
+35 83 1
+43 83 1.596171
+243 83 -0.78975119999999999
+74 84 1
+388 84 0.88175619999999999
+86 85 1
+44 86 1
+60 86 -2.7937599999999998
+61 86 -8.4458229999999999e-05
+74 86 2.0156649999999998
+78 86 1
+86 86 1.5939939999999999
+387 86 -0.96191499999999996
+385 87 0.002424669
+386 87 0.030362779999999999
+387 87 0.67304509999999995
+388 87 1.45936
+96 88 0.016896609999999999
+97 88 0.034848030000000002
+98 88 -0.060080179999999997
+120 88 -0.55527170000000003
+121 88 -0.47703980000000001
+122 88 -0.1858293
+141 88 -1
+142 88 -1
+143 88 -1
+185 88 -55.188569999999999
+186 88 -95.676860000000005
+187 88 -215.83770000000001
+389 88 1
+438 88 1
+439 88 1
+440 88 1
+441 88 1
+442 88 1
+443 88 1
+450 88 -0.0018907559999999999
+451 88 -0.0015311400000000001
+452 88 -0.001013726
+455 88 2.5
+456 88 26.063700000000001
+458 88 1
+459 88 -1.5
+461 88 -9.6031809999999993
+462 88 -9.4541850000000007
+463 88 -9.4376809999999995
+464 88 -48.295720000000003
+472 88 0.90759219999999996
+473 88 -4.3759670000000002
+474 88 -8.997992
+475 88 -8.8819579999999991
+476 88 1
+182 89 1
+183 89 1
+184 89 1
+391 89 1
+455 89 -1
+456 89 -26.063700000000001
+458 89 -1
+468 89 1
+388 90 -1.45936
+467 90 1
+479 91 1
+203 92 -1
+204 92 -1
+205 92 -1
+209 92 1
+210 92 1
+211 92 1
+382 92 56.953099999999999
+385 92 0.70583249999999997
+437 92 1
+453 92 -0.64913719999999997
+454 92 -3.2948409999999999e-05
+467 92 0.53807479999999996
+469 92 1
+479 92 0.082471119999999995
+203 93 -1
+204 93 -1
+205 93 -1
+209 93 1
+210 93 1
+211 93 1
+383 93 11.58384
+386 93 0.70583249999999997
+437 93 1
+453 93 -1.021542
+454 93 -4.0990330000000002e-05
+467 93 -0.36302479999999998
+470 93 1
+479 93 0.069522609999999999
+203 94 -1
+204 94 -1
+205 94 -1
+209 94 1
+210 94 1
+211 94 1
+384 94 0.3209631
+387 94 0.70583249999999997
+437 94 1
+453 94 -2.049007
+454 94 -8.4470029999999998e-05
+467 94 0.91353620000000002
+471 94 1
+479 94 0.83976379999999995
+241 95 0.55083519999999997
+242 95 0.4489223
+243 95 0.0002425203
+244 95 0.40528330000000001
+108 96 -0.067276619999999995
+109 96 -0.15700610000000001
+110 96 -0.097475699999999998
+132 96 -0.25060070000000001
+133 96 -0.2802617
+134 96 0.1008491
+245 96 -1
+395 96 1
+396 96 1
+397 96 1
+398 96 1
+399 96 1
+400 96 1
+407 96 -0.0028636019999999998
+408 96 -0.0023162590000000002
+409 96 -0.00153089
+412 96 2.5
+413 96 11.5878
+415 96 1
+416 96 -1.101224
+418 96 -1.3644320000000001
+419 96 -1.2188209999999999
+420 96 -1.2108589999999999
+421 96 -34.621049999999997
+429 96 0.60313589999999995
+430 96 -0.59963840000000002
+431 96 -1.403392
+432 96 -1.3703860000000001
+433 96 1
+246 97 1
+412 97 -1
+413 97 -11.5878
+415 97 -1
+425 97 1
+244 98 -0.40528330000000001
+424 98 1
+436 99 1
+160 100 -0.85938400000000004
+161 100 -0.773339
+162 100 -0.79517400000000005
+238 100 -1
+241 100 1
+394 100 1
+410 100 -1.623659
+411 100 -3.3032779999999999e-05
+424 100 3.5720350000000001
+426 100 1
+436 100 0.92435319999999999
+160 101 -1.171821
+161 101 -1.277352
+162 101 -1.250508
+239 101 -1
+242 101 1
+394 101 1
+410 101 -2.4602889999999999
+411 101 -4.1050809999999997e-05
+424 101 -2.1785329999999998
+427 101 1
+436 101 0.65098420000000001
+160 102 -2.3280470000000002
+161 102 -2.4161549999999998
+162 102 -2.5121660000000001
+240 102 -1
+243 102 1
+394 102 1
+410 102 -4.7536199999999997
+411 102 -8.45305e-05
+424 102 6.1671399999999998
+428 102 1
+436 102 3.3966910000000001
+241 103 0.043736570000000002
+242 103 0.57396460000000005
+243 103 0.15834899999999999
+244 103 0.18781249999999999
+253 103 -0.044344130000000002
+254 103 -0.58193779999999995
+255 103 -0.16054869999999999
+256 103 -1
+135 104 -1
+136 104 -1
+137 104 -1
+151 104 -62.680900000000001
+152 104 -123.89
+153 104 -464.35550000000001
+245 104 1
+248 104 -0.051646549999999999
+249 104 -0.32417620000000003
+148 105 1
+149 105 1
+150 105 1
+247 105 1
+244 106 -0.18781249999999999
+248 106 1
+256 106 1
+249 107 1
+147 108 1
+169 108 -1
+170 108 -1
+171 108 -1
+175 108 1
+176 108 1
+177 108 1
+238 108 9.7738750000000003
+241 108 0.77605020000000002
+248 108 7.2528309999999996
+249 108 0.78041000000000005
+253 108 -0.78683060000000005
+147 109 1
+169 109 -1
+170 109 -1
+171 109 -1
+175 109 1
+176 109 1
+177 109 1
+239 109 0.60698209999999997
+242 109 0.77605020000000002
+248 109 -2.3895080000000002
+249 109 0.68493979999999999
+254 109 -0.78683060000000005
+147 110 1
+169 110 -1
+170 110 -1
+171 110 -1
+175 110 1
+176 110 1
+177 110 1
+240 110 0.001188564
+243 110 0.77605020000000002
+248 110 11.55883
+249 110 2.2026439999999998
+255 110 -0.78683060000000005
+363 111 -0.17051479999999999
+364 111 -0.43429630000000002
+365 111 -0.26674209999999998
+366 111 -2.609302
+385 111 0.1956447
+386 111 0.49830160000000001
+387 111 0.30605369999999998
+388 111 0.42239599999999999
+215 112 1
+216 112 1
+217 112 1
+218 112 1
+219 112 1
+220 112 1
+227 112 -0.0018907559999999999
+228 112 -0.0015311400000000001
+229 112 -0.001013726
+232 112 2.5
+233 112 16.672409999999999
+235 112 1
+236 112 -1.5
+389 112 -1
+392 112 -0.46212130000000001
+393 112 -0.1234962
+232 113 -1
+233 113 -16.672409999999999
+235 113 -1
+368 113 -1
+369 113 -1
+390 113 1
+366 114 2.609302
+388 114 -0.42239599999999999
+392 114 1
+393 115 1
+181 116 1
+194 116 -0.58697619999999995
+195 116 -0.50651550000000001
+196 116 -0.5139918
+230 116 -1.0366850000000001
+231 116 -3.2948409999999999e-05
+363 116 -0.87155309999999997
+382 116 -1
+385 116 1
+392 116 2.63998
+393 116 0.55742069999999999
+181 117 1
+194 117 -0.80016370000000003
+195 117 -0.83640899999999996
+196 117 -0.8081026
+230 117 -1.6376949999999999
+231 117 -4.0990330000000002e-05
+364 117 -0.87155309999999997
+383 117 -1
+386 117 1
+392 117 -1.7736780000000001
+393 117 0.40754220000000002
+181 118 1
+194 118 -1.5893889999999999
+195 118 -1.5818110000000001
+196 118 -1.6231180000000001
+230 118 -3.205686
+231 118 -8.4470029999999998e-05
+365 118 -0.87155309999999997
+384 118 -1
+387 118 1
+392 118 4.4676090000000004
+393 118 2.2475290000000001
+93 119 -1
+96 119 -1
+248 119 -0.40421560000000001
+262 119 -0.1818777
+284 119 -0.1563455
+306 119 -0.15456990000000001
+328 119 -0.1521778
+350 119 -0.091905799999999996
+372 119 -0.0078705370000000004
+94 120 -1
+97 120 -1
+248 120 -1.8091710000000001
+262 120 -3.1896550000000001
+284 120 -3.3490190000000002
+306 120 -3.358644
+328 120 -3.3085849999999999
+350 120 -1.96787
+372 120 -0.11333559999999999
+95 121 -1
+98 121 -1
+248 121 -2.4566020000000002
+262 121 -4.1011280000000001
+284 121 -4.2908920000000004
+306 121 -4.3026030000000004
+328 121 -4.2541469999999997
+350 121 -2.9523890000000002
+372 121 -1.157365
+93 122 -0.0081214960000000006
+96 122 -0.016896609999999999
+248 122 -0.0045387600000000002
+262 122 -0.00217052
+284 122 -0.0018740689999999999
+306 122 -0.0018533180000000001
+328 122 -0.0018248369999999999
+350 122 -0.001106561
+372 122 -0.0001054494
+94 123 -0.016749989999999999
+97 123 -0.034848030000000002
+248 123 -0.041896919999999997
+262 123 -0.078506679999999995
+284 123 -0.082793510000000001
+306 123 -0.083055320000000002
+328 123 -0.081826380000000004
+350 123 -0.048866050000000001
+372 123 -0.0031317319999999999
+95 124 -0.028878029999999999
+98 124 -0.060080179999999997
+248 124 -0.098082240000000001
+262 124 -0.17402809999999999
+284 124 -0.18288550000000001
+306 124 -0.1834374
+328 124 -0.18139140000000001
+350 124 -0.12639719999999999
+372 124 -0.055136770000000002
+105 125 -1
+108 125 -1
+264 125 -0.76362319999999995
+286 125 -0.5413211
+308 125 -0.52907530000000003
+330 125 -0.52832599999999996
+352 125 -0.52965340000000005
+374 125 -0.59901059999999995
+392 125 -0.57467679999999999
+106 126 -1
+109 126 -1
+264 126 -1.4679789999999999
+286 126 -1.289806
+308 126 -1.279992
+330 126 -1.279385
+352 126 -1.2801739999999999
+374 126 -1.3601430000000001
+392 126 -0.71491899999999997
+107 127 -1
+110 127 -1
+264 127 -0.0043708569999999997
+286 127 -0.0039541009999999998
+308 127 -0.0039318030000000002
+330 127 -0.0039476679999999997
+352 127 -0.0047490229999999998
+374 127 -0.072455389999999995
+392 127 -1.6023639999999999
+105 128 -0.1122933
+108 128 -0.067276619999999995
+264 128 -0.054601370000000003
+286 128 -0.038877219999999997
+308 128 -0.03800866
+330 128 -0.037958989999999998
+352 128 -0.038208859999999997
+374 128 -0.048085490000000002
+392 128 -0.05817862
+106 129 -0.2620633
+109 129 -0.15700610000000001
+264 129 -0.24496080000000001
+286 129 -0.2161806
+308 129 -0.21459739999999999
+330 129 -0.21451909999999999
+352 129 -0.21552299999999999
+374 129 -0.25480999999999998
+392 129 -0.16890749999999999
+107 130 -0.1626995
+110 130 -0.097475699999999998
+264 130 -0.00045281759999999999
+286 130 -0.00041145290000000001
+308 130 -0.00040925029999999999
+330 130 -0.0004109467
+352 130 -0.00049637369999999995
+374 130 -0.0084271850000000002
+392 130 -0.2350352
+117 131 -1
+120 131 -1
+249 131 -0.069702840000000002
+263 131 -0.019243320000000001
+285 131 -0.01583793
+307 131 -0.01561791
+329 131 -0.01558321
+351 131 -0.01471856
+373 131 -0.0057599519999999996
+118 132 -1
+121 132 -1
+249 132 -0.74171359999999997
+263 132 -0.80234939999999999
+285 132 -0.80658470000000004
+307 132 -0.80682860000000001
+329 132 -0.80550310000000003
+351 132 -0.74926979999999999
+373 132 -0.19719700000000001
+119 133 -1
+122 133 -1
+249 133 -0.51275979999999999
+263 133 -0.52522530000000001
+285 133 -0.52614130000000003
+307 133 -0.52622449999999998
+329 133 -0.52730270000000001
+351 133 -0.57231860000000001
+373 133 -1.025242
+117 134 -0.46575929999999999
+120 134 -0.96900310000000001
+249 134 -0.044884880000000002
+263 134 -0.01317012
+285 134 -0.01088739
+307 134 -0.010739240000000001
+329 134 -0.01071655
+351 134 -0.01016303
+373 134 -0.0044257189999999998
+118 135 -0.57440230000000003
+121 135 -1.195033
+249 135 -0.58903419999999995
+263 135 -0.67721739999999997
+285 135 -0.68380180000000002
+307 135 -0.68420530000000002
+329 135 -0.68315610000000004
+351 135 -0.63804399999999994
+373 135 -0.18686159999999999
+119 136 -0.2292285
+122 136 -0.47690549999999998
+249 136 -0.1625065
+263 136 -0.17691419999999999
+285 136 -0.1780062
+307 136 -0.17808560000000001
+329 136 -0.17846999999999999
+351 136 -0.19449250000000001
+373 136 -0.38770260000000001
+129 137 -1
+132 137 -1
+265 137 -0.34272789999999997
+287 137 -0.2911376
+309 137 -0.2876937
+331 137 -0.28748889999999999
+353 137 -0.28823179999999998
+375 137 -0.30269869999999999
+393 137 -0.17507890000000001
+130 138 -1
+133 138 -1
+265 138 -1.0623339999999999
+287 138 -1.118506
+309 138 -1.1222529999999999
+331 138 -1.122512
+353 138 -1.1232850000000001
+375 138 -1.1082339999999999
+393 138 -0.35118640000000001
+131 139 -1
+134 139 -1
+265 139 -0.0023999820000000002
+287 139 -0.00260173
+309 139 -0.0026156270000000001
+331 139 -0.0026280330000000001
+353 139 -0.0031617350000000002
+375 139 -0.044793810000000003
+393 139 -0.59723090000000001
+129 140 -2.0182530000000001
+132 140 -1.209166
+265 140 -0.44044889999999998
+287 140 -0.3758029
+309 140 -0.37146430000000003
+331 140 -0.37124049999999997
+353 140 -0.37371090000000001
+375 140 -0.43672879999999997
+393 140 -0.31856279999999998
+130 141 -2.5626880000000001
+133 141 -1.535345
+265 141 -1.7335130000000001
+287 141 -1.833245
+309 141 -1.839915
+331 141 -1.840541
+353 141 -1.849286
+375 141 -2.0302660000000001
+393 141 -0.81137049999999999
+131 142 -0.92554289999999995
+134 142 -0.55450670000000002
+265 142 -0.0014144089999999999
+287 142 -0.001540086
+309 142 -0.0015487579999999999
+331 142 -0.0015562740000000001
+353 142 -0.001879925
+375 142 -0.029637400000000001
+393 142 -0.49833870000000002
+135 143 -1.4338919999999999
+141 143 -2.1577039999999998
+266 143 -1.523971
+288 143 -1.530708
+310 143 -1.531148
+332 143 -1.5313159999999999
+354 143 -1.537533
+376 143 -1.710928
+136 144 -0.94320599999999999
+142 144 -1.4193260000000001
+267 144 -1.0024599999999999
+289 144 -1.006891
+311 144 -1.0071810000000001
+333 144 -1.0072909999999999
+355 144 -1.0113810000000001
+377 144 -1.1254390000000001
+137 145 -0.59645269999999995
+143 145 -0.89753530000000004
+268 145 -0.63392269999999995
+290 145 -0.63672519999999999
+312 145 -0.63690829999999998
+334 145 -0.63697809999999999
+356 145 -0.63956420000000003
+378 145 -0.71169090000000002
+135 146 -1
+141 146 -1
+266 146 -1
+288 146 -1
+310 146 -1
+332 146 -1
+354 146 -1
+376 146 -1
+136 147 -1
+142 147 -1
+267 147 -1
+289 147 -1
+311 147 -1
+333 147 -1
+355 147 -1
+377 147 -1
+137 148 -1
+143 148 -1
+268 148 -1
+290 148 -1
+312 148 -1
+334 148 -1
+356 148 -1
+378 148 -1
+138 149 -1
+148 149 1
+238 149 0.55083519999999997
+139 150 -1
+149 150 1.6474949999999999
+239 150 0.73959730000000001
+140 151 -1
+150 151 841.35159999999996
+240 151 0.2040448
+144 152 -1
+182 152 1
+382 152 0.1956447
+145 153 -1
+183 153 1
+383 153 0.49830160000000001
+146 154 -1
+184 154 3.1156220000000001
+384 154 0.95354779999999995
+395 155 66.224919999999997
+401 155 -1
+404 155 -3.3282569999999997e-05
+396 156 115.06229999999999
+402 156 -1
+405 156 -4.122831e-05
+397 157 237.33869999999999
+403 157 -1
+406 157 -8.4706899999999994e-05
+398 158 133.245
+401 158 2.5
+404 158 3.3282569999999997e-05
+399 159 232.26390000000001
+402 159 2.5
+405 159 4.122831e-05
+400 160 480.18209999999999
+403 160 2.5
+406 160 8.4706899999999994e-05
+160 161 -0.47337899999999999
+401 161 1
+410 161 -0.2116876
+161 162 -0.57343169999999999
+402 162 1
+410 162 -0.31667149999999999
+162 163 -0.00060925110000000003
+403 163 1
+410 163 -3.511874e-07
+163 164 -4575.0039999999999
+404 164 1.0075620000000001
+411 164 -0.55083519999999997
+164 165 -3681.4160000000002
+405 165 1.004324
+411 165 -0.4489223
+165 166 -1787.818
+406 166 1.002087
+411 166 -0.0002425203
+160 167 -0.52605639999999998
+161 167 -0.42598229999999998
+407 167 1
+410 167 -0.47048839999999997
+160 168 -0.00056459870000000005
+162 168 -0.4380098
+408 168 1
+410 168 -0.00050495930000000002
+161 169 -0.00058596669999999996
+162 169 -0.56138089999999996
+409 169 1
+410 169 -0.00064718760000000001
+163 170 -1
+164 170 -1
+165 170 -1
+410 170 1
+412 170 -1
+423 170 0.061444209999999999
+435 170 0.0204814
+157 171 -1
+163 171 4124.0600000000004
+164 171 4124.0600000000004
+165 171 4124.0600000000004
+411 171 1
+413 171 -316220
+416 171 -20034.240000000002
+417 171 -1
+423 171 -2625.6570000000002
+434 171 222.12899999999999
+412 172 18.737269999999999
+414 172 0.94488159999999999
+413 173 1494.367
+414 173 -1.02078
+158 174 -0.99186010000000002
+163 174 -17.922339999999998
+164 174 -17.922339999999998
+165 174 -17.922339999999998
+414 174 0.86282899999999996
+415 174 1.0497190000000001
+423 174 -0.73414950000000001
+157 175 0.0081398600000000005
+415 175 -222.12899999999999
+417 175 0.0081398600000000005
+433 175 -222.12899999999999
+434 175 -1.8080989999999999
+163 176 -1.0913280000000001
+164 176 -1.629397
+165 176 -1.4448529999999999
+416 176 1
+423 176 0.047364059999999999
+435 176 -0.027898139999999998
+417 177 0.0045385340000000003
+423 177 7.5792400000000004
+435 177 2.5264129999999998
+148 178 -1
+178 178 -1
+149 179 -1
+179 179 -1
+150 180 -1
+180 180 -1
+148 181 1.0266459999999999
+166 181 -1
+149 182 1.0737239999999999
+167 182 -1
+150 183 1.2081470000000001
+168 183 -1
+148 184 -1
+154 184 -1
+149 185 -1
+155 185 -1
+150 186 -1
+156 186 -1
+215 187 99.149730000000005
+221 187 -1
+224 187 -3.311398e-05
+216 188 172.6396
+222 188 -1
+225 188 -4.1108120000000002e-05
+217 189 356.63979999999998
+223 189 -1
+226 189 -8.4587179999999994e-05
+218 190 200.0008
+221 190 2.5
+224 190 3.311398e-05
+219 191 349.00330000000002
+222 191 2.5
+225 191 4.1108120000000002e-05
+220 192 722.06780000000003
+223 192 2.5
+226 192 8.4587179999999994e-05
+194 193 -0.1148388
+221 193 1
+230 193 -0.011645920000000001
+195 194 -0.41678389999999998
+222 194 1
+230 194 -0.17006160000000001
+196 195 -0.49676140000000002
+223 195 1
+230 195 -0.2436893
+197 196 -5276.8620000000001
+224 196 1.0050250000000001
+231 196 -0.1956447
+198 197 -4241.5910000000003
+225 197 1.002874
+231 197 -0.49830160000000001
+199 198 -2058.2939999999999
+226 198 1.001387
+231 198 -0.30605369999999998
+194 199 -0.39872279999999999
+195 199 -0.099097089999999999
+227 199 1
+230 199 -0.080869759999999999
+194 200 -0.48643839999999999
+196 200 -0.1005598
+228 200 1
+230 200 -0.098660410000000004
+195 201 -0.48411900000000002
+196 201 -0.4026788
+229 201 1
+230 201 -0.39507300000000001
+197 202 -1
+198 202 -1
+199 202 -1
+230 202 1
+232 202 -1
+191 203 -1
+197 203 3297.623
+198 203 3297.623
+199 203 3297.623
+231 203 1
+233 203 -316220
+236 203 -18966.66
+237 203 -1
+232 204 22.66987
+234 204 0.95486020000000005
+233 205 2248.7060000000001
+234 205 -1.0206550000000001
+192 206 -0.99229509999999999
+197 206 -21.898569999999999
+198 206 -21.898569999999999
+199 206 -21.898569999999999
+234 206 0.89000959999999996
+235 206 1.0392049999999999
+191 207 0.0077048969999999996
+235 207 -146.1362
+237 207 0.0077048969999999996
+197 208 -0.65890519999999997
+198 208 -1.1064970000000001
+199 208 -1.000909
+236 208 1
+237 209 0.0068956570000000003
+182 210 -1
+212 210 -1
+183 211 -1
+213 211 -1
+184 212 -1
+214 212 -1
+182 213 1
+200 213 -1
+183 214 1.0226759999999999
+201 214 -1
+184 215 1.091418
+202 215 -1
+182 216 -1
+188 216 -1
+183 217 -1
+189 217 -1
+184 218 -1
+190 218 -1
+241 219 -0.19969609999999999
+242 219 -0.78596160000000004
+243 219 -0.00064128229999999996
+244 219 0.40690409999999999
+253 219 0.20247019999999999
+254 219 0.79687960000000002
+255 219 0.00065019060000000002
+256 219 -2.166544
+257 220 -1
+264 220 -0.30001499999999998
+265 220 -0.40746149999999998
+246 221 -1
+247 221 -1
+258 221 1
+244 222 0.40690409999999999
+256 222 -2.166544
+264 222 1
+265 223 1
+241 224 -0.98629889999999998
+250 224 -1
+253 224 1
+261 224 1
+264 224 3.5018579999999999
+265 224 1.241884
+242 225 -0.98629889999999998
+251 225 -1
+254 225 1
+261 225 1
+264 225 -2.149559
+265 225 0.93602390000000002
+243 226 -0.98629889999999998
+252 226 -1
+255 226 1
+261 226 1
+264 226 6.0259859999999996
+265 226 4.0868380000000002
+253 227 0.0119553
+254 227 0.61475029999999997
+255 227 0.1605955
+256 227 0.59918099999999996
+275 227 -0.011949680000000001
+276 227 -0.61446120000000004
+277 227 -0.16052
+278 227 -1
+257 228 1
+262 228 -0.093350859999999994
+263 228 -0.34681810000000002
+266 228 -1
+267 228 -1
+268 228 -1
+259 229 1
+256 230 -0.59918099999999996
+262 230 1
+278 230 1
+263 231 1
+250 232 13.33342
+253 232 0.78730109999999998
+260 232 1
+262 232 12.12026
+263 232 0.77025089999999996
+275 232 -0.78693089999999999
+251 233 1.020551
+254 233 0.78730109999999998
+260 233 1
+262 233 -3.9843989999999998
+263 233 0.681342
+276 233 -0.78693089999999999
+252 234 0.0031874849999999999
+255 234 0.78730109999999998
+260 234 1
+262 234 19.25216
+263 234 2.236907
+277 234 -0.78693089999999999
+253 235 -0.17008129999999999
+254 235 -0.82969219999999999
+255 235 -0.00069701409999999996
+256 235 2.5673629999999998
+275 235 0.1700014
+276 235 0.82930199999999998
+277 235 0.00069668629999999996
+278 235 -4.2847869999999997
+279 236 -1
+286 236 -0.25546930000000001
+287 236 -0.41224569999999999
+258 237 -1
+259 237 -1
+280 237 1
+256 238 2.5673629999999998
+278 238 -4.2847869999999997
+286 238 1
+287 239 1
+253 240 -1.0004710000000001
+272 240 -1
+275 240 1
+283 240 1
+286 240 2.9555289999999999
+287 240 1.2544139999999999
+254 241 -1.0004710000000001
+273 241 -1
+276 241 1
+283 241 1
+286 241 -1.8159689999999999
+287 241 0.94521189999999999
+255 242 -1.0004710000000001
+274 242 -1
+277 242 1
+283 242 1
+286 242 5.0849970000000004
+287 242 4.1364789999999996
+250 243 0.20247019999999999
+269 243 -1
+251 244 0.79687960000000002
+270 244 -1
+252 245 0.20398230000000001
+271 245 -1
+275 246 0.0098180809999999993
+276 246 0.61664169999999996
+278 246 0.95579440000000004
+297 246 -0.0098175689999999999
+298 246 -0.61660959999999998
+299 246 -0.16051480000000001
+300 246 -1
+279 247 1
+284 247 -0.098217899999999997
+285 247 -0.34856389999999998
+288 247 -1
+289 247 -1
+290 247 -1
+281 248 1
+278 249 -0.95579440000000004
+284 249 1
+300 249 1
+285 250 1
+272 251 13.626709999999999
+275 251 0.78698299999999999
+282 251 1
+284 251 12.68233
+285 251 0.76942869999999997
+297 251 -0.78694200000000003
+273 252 1.058389
+276 252 0.78698299999999999
+282 252 1
+284 252 -4.1684890000000001
+285 252 0.68102850000000004
+298 252 -0.78694200000000003
+274 253 0.0034155829999999998
+277 253 0.78698299999999999
+282 253 1
+284 253 20.139959999999999
+285 253 2.2394150000000002
+299 253 -0.78694200000000003
+275 254 -0.16786980000000001
+276 254 -0.83148250000000001
+277 254 -0.00069990470000000002
+278 254 4.3289929999999996
+297 254 0.16786100000000001
+298 254 0.83143909999999999
+299 254 0.00069986820000000004
+300 254 -4.5292089999999998
+301 255 -1
+308 255 -0.2530153
+309 255 -0.4125625
+280 256 -1
+281 256 -1
+302 256 1
+278 257 4.3289929999999996
+300 257 -4.5292089999999998
+308 257 1
+309 258 1
+275 259 -1.0000519999999999
+294 259 -1
+297 259 1
+305 259 1
+308 259 2.9254359999999999
+309 259 1.2552490000000001
+276 260 -1.0000519999999999
+295 260 -1
+298 260 1
+305 260 1
+308 260 -1.797593
+309 260 0.94582429999999995
+277 261 -1.0000519999999999
+296 261 -1
+299 261 1
+305 261 1
+308 261 5.0331659999999996
+309 261 4.1397830000000004
+272 262 0.1700014
+291 262 -1
+273 263 0.82930199999999998
+292 263 -1
+274 264 0.20397290000000001
+293 264 -1
+297 265 0.0096798500000000003
+298 265 0.61671089999999995
+299 265 0.1605181
+300 265 0.99729840000000003
+319 265 -0.0096801700000000001
+320 265 -0.61673129999999998
+321 265 -0.16052340000000001
+322 265 -1
+301 266 1
+306 266 -0.09852872
+307 266 -0.34867100000000001
+310 266 -1
+311 266 -1
+312 266 -1
+303 267 1
+300 268 -0.99729840000000003
+306 268 1
+322 268 1
+307 269 1
+294 270 13.64601
+297 270 0.78690890000000002
+304 270 1
+306 270 12.716189999999999
+307 270 0.7693586
+319 270 -0.78693489999999999
+295 271 1.060897
+298 271 0.78690890000000002
+304 271 1
+306 271 -4.1795749999999998
+307 271 0.68099359999999998
+320 271 -0.78693489999999999
+296 272 0.003430968
+299 272 0.78690890000000002
+304 272 1
+306 272 20.19341
+307 272 2.2395320000000001
+321 272 -0.78693489999999999
+297 273 -0.16772329999999999
+298 273 -0.83154050000000002
+299 273 -0.00070311129999999996
+300 273 4.531911
+319 273 0.16772880000000001
+320 273 0.83156799999999997
+321 273 0.0007031346
+322 273 -4.5441880000000001
+323 274 -1
+330 274 -0.25288909999999998
+331 274 -0.41262900000000002
+302 275 -1
+303 275 -1
+324 275 1
+300 276 4.531911
+322 276 -4.5441880000000001
+330 276 1
+331 277 1
+297 278 -0.99996689999999999
+316 278 -1
+319 278 1
+327 278 1
+330 278 2.9235699999999998
+331 278 1.2552939999999999
+298 279 -0.99996689999999999
+317 279 -1
+320 279 1
+327 279 1
+330 279 -1.7964899999999999
+331 279 0.94585160000000001
+299 280 -0.99996689999999999
+318 280 -1
+321 280 1
+327 280 1
+330 280 5.029935
+331 280 4.1401399999999997
+294 281 0.16786100000000001
+313 281 -1
+295 282 0.83143909999999999
+314 282 -1
+296 283 0.20398559999999999
+315 283 -1
+319 284 0.0096473500000000007
+320 284 0.61499680000000001
+321 284 0.1606638
+322 284 1.012275
+341 284 -0.0096630710000000005
+342 284 -0.61599899999999996
+343 284 -0.1609257
+344 284 -1
+323 285 1
+328 285 -0.097740149999999998
+329 285 -0.348389
+332 285 -1
+333 285 -1
+334 285 -1
+325 286 1
+322 287 -1.012275
+328 287 1
+344 287 1
+329 288 1
+316 289 13.653370000000001
+319 289 0.78530800000000001
+326 289 1
+328 289 12.53604
+329 289 0.76861380000000001
+341 289 -0.7865877
+317 290 1.0618540000000001
+320 290 0.78530800000000001
+326 290 1
+328 290 -4.1203450000000004
+329 290 0.68034459999999997
+342 290 -0.7865877
+318 291 0.0034368480000000002
+321 291 0.78530800000000001
+326 291 1
+328 291 19.9072
+329 291 2.2374860000000001
+343 291 -0.7865877
+319 292 -0.16769600000000001
+320 292 -0.8298335
+321 292 -0.00084358209999999998
+322 292 4.5319130000000003
+341 292 0.16796929999999999
+342 292 0.83118579999999997
+343 292 0.00084495670000000003
+344 292 -4.4769569999999996
+345 293 -1
+352 293 -0.25422820000000002
+353 293 -0.41467850000000001
+324 294 -1
+325 294 -1
+346 294 1
+322 295 4.5319120000000002
+344 295 -4.4769569999999996
+352 295 1
+353 296 1
+319 297 -0.99837310000000001
+338 297 -1
+341 297 1
+349 297 1
+352 297 2.9258000000000002
+353 297 1.2548710000000001
+320 298 -0.99837310000000001
+339 298 -1
+342 298 1
+349 298 1
+352 298 -1.799474
+353 298 0.94529589999999997
+321 299 -0.99837310000000001
+340 299 -1
+343 299 1
+349 299 1
+352 299 5.032978
+353 299 4.1465319999999997
+316 300 0.16772880000000001
+335 300 -1
+317 301 0.83156799999999997
+336 301 -1
+318 302 0.20458699999999999
+337 302 -1
+341 303 0.0089580030000000008
+342 303 0.56239150000000004
+343 303 0.17143159999999999
+344 303 1.5349870000000001
+363 303 -0.0093684010000000002
+364 303 -0.58815669999999998
+365 303 -0.17928549999999999
+366 303 -1
+345 304 1
+350 304 -0.076424569999999997
+351 304 -0.33630700000000002
+354 304 -1
+355 304 -1
+356 304 -1
+347 305 1
+344 306 -1.5349870000000001
+350 306 1
+366 306 1
+351 307 1
+338 308 13.9277
+341 308 0.74278120000000003
+348 308 1
+350 308 7.7124139999999999
+351 308 0.73754050000000004
+363 308 -0.77681060000000002
+339 309 1.0977920000000001
+342 309 0.74278120000000003
+348 309 1
+350 309 -2.5345339999999998
+351 309 0.65320800000000001
+364 309 -0.77681060000000002
+340 310 0.00366104
+343 310 0.74278120000000003
+348 310 1
+350 310 12.244490000000001
+351 310 2.151386
+365 310 -0.77681060000000002
+341 311 -0.1672642
+342 311 -0.77757829999999994
+343 311 -0.01135093
+344 311 3.9419710000000001
+363 311 0.1749272
+364 311 0.81320190000000003
+365 311 0.01187095
+366 311 -2.568082
+367 312 -1
+374 312 -0.31132270000000001
+375 312 -0.45572679999999999
+346 313 -1
+347 313 -1
+368 313 1
+344 314 3.9419710000000001
+366 314 -2.568082
+374 314 1
+375 315 1
+341 316 -0.95619350000000003
+360 316 -1
+363 316 1
+371 316 1
+374 316 3.149454
+375 316 1.212998
+342 317 -0.95619350000000003
+361 317 -1
+364 317 1
+371 317 1
+374 317 -1.985919
+375 317 0.9070684
+343 318 -0.95619350000000003
+362 318 -1
+365 318 1
+371 318 1
+374 318 5.3936869999999999
+375 318 4.2274630000000002
+338 319 0.16796929999999999
+357 319 -1
+339 320 0.83118579999999997
+358 320 -1
+340 321 0.2307969
+359 321 -1
+363 322 0.0049560029999999996
+364 322 0.2092511
+365 322 0.4341566
+366 322 6.177384
+385 322 -0.0056864039999999999
+386 322 -0.24008989999999999
+387 322 -0.49814130000000001
+388 322 -1
+367 323 1
+372 323 -0.051899590000000002
+373 323 -0.22819929999999999
+376 323 -1
+377 323 -1
+378 323 -1
+369 324 1
+366 325 -6.177384
+372 325 1
+388 325 1
+373 326 1
+360 327 22.88466
+363 327 0.64836369999999999
+370 327 1
+372 327 1.04345
+373 327 0.42175859999999998
+385 327 -0.74391759999999996
+361 328 2.5197029999999998
+364 328 0.64836369999999999
+370 328 1
+372 328 -0.3414664
+373 328 0.3798898
+386 328 -0.74391759999999996
+362 329 0.017727920000000001
+365 329 0.64836369999999999
+370 329 1
+372 329 1.6460520000000001
+373 329 1.3054760000000001
+387 329 -0.74391759999999996
+360 330 0.1749272
+379 330 -1
+361 331 0.81320190000000003
+380 331 -1
+362 332 0.66961899999999996
+381 332 -1
+87 333 6.3180579999999997
+93 333 1.008121
+88 334 2.1016520000000001
+94 334 0.98324999999999996
+89 335 10.216340000000001
+95 335 0.97112200000000004
+90 336 4.7715329999999998
+96 336 1.0168969999999999
+91 337 1.5445530000000001
+97 337 0.96515200000000001
+92 338 7.4032580000000001
+98 338 0.93991979999999997
+99 339 276.76479999999998
+105 339 0.88770669999999996
+100 340 192.19040000000001
+106 340 1.2620629999999999
+101 341 465.29739999999998
+107 341 0.8373005
+102 342 402.63529999999997
+108 342 0.93272339999999998
+103 343 243.95160000000001
+109 343 1.157006
+104 344 694.42570000000001
+110 344 0.90252429999999995
+111 345 2.1471689999999999
+117 345 0.73310410000000004
+112 346 1.830354
+118 346 0.77070689999999997
+113 347 5.4194959999999996
+119 347 0.91067969999999998
+114 348 1.5934600000000001
+120 348 0.44472830000000002
+115 349 1.5193589999999999
+121 349 0.52296010000000004
+116 350 5.9272710000000002
+122 350 0.81417070000000002
+123 351 8.6013230000000007
+129 351 0.58171510000000004
+124 352 6.1974850000000004
+130 352 0.53220719999999999
+125 353 37.67033
+131 353 1.1683300000000001
+126 354 10.955349999999999
+132 354 0.74939929999999999
+127 355 8.2864269999999998
+133 355 0.71973830000000005
+128 356 35.092930000000003
+134 356 1.100849
+135 357 0.4338919
+138 357 2.2797130000000001
+136 358 0.1137572
+139 358 0.60698209999999997
+137 359 0.4035473
+140 359 0.0080049890000000005
+141 360 1.1577040000000001
+144 360 4.0422279999999997
+142 361 0.41932589999999997
+145 361 2.449611
+143 362 0.10246470000000001
+146 362 0.36475180000000001
+151 363 172.5745
+154 363 14.91761
+152 364 161.58449999999999
+155 364 12.0938
+153 365 145.31450000000001
+156 365 5.7400960000000003
+157 366 0.0045018890000000002
+158 366 0.95263589999999998
+159 366 -1
+158 367 0.94488159999999999
+163 367 19.882059999999999
+164 367 15.998699999999999
+165 367 7.7694989999999997
+159 368 1.00814
+163 368 98.828980000000001
+164 368 147.5558
+165 368 130.84370000000001
+160 369 1
+163 369 1.8011980000000001
+161 370 1
+164 370 2.196221
+162 371 1
+165 371 2.0607380000000002
+163 372 19.882059999999999
+166 372 0.9740453
+164 373 15.998699999999999
+167 373 0.93133779999999999
+165 374 7.7694989999999997
+168 374 0.82771399999999995
+169 375 -1
+172 375 -1
+175 375 0.056357909999999997
+176 375 0.056357909999999997
+177 375 0.056357909999999997
+170 376 -1
+173 376 -1
+175 376 0.73959730000000001
+176 376 0.73959730000000001
+177 376 0.73959730000000001
+171 377 -1
+174 377 -1
+175 377 0.2040448
+176 377 0.2040448
+177 377 0.2040448
+172 378 1
+175 378 -1
+173 379 1
+176 379 -1
+174 380 1
+177 380 -1
+175 381 1
+178 381 1
+176 382 1
+179 382 1
+177 383 1
+180 383 1
+102 384 -19.453890000000001
+418 384 1
+424 384 -0.09530421
+103 385 -22.090309999999999
+419 385 1
+424 385 -0.088197620000000004
+104 386 -49.563589999999998
+420 386 1
+424 386 -0.00010690420000000001
+421 387 179.7345
+422 387 -2.5957400000000002
+422 388 1
+423 388 -0.09621652
+102 389 -1
+103 389 -1
+104 389 -1
+423 389 0.09621652
+424 389 -0.0088937280000000001
+126 390 0.93082790000000004
+127 390 0.93082790000000004
+128 390 0.93082790000000004
+425 390 -1.138352
+436 390 0.095341780000000001
+126 391 0.81769789999999998
+426 391 -0.55083519999999997
+436 391 0.04613478
+127 392 0.81769789999999998
+427 392 -0.4489223
+436 392 0.037599149999999998
+128 393 6.8068650000000002
+428 393 -0.0020188419999999999
+436 393 0.0001690866
+429 394 -0.60313589999999995
+430 394 -1.1914260000000001
+431 394 -0.2090101
+432 394 -0.2323664
+126 395 -1.5881989999999999
+430 395 1
+436 395 -0.089606729999999996
+127 396 -1.7894779999999999
+431 396 1
+436 396 -0.082283250000000002
+128 397 -4.012804
+432 397 1
+436 397 -9.9680419999999997e-05
+433 398 1.186874
+435 398 -0.87134319999999998
+434 399 0.99186010000000002
+435 399 -0.73414950000000001
+126 400 -1
+127 400 -1
+128 400 -1
+435 400 0.89782490000000004
+436 400 -0.1024269
+185 401 263.30250000000001
+188 401 16.710229999999999
+186 402 252.3125
+189 402 15.091379999999999
+187 403 236.04249999999999
+190 403 11.440289999999999
+191 404 0.0068429329999999998
+192 404 0.96227439999999997
+193 404 -1
+192 405 0.95486020000000005
+197 405 35.042119999999997
+198 405 28.167190000000002
+199 405 13.66854
+193 406 1.0077050000000001
+197 406 85.846760000000003
+198 406 144.16210000000001
+199 406 130.40539999999999
+194 407 1
+197 407 1.6589050000000001
+195 408 1
+198 408 2.1064970000000001
+196 409 1
+199 409 2.000909
+197 410 35.042119999999997
+200 410 1
+198 411 28.167190000000002
+201 411 0.97782690000000005
+199 412 13.66854
+202 412 0.91623940000000004
+203 413 -1
+206 413 -1
+209 413 0.0034351899999999999
+210 413 0.0034351899999999999
+211 413 0.0034351899999999999
+204 414 -1
+207 414 -1
+209 414 0.043016970000000002
+210 414 0.043016970000000002
+211 414 0.043016970000000002
+205 415 -1
+208 415 -1
+209 415 0.95354779999999995
+210 415 0.95354779999999995
+211 415 0.95354779999999995
+206 416 1
+209 416 -1
+207 417 1
+210 417 -1
+208 418 1
+211 418 -1
+209 419 1
+212 419 1
+210 420 1
+213 420 1
+211 421 1
+214 421 1
+90 422 -0.047613129999999997
+461 422 1
+467 422 -2.3334699999999999e-05
+91 423 -0.057464349999999997
+462 423 1
+467 423 -0.00035266559999999999
+92 424 -0.12956039999999999
+463 424 1
+467 424 -0.017625419999999999
+464 425 270.46249999999998
+465 425 -2.8000669999999999
+465 426 1
+466 426 -1.6856930000000001
+90 427 -1
+91 427 -1
+92 427 -1
+466 427 1.6856930000000001
+467 427 -0.1426674
+114 428 0.12149740000000001
+115 428 0.12149740000000001
+116 428 0.12149740000000001
+468 428 -1.138352
+479 428 0.021230519999999999
+114 429 0.60555749999999997
+469 429 -0.019490179999999999
+479 429 0.00036349629999999998
+115 430 0.3357927
+470 430 -0.13533829999999999
+479 430 0.0025240900000000001
+116 431 0.1067309
+471 431 -0.95354779999999995
+479 431 0.017783879999999998
+472 432 -0.90759219999999996
+473 432 -5.7118219999999997
+474 432 -0.93568410000000002
+475 432 -1.0346550000000001
+114 433 -0.043240929999999997
+473 433 1
+479 433 -2.5956110000000001e-05
+115 434 -0.052174909999999998
+474 434 1
+479 434 -0.00039218899999999998
+116 435 -0.1176314
+475 435 1
+479 435 -0.019600159999999998
+476 436 5.3140780000000003
+478 436 -1.002184
+477 437 0.34483720000000001
+478 437 -0.26478620000000003
+114 438 -1
+115 438 -1
+116 438 -1
+478 438 1.7669710000000001
+479 438 -0.1747406
+438 439 99.149730000000005
+444 439 -1
+447 439 -3.311398e-05
+439 440 172.6396
+445 440 -1
+448 440 -4.1108120000000002e-05
+440 441 356.63979999999998
+446 441 -1
+449 441 -8.4587179999999994e-05
+441 442 200.0008
+444 442 2.5
+447 442 3.311398e-05
+442 443 349.00330000000002
+445 443 2.5
+448 443 4.1108120000000002e-05
+443 444 722.06780000000003
+446 444 2.5
+449 444 8.4587179999999994e-05
+444 445 1
+453 445 -1.4485650000000001e-06
+445 446 1
+453 446 -0.0005113292
+446 447 1
+453 447 -0.95438869999999998
+447 448 1.0050250000000001
+454 448 -0.0034351899999999999
+448 449 1.002874
+454 449 -0.043016970000000002
+449 450 1.001387
+454 450 -0.95354779999999995
+450 451 1
+453 451 -4.9455600000000001e-05
+451 452 1
+453 452 -0.0021775570000000001
+452 453 1
+453 453 -0.042871529999999998
+453 454 1
+455 454 -1
+466 454 1.5
+478 454 0.5
+454 455 1
+456 455 -316220
+459 455 -12132.58
+460 455 -1
+466 455 -20451.810000000001
+477 455 9152.7510000000002
+455 456 9.1463570000000001
+457 456 0.0037734919999999998
+456 457 2248.7060000000001
+457 457 -0.12505330000000001
+457 458 0.067588380000000003
+458 458 65.087119999999999
+466 458 -0.18859039999999999
+458 459 -9152.7510000000002
+460 459 0.75439429999999996
+476 459 -9152.7510000000002
+477 459 -6904.7830000000004
+459 460 1
+466 460 0.18569289999999999
+478 460 -0.5
+460 461 0.00019167939999999999
+466 461 2.6684519999999998
+478 461 0.88948400000000005
+266 462 0.52397099999999996
+269 462 2.5902729999999998
+267 463 0.1209036
+270 463 1
+268 464 0.36607729999999999
+271 464 0.018323329999999999
+288 465 0.53070830000000002
+291 465 2.6120320000000001
+289 466 0.12143809999999999
+292 466 1
+290 467 0.36327480000000001
+293 467 0.019398479999999999
+310 468 0.53114850000000002
+313 468 2.6134469999999999
+311 469 0.1214731
+314 469 1
+312 470 0.36309170000000002
+315 470 0.01947045
+332 471 0.53131620000000002
+335 471 2.6139860000000001
+333 472 0.12148639999999999
+336 472 1
+334 473 0.36302190000000001
+337 473 0.01949793
+354 474 0.53753340000000005
+357 474 2.63388
+355 475 0.12197959999999999
+358 475 1
+356 476 0.36043579999999997
+359 476 0.020538460000000001
+376 477 0.71092829999999996
+379 477 3.1304669999999999
+377 478 0.13573579999999999
+380 478 1
+378 479 0.28830909999999998
+381 479 0.071489880000000006
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/data/west0479.mtx	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1912 @@
+%%MatrixMarket matrix coordinate real general
+479 479 1910
+25 1  1.0000000000000e+00
+31 1 -3.7648130000000e-02
+87 1 -3.4423960000000e-01
+26 2  1.0000000000000e+00
+31 2 -2.4522620000000e-02
+88 2 -3.7370860000000e-01
+27 3  1.0000000000000e+00
+31 3 -3.6613040000000e-02
+89 3 -8.3693790000000e-01
+28 4  1.3000000000000e+02
+29 4 -2.4337670000000e+00
+29 5  1.0000000000000e+00
+30 5 -1.6140910000000e+00
+30 6  1.6140910000000e+00
+31 6 -2.1873210000000e-01
+87 6 -1.0000000000000e+00
+88 6 -1.0000000000000e+00
+89 6 -1.0000000000000e+00
+32 7 -1.1383520000000e+00
+43 7  3.6694280000000e-02
+111 7  9.9316360000000e-02
+112 7  9.9316360000000e-02
+113 7  9.9316360000000e-02
+33 8 -5.0000000000000e-01
+43 8  1.6117290000000e-02
+111 8  8.7245760000000e-02
+34 9 -3.6119180000000e-01
+43 9  1.1642860000000e-02
+112 9  1.0504150000000e-01
+35 10 -3.2188760000000e-01
+43 10  1.0375910000000e-02
+113 10  1.4041660000000e-01
+36 11 -4.3624160000000e-01
+37 11 -7.6804250000000e-01
+38 11 -1.4302790000000e-01
+39 11 -1.5938860000000e-01
+37 12  1.0000000000000e+00
+43 12 -4.8560820000000e-02
+111 12 -2.6286840000000e-01
+38 13  1.0000000000000e+00
+43 13 -3.0925950000000e-02
+112 13 -2.7901280000000e-01
+39 14  1.0000000000000e+00
+43 14 -4.6123590000000e-02
+113 14 -6.2418820000000e-01
+40 15  5.2824360000000e+00
+42 15 -6.1239210000000e-01
+41 16  2.8868220000000e-01
+42 16 -2.1638150000000e-01
+42 17  1.3287740000000e+00
+43 17 -3.6946860000000e-01
+111 17 -1.0000000000000e+00
+112 17 -1.0000000000000e+00
+113 17 -1.0000000000000e+00
+2 18  4.8176470000000e+01
+8 18 -1.0000000000000e+00
+11 18 -3.3474840000000e-05
+3 19  8.3500000000000e+01
+9 19 -1.0000000000000e+00
+12 19 -4.1365390000000e-05
+4 20  1.7194120000000e+02
+10 20 -1.0000000000000e+00
+13 20 -8.4843450000000e-05
+5 21  9.6651380000000e+01
+8 21  2.5000000000000e+00
+11 21  3.3474840000000e-05
+6 22  1.6827060000000e+02
+9 22  2.5000000000000e+00
+12 22  4.1365390000000e-05
+7 23  3.4758720000000e+02
+10 23  2.5000000000000e+00
+13 23  8.4843450000000e-05
+8 24  1.0000000000000e+00
+17 24 -1.1069670000000e-01
+27 24  1.6052320000000e+00
+9 25  1.0000000000000e+00
+17 25 -8.9808520000000e-02
+10 26  1.0000000000000e+00
+17 26 -1.5173690000000e-01
+11 27  1.0104550000000e+00
+18 27 -5.0000000000000e-01
+12 28  1.0059780000000e+00
+18 28 -3.0000000000000e-01
+13 29  1.0028850000000e+00
+18 29 -2.0000000000000e-01
+14 30  1.0000000000000e+00
+17 30 -1.8118550000000e-01
+15 31  1.0000000000000e+00
+17 31 -2.4002390000000e-01
+16 32  1.0000000000000e+00
+17 32 -2.2654840000000e-01
+17 33  1.0000000000000e+00
+19 33 -1.0000000000000e+00
+30 33  1.5000000000000e+00
+42 33  5.0000000000000e-01
+18 34  1.0000000000000e+00
+20 34 -3.1622000000000e+05
+23 34 -1.2323690000000e+04
+24 34 -1.0000000000000e+00
+30 34 -3.5226800000000e+04
+41 34  1.8449020000000e+04
+19 35  5.2983390000000e+00
+21 35  2.4526870000000e-03
+20 36  1.0808590000000e+03
+21 36 -2.0502150000000e-01
+21 37  1.4419200000000e-01
+22 37  6.3059860000000e+01
+30 37 -1.1592990000000e-01
+22 38 -1.8449020000000e+04
+24 38  8.4533390000000e-01
+40 38 -1.8449020000000e+04
+41 38 -1.5595580000000e+04
+23 39  1.0000000000000e+00
+30 39  2.0204930000000e-01
+42 39 -8.8547100000000e-01
+24 40  1.0002340000000e-04
+30 40  2.4483390000000e+00
+42 40  8.1611300000000e-01
+68 41  1.0000000000000e+00
+74 41 -2.2786690000000e-04
+99 41 -2.6243950000000e-01
+69 42  1.0000000000000e+00
+74 42 -4.1887630000000e-04
+100 42 -3.2161960000000e-01
+70 43  1.0000000000000e+00
+74 43 -1.5769330000000e-03
+101 43 -7.2647610000000e-01
+71 44  3.0000000000000e+02
+72 44 -2.8518910000000e+00
+72 45  1.0000000000000e+00
+73 45 -2.8701590000000e-01
+73 46  2.8701590000000e-01
+74 46 -4.3413220000000e-03
+99 46 -1.0000000000000e+00
+100 46 -1.0000000000000e+00
+101 46 -1.0000000000000e+00
+75 47 -1.1383520000000e+00
+86 47  4.2002860000000e-02
+123 47  9.4148060000000e-01
+124 47  9.4148060000000e-01
+125 47  9.4148060000000e-01
+76 48 -3.2188760000000e-01
+86 48  1.1877000000000e-02
+123 48  1.3310950000000e+00
+77 49 -3.6119180000000e-01
+86 49  1.3327240000000e-02
+124 49  9.9575290000000e-01
+78 50 -5.0000000000000e-01
+86 50  1.8448980000000e-02
+125 50  8.2705600000000e-01
+79 51 -1.0000000000000e+00
+80 51 -1.9240000000000e+01
+81 51 -3.8030000000000e+00
+82 51 -9.4810000000000e+00
+80 52  1.0000000000000e+00
+86 52 -8.8757840000000e-04
+123 52 -9.9473920000000e-02
+81 53  1.0000000000000e+00
+86 53 -1.3313680000000e-03
+124 53 -9.9473920000000e-02
+82 54  1.0000000000000e+00
+86 54 -2.2189460000000e-03
+125 54 -9.9473920000000e-02
+83 55  1.1776130000000e+00
+85 55 -3.1089630000000e+00
+84 56  9.9194250000000e-01
+85 56 -2.6400560000000e+00
+85 57  3.1921120000000e+00
+86 57 -4.4613630000000e-02
+123 57 -1.0000000000000e+00
+124 57 -1.0000000000000e+00
+125 57 -1.0000000000000e+00
+45 58  1.0986880000000e+02
+51 58 -1.0000000000000e+00
+54 58 -3.3081100000000e-05
+46 59  1.9138460000000e+02
+52 59 -1.0000000000000e+00
+55 59 -4.1084670000000e-05
+47 60  3.9547960000000e+02
+53 60 -1.0000000000000e+00
+56 60 -8.4563830000000e-05
+48 61  2.2173390000000e+02
+51 61  2.5000000000000e+00
+54 61  3.3081100000000e-05
+49 62  3.8700920000000e+02
+52 62  2.5000000000000e+00
+55 62  4.1084670000000e-05
+50 63  8.0081650000000e+02
+53 63  2.5000000000000e+00
+56 63  8.4563830000000e-05
+51 64  1.0000000000000e+00
+60 64 -9.1702290000000e-03
+52 65  1.0000000000000e+00
+60 65 -4.6441100000000e-02
+53 66  1.0000000000000e+00
+60 66 -4.8999190000000e-01
+54 67  1.0045300000000e+00
+61 67 -2.0000000000000e-01
+55 68  1.0025910000000e+00
+61 68 -3.0000000000000e-01
+56 69  1.0012500000000e+00
+61 69 -5.0000000000000e-01
+57 70  1.0000000000000e+00
+60 70 -3.7500530000000e-02
+58 71  1.0000000000000e+00
+60 71 -1.2414300000000e-01
+59 72  1.0000000000000e+00
+60 72 -2.9275320000000e-01
+60 73  1.0000000000000e+00
+62 73 -1.0000000000000e+00
+73 73  1.8537330000000e-01
+85 73  6.1791090000000e-02
+61 74  1.0000000000000e+00
+63 74 -3.1622000000000e+05
+66 74 -1.6364190000000e+04
+67 74 -1.0000000000000e+00
+73 74 -4.6967820000000e+03
+84 74  1.3185400000000e+02
+62 75  2.2129130000000e+01
+64 75  9.5375260000000e-01
+63 76  2.4942900000000e+03
+64 76 -1.0215870000000e+00
+64 77  8.8782810000000e-01
+65 77  1.0400420000000e+00
+73 77 -2.6400560000000e+00
+65 78 -1.3185400000000e+02
+67 78  8.0574700000000e-03
+83 78 -1.3185400000000e+02
+84 78 -1.0624090000000e+00
+66 79  1.0000000000000e+00
+73 79  1.0164260000000e-01
+85 79 -6.1791090000000e-02
+67 80  7.6452570000000e-03
+73 80  2.3098950000000e+01
+85 80  7.6996490000000e+00
+31 81  1.0000000000000e+00
+244 81  1.0000000000000e+00
+43 82  1.0000000000000e+00
+1 83  1.0000000000000e+00
+17 83 -3.8502310000000e+00
+18 83 -8.4599350000000e-05
+31 83  2.0159100000000e+00
+35 83  1.0000000000000e+00
+43 83  1.5961710000000e+00
+243 83 -7.8975120000000e-01
+74 84  1.0000000000000e+00
+388 84  8.8175620000000e-01
+86 85  1.0000000000000e+00
+44 86  1.0000000000000e+00
+60 86 -2.7937600000000e+00
+61 86 -8.4458230000000e-05
+74 86  2.0156650000000e+00
+78 86  1.0000000000000e+00
+86 86  1.5939940000000e+00
+384 86  0.0000000000000e+00
+387 86 -9.6191500000000e-01
+385 87  2.4246690000000e-03
+386 87  3.0362780000000e-02
+387 87  6.7304510000000e-01
+388 87  1.4593600000000e+00
+96 88  1.6896610000000e-02
+97 88  3.4848030000000e-02
+98 88 -6.0080180000000e-02
+120 88 -5.5527170000000e-01
+121 88 -4.7703980000000e-01
+122 88 -1.8582930000000e-01
+141 88 -1.0000000000000e+00
+142 88 -1.0000000000000e+00
+143 88 -1.0000000000000e+00
+185 88 -5.5188570000000e+01
+186 88 -9.5676860000000e+01
+187 88 -2.1583770000000e+02
+389 88  1.0000000000000e+00
+438 88  1.0000000000000e+00
+439 88  1.0000000000000e+00
+440 88  1.0000000000000e+00
+441 88  1.0000000000000e+00
+442 88  1.0000000000000e+00
+443 88  1.0000000000000e+00
+450 88 -1.8907560000000e-03
+451 88 -1.5311400000000e-03
+452 88 -1.0137260000000e-03
+455 88  2.5000000000000e+00
+456 88  2.6063700000000e+01
+458 88  1.0000000000000e+00
+459 88 -1.5000000000000e+00
+461 88 -9.6031810000000e+00
+462 88 -9.4541850000000e+00
+463 88 -9.4376810000000e+00
+464 88 -4.8295720000000e+01
+472 88  9.0759220000000e-01
+473 88 -4.3759670000000e+00
+474 88 -8.9979920000000e+00
+475 88 -8.8819580000000e+00
+476 88  1.0000000000000e+00
+182 89  1.0000000000000e+00
+183 89  1.0000000000000e+00
+184 89  1.0000000000000e+00
+391 89  1.0000000000000e+00
+455 89 -1.0000000000000e+00
+456 89 -2.6063700000000e+01
+458 89 -1.0000000000000e+00
+468 89  1.0000000000000e+00
+388 90 -1.4593600000000e+00
+467 90  1.0000000000000e+00
+479 91  1.0000000000000e+00
+203 92 -1.0000000000000e+00
+204 92 -1.0000000000000e+00
+205 92 -1.0000000000000e+00
+209 92  1.0000000000000e+00
+210 92  1.0000000000000e+00
+211 92  1.0000000000000e+00
+382 92  5.6953100000000e+01
+385 92  7.0583250000000e-01
+437 92  1.0000000000000e+00
+453 92 -6.4913720000000e-01
+454 92 -3.2948410000000e-05
+467 92  5.3807480000000e-01
+469 92  1.0000000000000e+00
+479 92  8.2471120000000e-02
+203 93 -1.0000000000000e+00
+204 93 -1.0000000000000e+00
+205 93 -1.0000000000000e+00
+209 93  1.0000000000000e+00
+210 93  1.0000000000000e+00
+211 93  1.0000000000000e+00
+383 93  1.1583840000000e+01
+386 93  7.0583250000000e-01
+437 93  1.0000000000000e+00
+453 93 -1.0215420000000e+00
+454 93 -4.0990330000000e-05
+467 93 -3.6302480000000e-01
+470 93  1.0000000000000e+00
+479 93  6.9522610000000e-02
+203 94 -1.0000000000000e+00
+204 94 -1.0000000000000e+00
+205 94 -1.0000000000000e+00
+209 94  1.0000000000000e+00
+210 94  1.0000000000000e+00
+211 94  1.0000000000000e+00
+384 94  3.2096310000000e-01
+387 94  7.0583250000000e-01
+437 94  1.0000000000000e+00
+453 94 -2.0490070000000e+00
+454 94 -8.4470030000000e-05
+467 94  9.1353620000000e-01
+471 94  1.0000000000000e+00
+479 94  8.3976380000000e-01
+241 95  5.5083520000000e-01
+242 95  4.4892230000000e-01
+243 95  2.4252030000000e-04
+244 95  4.0528330000000e-01
+108 96 -6.7276620000000e-02
+109 96 -1.5700610000000e-01
+110 96 -9.7475700000000e-02
+132 96 -2.5060070000000e-01
+133 96 -2.8026170000000e-01
+134 96  1.0084910000000e-01
+245 96 -1.0000000000000e+00
+395 96  1.0000000000000e+00
+396 96  1.0000000000000e+00
+397 96  1.0000000000000e+00
+398 96  1.0000000000000e+00
+399 96  1.0000000000000e+00
+400 96  1.0000000000000e+00
+407 96 -2.8636020000000e-03
+408 96 -2.3162590000000e-03
+409 96 -1.5308900000000e-03
+412 96  2.5000000000000e+00
+413 96  1.1587800000000e+01
+415 96  1.0000000000000e+00
+416 96 -1.1012240000000e+00
+418 96 -1.3644320000000e+00
+419 96 -1.2188210000000e+00
+420 96 -1.2108590000000e+00
+421 96 -3.4621050000000e+01
+429 96  6.0313590000000e-01
+430 96 -5.9963840000000e-01
+431 96 -1.4033920000000e+00
+432 96 -1.3703860000000e+00
+433 96  1.0000000000000e+00
+246 97  1.0000000000000e+00
+412 97 -1.0000000000000e+00
+413 97 -1.1587800000000e+01
+415 97 -1.0000000000000e+00
+425 97  1.0000000000000e+00
+244 98 -4.0528330000000e-01
+424 98  1.0000000000000e+00
+436 99  1.0000000000000e+00
+160 100 -8.5938400000000e-01
+161 100 -7.7333900000000e-01
+162 100 -7.9517400000000e-01
+238 100 -1.0000000000000e+00
+241 100  1.0000000000000e+00
+394 100  1.0000000000000e+00
+410 100 -1.6236590000000e+00
+411 100 -3.3032780000000e-05
+424 100  3.5720350000000e+00
+426 100  1.0000000000000e+00
+436 100  9.2435320000000e-01
+160 101 -1.1718210000000e+00
+161 101 -1.2773520000000e+00
+162 101 -1.2505080000000e+00
+239 101 -1.0000000000000e+00
+242 101  1.0000000000000e+00
+394 101  1.0000000000000e+00
+410 101 -2.4602890000000e+00
+411 101 -4.1050810000000e-05
+424 101 -2.1785330000000e+00
+427 101  1.0000000000000e+00
+436 101  6.5098420000000e-01
+160 102 -2.3280470000000e+00
+161 102 -2.4161550000000e+00
+162 102 -2.5121660000000e+00
+240 102 -1.0000000000000e+00
+243 102  1.0000000000000e+00
+394 102  1.0000000000000e+00
+410 102 -4.7536200000000e+00
+411 102 -8.4530500000000e-05
+424 102  6.1671400000000e+00
+428 102  1.0000000000000e+00
+436 102  3.3966910000000e+00
+241 103  4.3736570000000e-02
+242 103  5.7396460000000e-01
+243 103  1.5834900000000e-01
+244 103  1.8781250000000e-01
+253 103 -4.4344130000000e-02
+254 103 -5.8193780000000e-01
+255 103 -1.6054870000000e-01
+256 103 -1.0000000000000e+00
+135 104 -1.0000000000000e+00
+136 104 -1.0000000000000e+00
+137 104 -1.0000000000000e+00
+151 104 -6.2680900000000e+01
+152 104 -1.2389000000000e+02
+153 104 -4.6435550000000e+02
+245 104  1.0000000000000e+00
+248 104 -5.1646550000000e-02
+249 104 -3.2417620000000e-01
+148 105  1.0000000000000e+00
+149 105  1.0000000000000e+00
+150 105  1.0000000000000e+00
+247 105  1.0000000000000e+00
+244 106 -1.8781250000000e-01
+248 106  1.0000000000000e+00
+256 106  1.0000000000000e+00
+249 107  1.0000000000000e+00
+147 108  1.0000000000000e+00
+169 108 -1.0000000000000e+00
+170 108 -1.0000000000000e+00
+171 108 -1.0000000000000e+00
+175 108  1.0000000000000e+00
+176 108  1.0000000000000e+00
+177 108  1.0000000000000e+00
+238 108  9.7738750000000e+00
+241 108  7.7605020000000e-01
+248 108  7.2528310000000e+00
+249 108  7.8041000000000e-01
+253 108 -7.8683060000000e-01
+147 109  1.0000000000000e+00
+169 109 -1.0000000000000e+00
+170 109 -1.0000000000000e+00
+171 109 -1.0000000000000e+00
+175 109  1.0000000000000e+00
+176 109  1.0000000000000e+00
+177 109  1.0000000000000e+00
+239 109  6.0698210000000e-01
+242 109  7.7605020000000e-01
+248 109 -2.3895080000000e+00
+249 109  6.8493980000000e-01
+254 109 -7.8683060000000e-01
+147 110  1.0000000000000e+00
+169 110 -1.0000000000000e+00
+170 110 -1.0000000000000e+00
+171 110 -1.0000000000000e+00
+175 110  1.0000000000000e+00
+176 110  1.0000000000000e+00
+177 110  1.0000000000000e+00
+240 110  1.1885640000000e-03
+243 110  7.7605020000000e-01
+248 110  1.1558830000000e+01
+249 110  2.2026440000000e+00
+255 110 -7.8683060000000e-01
+363 111 -1.7051480000000e-01
+364 111 -4.3429630000000e-01
+365 111 -2.6674210000000e-01
+366 111 -2.6093020000000e+00
+385 111  1.9564470000000e-01
+386 111  4.9830160000000e-01
+387 111  3.0605370000000e-01
+388 111  4.2239600000000e-01
+215 112  1.0000000000000e+00
+216 112  1.0000000000000e+00
+217 112  1.0000000000000e+00
+218 112  1.0000000000000e+00
+219 112  1.0000000000000e+00
+220 112  1.0000000000000e+00
+227 112 -1.8907560000000e-03
+228 112 -1.5311400000000e-03
+229 112 -1.0137260000000e-03
+232 112  2.5000000000000e+00
+233 112  1.6672410000000e+01
+235 112  1.0000000000000e+00
+236 112 -1.5000000000000e+00
+389 112 -1.0000000000000e+00
+392 112 -4.6212130000000e-01
+393 112 -1.2349620000000e-01
+232 113 -1.0000000000000e+00
+233 113 -1.6672410000000e+01
+235 113 -1.0000000000000e+00
+368 113 -1.0000000000000e+00
+369 113 -1.0000000000000e+00
+390 113  1.0000000000000e+00
+366 114  2.6093020000000e+00
+388 114 -4.2239600000000e-01
+392 114  1.0000000000000e+00
+393 115  1.0000000000000e+00
+181 116  1.0000000000000e+00
+194 116 -5.8697620000000e-01
+195 116 -5.0651550000000e-01
+196 116 -5.1399180000000e-01
+230 116 -1.0366850000000e+00
+231 116 -3.2948410000000e-05
+360 116  0.0000000000000e+00
+363 116 -8.7155310000000e-01
+382 116 -1.0000000000000e+00
+385 116  1.0000000000000e+00
+392 116  2.6399800000000e+00
+393 116  5.5742070000000e-01
+181 117  1.0000000000000e+00
+194 117 -8.0016370000000e-01
+195 117 -8.3640900000000e-01
+196 117 -8.0810260000000e-01
+230 117 -1.6376950000000e+00
+231 117 -4.0990330000000e-05
+361 117  0.0000000000000e+00
+364 117 -8.7155310000000e-01
+383 117 -1.0000000000000e+00
+386 117  1.0000000000000e+00
+392 117 -1.7736780000000e+00
+393 117  4.0754220000000e-01
+181 118  1.0000000000000e+00
+194 118 -1.5893890000000e+00
+195 118 -1.5818110000000e+00
+196 118 -1.6231180000000e+00
+230 118 -3.2056860000000e+00
+231 118 -8.4470030000000e-05
+362 118  0.0000000000000e+00
+365 118 -8.7155310000000e-01
+384 118 -1.0000000000000e+00
+387 118  1.0000000000000e+00
+392 118  4.4676090000000e+00
+393 118  2.2475290000000e+00
+93 119 -1.0000000000000e+00
+96 119 -1.0000000000000e+00
+248 119 -4.0421560000000e-01
+262 119 -1.8187770000000e-01
+284 119 -1.5634550000000e-01
+306 119 -1.5456990000000e-01
+328 119 -1.5217780000000e-01
+350 119 -9.1905800000000e-02
+372 119 -7.8705370000000e-03
+94 120 -1.0000000000000e+00
+97 120 -1.0000000000000e+00
+248 120 -1.8091710000000e+00
+262 120 -3.1896550000000e+00
+284 120 -3.3490190000000e+00
+306 120 -3.3586440000000e+00
+328 120 -3.3085850000000e+00
+350 120 -1.9678700000000e+00
+372 120 -1.1333560000000e-01
+95 121 -1.0000000000000e+00
+98 121 -1.0000000000000e+00
+248 121 -2.4566020000000e+00
+262 121 -4.1011280000000e+00
+284 121 -4.2908920000000e+00
+306 121 -4.3026030000000e+00
+328 121 -4.2541470000000e+00
+350 121 -2.9523890000000e+00
+372 121 -1.1573650000000e+00
+93 122 -8.1214960000000e-03
+96 122 -1.6896610000000e-02
+248 122 -4.5387600000000e-03
+262 122 -2.1705200000000e-03
+284 122 -1.8740690000000e-03
+306 122 -1.8533180000000e-03
+328 122 -1.8248370000000e-03
+350 122 -1.1065610000000e-03
+372 122 -1.0544940000000e-04
+94 123 -1.6749990000000e-02
+97 123 -3.4848030000000e-02
+248 123 -4.1896920000000e-02
+262 123 -7.8506680000000e-02
+284 123 -8.2793510000000e-02
+306 123 -8.3055320000000e-02
+328 123 -8.1826380000000e-02
+350 123 -4.8866050000000e-02
+372 123 -3.1317320000000e-03
+95 124 -2.8878030000000e-02
+98 124 -6.0080180000000e-02
+248 124 -9.8082240000000e-02
+262 124 -1.7402810000000e-01
+284 124 -1.8288550000000e-01
+306 124 -1.8343740000000e-01
+328 124 -1.8139140000000e-01
+350 124 -1.2639720000000e-01
+372 124 -5.5136770000000e-02
+105 125 -1.0000000000000e+00
+108 125 -1.0000000000000e+00
+264 125 -7.6362320000000e-01
+286 125 -5.4132110000000e-01
+308 125 -5.2907530000000e-01
+330 125 -5.2832600000000e-01
+352 125 -5.2965340000000e-01
+374 125 -5.9901060000000e-01
+392 125 -5.7467680000000e-01
+106 126 -1.0000000000000e+00
+109 126 -1.0000000000000e+00
+264 126 -1.4679790000000e+00
+286 126 -1.2898060000000e+00
+308 126 -1.2799920000000e+00
+330 126 -1.2793850000000e+00
+352 126 -1.2801740000000e+00
+374 126 -1.3601430000000e+00
+392 126 -7.1491900000000e-01
+107 127 -1.0000000000000e+00
+110 127 -1.0000000000000e+00
+264 127 -4.3708570000000e-03
+286 127 -3.9541010000000e-03
+308 127 -3.9318030000000e-03
+330 127 -3.9476680000000e-03
+352 127 -4.7490230000000e-03
+374 127 -7.2455390000000e-02
+392 127 -1.6023640000000e+00
+105 128 -1.1229330000000e-01
+108 128 -6.7276620000000e-02
+264 128 -5.4601370000000e-02
+286 128 -3.8877220000000e-02
+308 128 -3.8008660000000e-02
+330 128 -3.7958990000000e-02
+352 128 -3.8208860000000e-02
+374 128 -4.8085490000000e-02
+392 128 -5.8178620000000e-02
+106 129 -2.6206330000000e-01
+109 129 -1.5700610000000e-01
+264 129 -2.4496080000000e-01
+286 129 -2.1618060000000e-01
+308 129 -2.1459740000000e-01
+330 129 -2.1451910000000e-01
+352 129 -2.1552300000000e-01
+374 129 -2.5481000000000e-01
+392 129 -1.6890750000000e-01
+107 130 -1.6269950000000e-01
+110 130 -9.7475700000000e-02
+264 130 -4.5281760000000e-04
+286 130 -4.1145290000000e-04
+308 130 -4.0925030000000e-04
+330 130 -4.1094670000000e-04
+352 130 -4.9637370000000e-04
+374 130 -8.4271850000000e-03
+392 130 -2.3503520000000e-01
+117 131 -1.0000000000000e+00
+120 131 -1.0000000000000e+00
+249 131 -6.9702840000000e-02
+263 131 -1.9243320000000e-02
+285 131 -1.5837930000000e-02
+307 131 -1.5617910000000e-02
+329 131 -1.5583210000000e-02
+351 131 -1.4718560000000e-02
+373 131 -5.7599520000000e-03
+118 132 -1.0000000000000e+00
+121 132 -1.0000000000000e+00
+249 132 -7.4171360000000e-01
+263 132 -8.0234940000000e-01
+285 132 -8.0658470000000e-01
+307 132 -8.0682860000000e-01
+329 132 -8.0550310000000e-01
+351 132 -7.4926980000000e-01
+373 132 -1.9719700000000e-01
+119 133 -1.0000000000000e+00
+122 133 -1.0000000000000e+00
+249 133 -5.1275980000000e-01
+263 133 -5.2522530000000e-01
+285 133 -5.2614130000000e-01
+307 133 -5.2622450000000e-01
+329 133 -5.2730270000000e-01
+351 133 -5.7231860000000e-01
+373 133 -1.0252420000000e+00
+117 134 -4.6575930000000e-01
+120 134 -9.6900310000000e-01
+249 134 -4.4884880000000e-02
+263 134 -1.3170120000000e-02
+285 134 -1.0887390000000e-02
+307 134 -1.0739240000000e-02
+329 134 -1.0716550000000e-02
+351 134 -1.0163030000000e-02
+373 134 -4.4257190000000e-03
+118 135 -5.7440230000000e-01
+121 135 -1.1950330000000e+00
+249 135 -5.8903420000000e-01
+263 135 -6.7721740000000e-01
+285 135 -6.8380180000000e-01
+307 135 -6.8420530000000e-01
+329 135 -6.8315610000000e-01
+351 135 -6.3804400000000e-01
+373 135 -1.8686160000000e-01
+119 136 -2.2922850000000e-01
+122 136 -4.7690550000000e-01
+249 136 -1.6250650000000e-01
+263 136 -1.7691420000000e-01
+285 136 -1.7800620000000e-01
+307 136 -1.7808560000000e-01
+329 136 -1.7847000000000e-01
+351 136 -1.9449250000000e-01
+373 136 -3.8770260000000e-01
+129 137 -1.0000000000000e+00
+132 137 -1.0000000000000e+00
+265 137 -3.4272790000000e-01
+287 137 -2.9113760000000e-01
+309 137 -2.8769370000000e-01
+331 137 -2.8748890000000e-01
+353 137 -2.8823180000000e-01
+375 137 -3.0269870000000e-01
+393 137 -1.7507890000000e-01
+130 138 -1.0000000000000e+00
+133 138 -1.0000000000000e+00
+265 138 -1.0623340000000e+00
+287 138 -1.1185060000000e+00
+309 138 -1.1222530000000e+00
+331 138 -1.1225120000000e+00
+353 138 -1.1232850000000e+00
+375 138 -1.1082340000000e+00
+393 138 -3.5118640000000e-01
+131 139 -1.0000000000000e+00
+134 139 -1.0000000000000e+00
+265 139 -2.3999820000000e-03
+287 139 -2.6017300000000e-03
+309 139 -2.6156270000000e-03
+331 139 -2.6280330000000e-03
+353 139 -3.1617350000000e-03
+375 139 -4.4793810000000e-02
+393 139 -5.9723090000000e-01
+129 140 -2.0182530000000e+00
+132 140 -1.2091660000000e+00
+265 140 -4.4044890000000e-01
+287 140 -3.7580290000000e-01
+309 140 -3.7146430000000e-01
+331 140 -3.7124050000000e-01
+353 140 -3.7371090000000e-01
+375 140 -4.3672880000000e-01
+393 140 -3.1856280000000e-01
+130 141 -2.5626880000000e+00
+133 141 -1.5353450000000e+00
+265 141 -1.7335130000000e+00
+287 141 -1.8332450000000e+00
+309 141 -1.8399150000000e+00
+331 141 -1.8405410000000e+00
+353 141 -1.8492860000000e+00
+375 141 -2.0302660000000e+00
+393 141 -8.1137050000000e-01
+131 142 -9.2554290000000e-01
+134 142 -5.5450670000000e-01
+265 142 -1.4144090000000e-03
+287 142 -1.5400860000000e-03
+309 142 -1.5487580000000e-03
+331 142 -1.5562740000000e-03
+353 142 -1.8799250000000e-03
+375 142 -2.9637400000000e-02
+393 142 -4.9833870000000e-01
+135 143 -1.4338920000000e+00
+141 143 -2.1577040000000e+00
+266 143 -1.5239710000000e+00
+288 143 -1.5307080000000e+00
+310 143 -1.5311480000000e+00
+332 143 -1.5313160000000e+00
+354 143 -1.5375330000000e+00
+376 143 -1.7109280000000e+00
+136 144 -9.4320600000000e-01
+142 144 -1.4193260000000e+00
+267 144 -1.0024600000000e+00
+289 144 -1.0068910000000e+00
+311 144 -1.0071810000000e+00
+333 144 -1.0072910000000e+00
+355 144 -1.0113810000000e+00
+377 144 -1.1254390000000e+00
+137 145 -5.9645270000000e-01
+143 145 -8.9753530000000e-01
+268 145 -6.3392270000000e-01
+290 145 -6.3672520000000e-01
+312 145 -6.3690830000000e-01
+334 145 -6.3697810000000e-01
+356 145 -6.3956420000000e-01
+378 145 -7.1169090000000e-01
+135 146 -1.0000000000000e+00
+141 146 -1.0000000000000e+00
+266 146 -1.0000000000000e+00
+288 146 -1.0000000000000e+00
+310 146 -1.0000000000000e+00
+332 146 -1.0000000000000e+00
+354 146 -1.0000000000000e+00
+376 146 -1.0000000000000e+00
+136 147 -1.0000000000000e+00
+142 147 -1.0000000000000e+00
+267 147 -1.0000000000000e+00
+289 147 -1.0000000000000e+00
+311 147 -1.0000000000000e+00
+333 147 -1.0000000000000e+00
+355 147 -1.0000000000000e+00
+377 147 -1.0000000000000e+00
+137 148 -1.0000000000000e+00
+143 148 -1.0000000000000e+00
+268 148 -1.0000000000000e+00
+290 148 -1.0000000000000e+00
+312 148 -1.0000000000000e+00
+334 148 -1.0000000000000e+00
+356 148 -1.0000000000000e+00
+378 148 -1.0000000000000e+00
+138 149 -1.0000000000000e+00
+148 149  1.0000000000000e+00
+238 149  5.5083520000000e-01
+139 150 -1.0000000000000e+00
+149 150  1.6474950000000e+00
+239 150  7.3959730000000e-01
+140 151 -1.0000000000000e+00
+150 151  8.4135160000000e+02
+240 151  2.0404480000000e-01
+144 152 -1.0000000000000e+00
+182 152  1.0000000000000e+00
+382 152  1.9564470000000e-01
+145 153 -1.0000000000000e+00
+183 153  1.0000000000000e+00
+383 153  4.9830160000000e-01
+146 154 -1.0000000000000e+00
+184 154  3.1156220000000e+00
+384 154  9.5354780000000e-01
+395 155  6.6224920000000e+01
+401 155 -1.0000000000000e+00
+404 155 -3.3282570000000e-05
+396 156  1.1506230000000e+02
+402 156 -1.0000000000000e+00
+405 156 -4.1228310000000e-05
+397 157  2.3733870000000e+02
+403 157 -1.0000000000000e+00
+406 157 -8.4706900000000e-05
+398 158  1.3324500000000e+02
+401 158  2.5000000000000e+00
+404 158  3.3282570000000e-05
+399 159  2.3226390000000e+02
+402 159  2.5000000000000e+00
+405 159  4.1228310000000e-05
+400 160  4.8018210000000e+02
+403 160  2.5000000000000e+00
+406 160  8.4706900000000e-05
+160 161 -4.7337900000000e-01
+401 161  1.0000000000000e+00
+410 161 -2.1168760000000e-01
+161 162 -5.7343170000000e-01
+402 162  1.0000000000000e+00
+410 162 -3.1667150000000e-01
+162 163 -6.0925110000000e-04
+403 163  1.0000000000000e+00
+410 163 -3.5118740000000e-07
+163 164 -4.5750040000000e+03
+404 164  1.0075620000000e+00
+411 164 -5.5083520000000e-01
+164 165 -3.6814160000000e+03
+405 165  1.0043240000000e+00
+411 165 -4.4892230000000e-01
+165 166 -1.7878180000000e+03
+406 166  1.0020870000000e+00
+411 166 -2.4252030000000e-04
+160 167 -5.2605640000000e-01
+161 167 -4.2598230000000e-01
+407 167  1.0000000000000e+00
+410 167 -4.7048840000000e-01
+160 168 -5.6459870000000e-04
+162 168 -4.3800980000000e-01
+408 168  1.0000000000000e+00
+410 168 -5.0495930000000e-04
+161 169 -5.8596670000000e-04
+162 169 -5.6138090000000e-01
+409 169  1.0000000000000e+00
+410 169 -6.4718760000000e-04
+163 170 -1.0000000000000e+00
+164 170 -1.0000000000000e+00
+165 170 -1.0000000000000e+00
+410 170  1.0000000000000e+00
+412 170 -1.0000000000000e+00
+423 170  6.1444210000000e-02
+435 170  2.0481400000000e-02
+157 171 -1.0000000000000e+00
+163 171  4.1240600000000e+03
+164 171  4.1240600000000e+03
+165 171  4.1240600000000e+03
+411 171  1.0000000000000e+00
+413 171 -3.1622000000000e+05
+416 171 -2.0034240000000e+04
+417 171 -1.0000000000000e+00
+423 171 -2.6256570000000e+03
+434 171  2.2212900000000e+02
+412 172  1.8737270000000e+01
+414 172  9.4488160000000e-01
+413 173  1.4943670000000e+03
+414 173 -1.0207800000000e+00
+158 174 -9.9186010000000e-01
+163 174 -1.7922340000000e+01
+164 174 -1.7922340000000e+01
+165 174 -1.7922340000000e+01
+414 174  8.6282900000000e-01
+415 174  1.0497190000000e+00
+423 174 -7.3414950000000e-01
+157 175  8.1398600000000e-03
+415 175 -2.2212900000000e+02
+417 175  8.1398600000000e-03
+433 175 -2.2212900000000e+02
+434 175 -1.8080990000000e+00
+163 176 -1.0913280000000e+00
+164 176 -1.6293970000000e+00
+165 176 -1.4448530000000e+00
+416 176  1.0000000000000e+00
+423 176  4.7364060000000e-02
+435 176 -2.7898140000000e-02
+417 177  4.5385340000000e-03
+423 177  7.5792400000000e+00
+435 177  2.5264130000000e+00
+148 178 -1.0000000000000e+00
+178 178 -1.0000000000000e+00
+149 179 -1.0000000000000e+00
+179 179 -1.0000000000000e+00
+150 180 -1.0000000000000e+00
+180 180 -1.0000000000000e+00
+148 181  1.0266460000000e+00
+166 181 -1.0000000000000e+00
+149 182  1.0737240000000e+00
+167 182 -1.0000000000000e+00
+150 183  1.2081470000000e+00
+168 183 -1.0000000000000e+00
+148 184 -1.0000000000000e+00
+154 184 -1.0000000000000e+00
+149 185 -1.0000000000000e+00
+155 185 -1.0000000000000e+00
+150 186 -1.0000000000000e+00
+156 186 -1.0000000000000e+00
+215 187  9.9149730000000e+01
+221 187 -1.0000000000000e+00
+224 187 -3.3113980000000e-05
+216 188  1.7263960000000e+02
+222 188 -1.0000000000000e+00
+225 188 -4.1108120000000e-05
+217 189  3.5663980000000e+02
+223 189 -1.0000000000000e+00
+226 189 -8.4587180000000e-05
+218 190  2.0000080000000e+02
+221 190  2.5000000000000e+00
+224 190  3.3113980000000e-05
+219 191  3.4900330000000e+02
+222 191  2.5000000000000e+00
+225 191  4.1108120000000e-05
+220 192  7.2206780000000e+02
+223 192  2.5000000000000e+00
+226 192  8.4587180000000e-05
+194 193 -1.1483880000000e-01
+221 193  1.0000000000000e+00
+230 193 -1.1645920000000e-02
+195 194 -4.1678390000000e-01
+222 194  1.0000000000000e+00
+230 194 -1.7006160000000e-01
+196 195 -4.9676140000000e-01
+223 195  1.0000000000000e+00
+230 195 -2.4368930000000e-01
+197 196 -5.2768620000000e+03
+224 196  1.0050250000000e+00
+231 196 -1.9564470000000e-01
+198 197 -4.2415910000000e+03
+225 197  1.0028740000000e+00
+231 197 -4.9830160000000e-01
+199 198 -2.0582940000000e+03
+226 198  1.0013870000000e+00
+231 198 -3.0605370000000e-01
+194 199 -3.9872280000000e-01
+195 199 -9.9097090000000e-02
+227 199  1.0000000000000e+00
+230 199 -8.0869760000000e-02
+194 200 -4.8643840000000e-01
+196 200 -1.0055980000000e-01
+228 200  1.0000000000000e+00
+230 200 -9.8660410000000e-02
+195 201 -4.8411900000000e-01
+196 201 -4.0267880000000e-01
+229 201  1.0000000000000e+00
+230 201 -3.9507300000000e-01
+197 202 -1.0000000000000e+00
+198 202 -1.0000000000000e+00
+199 202 -1.0000000000000e+00
+230 202  1.0000000000000e+00
+232 202 -1.0000000000000e+00
+191 203 -1.0000000000000e+00
+197 203  3.2976230000000e+03
+198 203  3.2976230000000e+03
+199 203  3.2976230000000e+03
+231 203  1.0000000000000e+00
+233 203 -3.1622000000000e+05
+236 203 -1.8966660000000e+04
+237 203 -1.0000000000000e+00
+232 204  2.2669870000000e+01
+234 204  9.5486020000000e-01
+233 205  2.2487060000000e+03
+234 205 -1.0206550000000e+00
+192 206 -9.9229510000000e-01
+197 206 -2.1898570000000e+01
+198 206 -2.1898570000000e+01
+199 206 -2.1898570000000e+01
+234 206  8.9000960000000e-01
+235 206  1.0392050000000e+00
+191 207  7.7048970000000e-03
+235 207 -1.4613620000000e+02
+237 207  7.7048970000000e-03
+197 208 -6.5890520000000e-01
+198 208 -1.1064970000000e+00
+199 208 -1.0009090000000e+00
+236 208  1.0000000000000e+00
+237 209  6.8956570000000e-03
+182 210 -1.0000000000000e+00
+212 210 -1.0000000000000e+00
+183 211 -1.0000000000000e+00
+213 211 -1.0000000000000e+00
+184 212 -1.0000000000000e+00
+214 212 -1.0000000000000e+00
+182 213  1.0000000000000e+00
+200 213 -1.0000000000000e+00
+183 214  1.0226760000000e+00
+201 214 -1.0000000000000e+00
+184 215  1.0914180000000e+00
+202 215 -1.0000000000000e+00
+182 216 -1.0000000000000e+00
+188 216 -1.0000000000000e+00
+183 217 -1.0000000000000e+00
+189 217 -1.0000000000000e+00
+184 218 -1.0000000000000e+00
+190 218 -1.0000000000000e+00
+241 219 -1.9969610000000e-01
+242 219 -7.8596160000000e-01
+243 219 -6.4128230000000e-04
+244 219  4.0690410000000e-01
+253 219  2.0247020000000e-01
+254 219  7.9687960000000e-01
+255 219  6.5019060000000e-04
+256 219 -2.1665440000000e+00
+257 220 -1.0000000000000e+00
+264 220 -3.0001500000000e-01
+265 220 -4.0746150000000e-01
+246 221 -1.0000000000000e+00
+247 221 -1.0000000000000e+00
+258 221  1.0000000000000e+00
+244 222  4.0690410000000e-01
+256 222 -2.1665440000000e+00
+264 222  1.0000000000000e+00
+265 223  1.0000000000000e+00
+238 224  0.0000000000000e+00
+241 224 -9.8629890000000e-01
+250 224 -1.0000000000000e+00
+253 224  1.0000000000000e+00
+261 224  1.0000000000000e+00
+264 224  3.5018580000000e+00
+265 224  1.2418840000000e+00
+239 225  0.0000000000000e+00
+242 225 -9.8629890000000e-01
+251 225 -1.0000000000000e+00
+254 225  1.0000000000000e+00
+261 225  1.0000000000000e+00
+264 225 -2.1495590000000e+00
+265 225  9.3602390000000e-01
+240 226  0.0000000000000e+00
+243 226 -9.8629890000000e-01
+252 226 -1.0000000000000e+00
+255 226  1.0000000000000e+00
+261 226  1.0000000000000e+00
+264 226  6.0259860000000e+00
+265 226  4.0868380000000e+00
+253 227  1.1955300000000e-02
+254 227  6.1475030000000e-01
+255 227  1.6059550000000e-01
+256 227  5.9918100000000e-01
+275 227 -1.1949680000000e-02
+276 227 -6.1446120000000e-01
+277 227 -1.6052000000000e-01
+278 227 -1.0000000000000e+00
+257 228  1.0000000000000e+00
+262 228 -9.3350860000000e-02
+263 228 -3.4681810000000e-01
+266 228 -1.0000000000000e+00
+267 228 -1.0000000000000e+00
+268 228 -1.0000000000000e+00
+259 229  1.0000000000000e+00
+256 230 -5.9918100000000e-01
+262 230  1.0000000000000e+00
+278 230  1.0000000000000e+00
+263 231  1.0000000000000e+00
+250 232  1.3333420000000e+01
+253 232  7.8730110000000e-01
+260 232  1.0000000000000e+00
+262 232  1.2120260000000e+01
+263 232  7.7025090000000e-01
+275 232 -7.8693090000000e-01
+251 233  1.0205510000000e+00
+254 233  7.8730110000000e-01
+260 233  1.0000000000000e+00
+262 233 -3.9843990000000e+00
+263 233  6.8134200000000e-01
+276 233 -7.8693090000000e-01
+252 234  3.1874850000000e-03
+255 234  7.8730110000000e-01
+260 234  1.0000000000000e+00
+262 234  1.9252160000000e+01
+263 234  2.2369070000000e+00
+277 234 -7.8693090000000e-01
+253 235 -1.7008130000000e-01
+254 235 -8.2969220000000e-01
+255 235 -6.9701410000000e-04
+256 235  2.5673630000000e+00
+275 235  1.7000140000000e-01
+276 235  8.2930200000000e-01
+277 235  6.9668630000000e-04
+278 235 -4.2847870000000e+00
+279 236 -1.0000000000000e+00
+286 236 -2.5546930000000e-01
+287 236 -4.1224570000000e-01
+258 237 -1.0000000000000e+00
+259 237 -1.0000000000000e+00
+280 237  1.0000000000000e+00
+256 238  2.5673630000000e+00
+278 238 -4.2847870000000e+00
+286 238  1.0000000000000e+00
+287 239  1.0000000000000e+00
+250 240  0.0000000000000e+00
+253 240 -1.0004710000000e+00
+272 240 -1.0000000000000e+00
+275 240  1.0000000000000e+00
+283 240  1.0000000000000e+00
+286 240  2.9555290000000e+00
+287 240  1.2544140000000e+00
+251 241  0.0000000000000e+00
+254 241 -1.0004710000000e+00
+273 241 -1.0000000000000e+00
+276 241  1.0000000000000e+00
+283 241  1.0000000000000e+00
+286 241 -1.8159690000000e+00
+287 241  9.4521190000000e-01
+252 242  0.0000000000000e+00
+255 242 -1.0004710000000e+00
+274 242 -1.0000000000000e+00
+277 242  1.0000000000000e+00
+283 242  1.0000000000000e+00
+286 242  5.0849970000000e+00
+287 242  4.1364790000000e+00
+250 243  2.0247020000000e-01
+269 243 -1.0000000000000e+00
+251 244  7.9687960000000e-01
+270 244 -1.0000000000000e+00
+252 245  2.0398230000000e-01
+271 245 -1.0000000000000e+00
+275 246  9.8180810000000e-03
+276 246  6.1664170000000e-01
+278 246  9.5579440000000e-01
+297 246 -9.8175690000000e-03
+298 246 -6.1660960000000e-01
+299 246 -1.6051480000000e-01
+300 246 -1.0000000000000e+00
+279 247  1.0000000000000e+00
+284 247 -9.8217900000000e-02
+285 247 -3.4856390000000e-01
+288 247 -1.0000000000000e+00
+289 247 -1.0000000000000e+00
+290 247 -1.0000000000000e+00
+281 248  1.0000000000000e+00
+278 249 -9.5579440000000e-01
+284 249  1.0000000000000e+00
+300 249  1.0000000000000e+00
+285 250  1.0000000000000e+00
+272 251  1.3626710000000e+01
+275 251  7.8698300000000e-01
+282 251  1.0000000000000e+00
+284 251  1.2682330000000e+01
+285 251  7.6942870000000e-01
+297 251 -7.8694200000000e-01
+273 252  1.0583890000000e+00
+276 252  7.8698300000000e-01
+282 252  1.0000000000000e+00
+284 252 -4.1684890000000e+00
+285 252  6.8102850000000e-01
+298 252 -7.8694200000000e-01
+274 253  3.4155830000000e-03
+277 253  7.8698300000000e-01
+282 253  1.0000000000000e+00
+284 253  2.0139960000000e+01
+285 253  2.2394150000000e+00
+299 253 -7.8694200000000e-01
+275 254 -1.6786980000000e-01
+276 254 -8.3148250000000e-01
+277 254 -6.9990470000000e-04
+278 254  4.3289930000000e+00
+297 254  1.6786100000000e-01
+298 254  8.3143910000000e-01
+299 254  6.9986820000000e-04
+300 254 -4.5292090000000e+00
+301 255 -1.0000000000000e+00
+308 255 -2.5301530000000e-01
+309 255 -4.1256250000000e-01
+280 256 -1.0000000000000e+00
+281 256 -1.0000000000000e+00
+302 256  1.0000000000000e+00
+278 257  4.3289930000000e+00
+300 257 -4.5292090000000e+00
+308 257  1.0000000000000e+00
+309 258  1.0000000000000e+00
+272 259  0.0000000000000e+00
+275 259 -1.0000520000000e+00
+294 259 -1.0000000000000e+00
+297 259  1.0000000000000e+00
+305 259  1.0000000000000e+00
+308 259  2.9254360000000e+00
+309 259  1.2552490000000e+00
+273 260  0.0000000000000e+00
+276 260 -1.0000520000000e+00
+295 260 -1.0000000000000e+00
+298 260  1.0000000000000e+00
+305 260  1.0000000000000e+00
+308 260 -1.7975930000000e+00
+309 260  9.4582430000000e-01
+274 261  0.0000000000000e+00
+277 261 -1.0000520000000e+00
+296 261 -1.0000000000000e+00
+299 261  1.0000000000000e+00
+305 261  1.0000000000000e+00
+308 261  5.0331660000000e+00
+309 261  4.1397830000000e+00
+272 262  1.7000140000000e-01
+291 262 -1.0000000000000e+00
+273 263  8.2930200000000e-01
+292 263 -1.0000000000000e+00
+274 264  2.0397290000000e-01
+293 264 -1.0000000000000e+00
+297 265  9.6798500000000e-03
+298 265  6.1671090000000e-01
+299 265  1.6051810000000e-01
+300 265  9.9729840000000e-01
+319 265 -9.6801700000000e-03
+320 265 -6.1673130000000e-01
+321 265 -1.6052340000000e-01
+322 265 -1.0000000000000e+00
+301 266  1.0000000000000e+00
+306 266 -9.8528720000000e-02
+307 266 -3.4867100000000e-01
+310 266 -1.0000000000000e+00
+311 266 -1.0000000000000e+00
+312 266 -1.0000000000000e+00
+303 267  1.0000000000000e+00
+300 268 -9.9729840000000e-01
+306 268  1.0000000000000e+00
+322 268  1.0000000000000e+00
+307 269  1.0000000000000e+00
+294 270  1.3646010000000e+01
+297 270  7.8690890000000e-01
+304 270  1.0000000000000e+00
+306 270  1.2716190000000e+01
+307 270  7.6935860000000e-01
+319 270 -7.8693490000000e-01
+295 271  1.0608970000000e+00
+298 271  7.8690890000000e-01
+304 271  1.0000000000000e+00
+306 271 -4.1795750000000e+00
+307 271  6.8099360000000e-01
+320 271 -7.8693490000000e-01
+296 272  3.4309680000000e-03
+299 272  7.8690890000000e-01
+304 272  1.0000000000000e+00
+306 272  2.0193410000000e+01
+307 272  2.2395320000000e+00
+321 272 -7.8693490000000e-01
+297 273 -1.6772330000000e-01
+298 273 -8.3154050000000e-01
+299 273 -7.0311130000000e-04
+300 273  4.5319110000000e+00
+319 273  1.6772880000000e-01
+320 273  8.3156800000000e-01
+321 273  7.0313460000000e-04
+322 273 -4.5441880000000e+00
+323 274 -1.0000000000000e+00
+330 274 -2.5288910000000e-01
+331 274 -4.1262900000000e-01
+302 275 -1.0000000000000e+00
+303 275 -1.0000000000000e+00
+324 275  1.0000000000000e+00
+300 276  4.5319110000000e+00
+322 276 -4.5441880000000e+00
+330 276  1.0000000000000e+00
+331 277  1.0000000000000e+00
+294 278  0.0000000000000e+00
+297 278 -9.9996690000000e-01
+316 278 -1.0000000000000e+00
+319 278  1.0000000000000e+00
+327 278  1.0000000000000e+00
+330 278  2.9235700000000e+00
+331 278  1.2552940000000e+00
+295 279  0.0000000000000e+00
+298 279 -9.9996690000000e-01
+317 279 -1.0000000000000e+00
+320 279  1.0000000000000e+00
+327 279  1.0000000000000e+00
+330 279 -1.7964900000000e+00
+331 279  9.4585160000000e-01
+296 280  0.0000000000000e+00
+299 280 -9.9996690000000e-01
+318 280 -1.0000000000000e+00
+321 280  1.0000000000000e+00
+327 280  1.0000000000000e+00
+330 280  5.0299350000000e+00
+331 280  4.1401400000000e+00
+294 281  1.6786100000000e-01
+313 281 -1.0000000000000e+00
+295 282  8.3143910000000e-01
+314 282 -1.0000000000000e+00
+296 283  2.0398560000000e-01
+315 283 -1.0000000000000e+00
+319 284  9.6473500000000e-03
+320 284  6.1499680000000e-01
+321 284  1.6066380000000e-01
+322 284  1.0122750000000e+00
+341 284 -9.6630710000000e-03
+342 284 -6.1599900000000e-01
+343 284 -1.6092570000000e-01
+344 284 -1.0000000000000e+00
+323 285  1.0000000000000e+00
+328 285 -9.7740150000000e-02
+329 285 -3.4838900000000e-01
+332 285 -1.0000000000000e+00
+333 285 -1.0000000000000e+00
+334 285 -1.0000000000000e+00
+325 286  1.0000000000000e+00
+322 287 -1.0122750000000e+00
+328 287  1.0000000000000e+00
+344 287  1.0000000000000e+00
+329 288  1.0000000000000e+00
+316 289  1.3653370000000e+01
+319 289  7.8530800000000e-01
+326 289  1.0000000000000e+00
+328 289  1.2536040000000e+01
+329 289  7.6861380000000e-01
+341 289 -7.8658770000000e-01
+317 290  1.0618540000000e+00
+320 290  7.8530800000000e-01
+326 290  1.0000000000000e+00
+328 290 -4.1203450000000e+00
+329 290  6.8034460000000e-01
+342 290 -7.8658770000000e-01
+318 291  3.4368480000000e-03
+321 291  7.8530800000000e-01
+326 291  1.0000000000000e+00
+328 291  1.9907200000000e+01
+329 291  2.2374860000000e+00
+343 291 -7.8658770000000e-01
+319 292 -1.6769600000000e-01
+320 292 -8.2983350000000e-01
+321 292 -8.4358210000000e-04
+322 292  4.5319130000000e+00
+341 292  1.6796930000000e-01
+342 292  8.3118580000000e-01
+343 292  8.4495670000000e-04
+344 292 -4.4769570000000e+00
+345 293 -1.0000000000000e+00
+352 293 -2.5422820000000e-01
+353 293 -4.1467850000000e-01
+324 294 -1.0000000000000e+00
+325 294 -1.0000000000000e+00
+346 294  1.0000000000000e+00
+322 295  4.5319120000000e+00
+344 295 -4.4769570000000e+00
+352 295  1.0000000000000e+00
+353 296  1.0000000000000e+00
+316 297  0.0000000000000e+00
+319 297 -9.9837310000000e-01
+338 297 -1.0000000000000e+00
+341 297  1.0000000000000e+00
+349 297  1.0000000000000e+00
+352 297  2.9258000000000e+00
+353 297  1.2548710000000e+00
+317 298  0.0000000000000e+00
+320 298 -9.9837310000000e-01
+339 298 -1.0000000000000e+00
+342 298  1.0000000000000e+00
+349 298  1.0000000000000e+00
+352 298 -1.7994740000000e+00
+353 298  9.4529590000000e-01
+318 299  0.0000000000000e+00
+321 299 -9.9837310000000e-01
+340 299 -1.0000000000000e+00
+343 299  1.0000000000000e+00
+349 299  1.0000000000000e+00
+352 299  5.0329780000000e+00
+353 299  4.1465320000000e+00
+316 300  1.6772880000000e-01
+335 300 -1.0000000000000e+00
+317 301  8.3156800000000e-01
+336 301 -1.0000000000000e+00
+318 302  2.0458700000000e-01
+337 302 -1.0000000000000e+00
+341 303  8.9580030000000e-03
+342 303  5.6239150000000e-01
+343 303  1.7143160000000e-01
+344 303  1.5349870000000e+00
+363 303 -9.3684010000000e-03
+364 303 -5.8815670000000e-01
+365 303 -1.7928550000000e-01
+366 303 -1.0000000000000e+00
+345 304  1.0000000000000e+00
+350 304 -7.6424570000000e-02
+351 304 -3.3630700000000e-01
+354 304 -1.0000000000000e+00
+355 304 -1.0000000000000e+00
+356 304 -1.0000000000000e+00
+347 305  1.0000000000000e+00
+344 306 -1.5349870000000e+00
+350 306  1.0000000000000e+00
+366 306  1.0000000000000e+00
+351 307  1.0000000000000e+00
+338 308  1.3927700000000e+01
+341 308  7.4278120000000e-01
+348 308  1.0000000000000e+00
+350 308  7.7124140000000e+00
+351 308  7.3754050000000e-01
+363 308 -7.7681060000000e-01
+339 309  1.0977920000000e+00
+342 309  7.4278120000000e-01
+348 309  1.0000000000000e+00
+350 309 -2.5345340000000e+00
+351 309  6.5320800000000e-01
+364 309 -7.7681060000000e-01
+340 310  3.6610400000000e-03
+343 310  7.4278120000000e-01
+348 310  1.0000000000000e+00
+350 310  1.2244490000000e+01
+351 310  2.1513860000000e+00
+365 310 -7.7681060000000e-01
+341 311 -1.6726420000000e-01
+342 311 -7.7757830000000e-01
+343 311 -1.1350930000000e-02
+344 311  3.9419710000000e+00
+363 311  1.7492720000000e-01
+364 311  8.1320190000000e-01
+365 311  1.1870950000000e-02
+366 311 -2.5680820000000e+00
+367 312 -1.0000000000000e+00
+374 312 -3.1132270000000e-01
+375 312 -4.5572680000000e-01
+346 313 -1.0000000000000e+00
+347 313 -1.0000000000000e+00
+368 313  1.0000000000000e+00
+344 314  3.9419710000000e+00
+366 314 -2.5680820000000e+00
+374 314  1.0000000000000e+00
+375 315  1.0000000000000e+00
+338 316  0.0000000000000e+00
+341 316 -9.5619350000000e-01
+360 316 -1.0000000000000e+00
+363 316  1.0000000000000e+00
+371 316  1.0000000000000e+00
+374 316  3.1494540000000e+00
+375 316  1.2129980000000e+00
+339 317  0.0000000000000e+00
+342 317 -9.5619350000000e-01
+361 317 -1.0000000000000e+00
+364 317  1.0000000000000e+00
+371 317  1.0000000000000e+00
+374 317 -1.9859190000000e+00
+375 317  9.0706840000000e-01
+340 318  0.0000000000000e+00
+343 318 -9.5619350000000e-01
+362 318 -1.0000000000000e+00
+365 318  1.0000000000000e+00
+371 318  1.0000000000000e+00
+374 318  5.3936870000000e+00
+375 318  4.2274630000000e+00
+338 319  1.6796930000000e-01
+357 319 -1.0000000000000e+00
+339 320  8.3118580000000e-01
+358 320 -1.0000000000000e+00
+340 321  2.3079690000000e-01
+359 321 -1.0000000000000e+00
+363 322  4.9560030000000e-03
+364 322  2.0925110000000e-01
+365 322  4.3415660000000e-01
+366 322  6.1773840000000e+00
+385 322 -5.6864040000000e-03
+386 322 -2.4008990000000e-01
+387 322 -4.9814130000000e-01
+388 322 -1.0000000000000e+00
+367 323  1.0000000000000e+00
+372 323 -5.1899590000000e-02
+373 323 -2.2819930000000e-01
+376 323 -1.0000000000000e+00
+377 323 -1.0000000000000e+00
+378 323 -1.0000000000000e+00
+369 324  1.0000000000000e+00
+366 325 -6.1773840000000e+00
+372 325  1.0000000000000e+00
+388 325  1.0000000000000e+00
+373 326  1.0000000000000e+00
+360 327  2.2884660000000e+01
+363 327  6.4836370000000e-01
+370 327  1.0000000000000e+00
+372 327  1.0434500000000e+00
+373 327  4.2175860000000e-01
+385 327 -7.4391760000000e-01
+361 328  2.5197030000000e+00
+364 328  6.4836370000000e-01
+370 328  1.0000000000000e+00
+372 328 -3.4146640000000e-01
+373 328  3.7988980000000e-01
+386 328 -7.4391760000000e-01
+362 329  1.7727920000000e-02
+365 329  6.4836370000000e-01
+370 329  1.0000000000000e+00
+372 329  1.6460520000000e+00
+373 329  1.3054760000000e+00
+387 329 -7.4391760000000e-01
+360 330  1.7492720000000e-01
+379 330 -1.0000000000000e+00
+361 331  8.1320190000000e-01
+380 331 -1.0000000000000e+00
+362 332  6.6961900000000e-01
+381 332 -1.0000000000000e+00
+87 333  6.3180580000000e+00
+93 333  1.0081210000000e+00
+88 334  2.1016520000000e+00
+94 334  9.8325000000000e-01
+89 335  1.0216340000000e+01
+95 335  9.7112200000000e-01
+90 336  4.7715330000000e+00
+96 336  1.0168970000000e+00
+91 337  1.5445530000000e+00
+97 337  9.6515200000000e-01
+92 338  7.4032580000000e+00
+98 338  9.3991980000000e-01
+99 339  2.7676480000000e+02
+105 339  8.8770670000000e-01
+100 340  1.9219040000000e+02
+106 340  1.2620630000000e+00
+101 341  4.6529740000000e+02
+107 341  8.3730050000000e-01
+102 342  4.0263530000000e+02
+108 342  9.3272340000000e-01
+103 343  2.4395160000000e+02
+109 343  1.1570060000000e+00
+104 344  6.9442570000000e+02
+110 344  9.0252430000000e-01
+111 345  2.1471690000000e+00
+117 345  7.3310410000000e-01
+112 346  1.8303540000000e+00
+118 346  7.7070690000000e-01
+113 347  5.4194960000000e+00
+119 347  9.1067970000000e-01
+114 348  1.5934600000000e+00
+120 348  4.4472830000000e-01
+115 349  1.5193590000000e+00
+121 349  5.2296010000000e-01
+116 350  5.9272710000000e+00
+122 350  8.1417070000000e-01
+123 351  8.6013230000000e+00
+129 351  5.8171510000000e-01
+124 352  6.1974850000000e+00
+130 352  5.3220720000000e-01
+125 353  3.7670330000000e+01
+131 353  1.1683300000000e+00
+126 354  1.0955350000000e+01
+132 354  7.4939930000000e-01
+127 355  8.2864270000000e+00
+133 355  7.1973830000000e-01
+128 356  3.5092930000000e+01
+134 356  1.1008490000000e+00
+135 357  4.3389190000000e-01
+138 357  2.2797130000000e+00
+136 358  1.1375720000000e-01
+139 358  6.0698210000000e-01
+137 359  4.0354730000000e-01
+140 359  8.0049890000000e-03
+141 360  1.1577040000000e+00
+144 360  4.0422280000000e+00
+142 361  4.1932590000000e-01
+145 361  2.4496110000000e+00
+143 362  1.0246470000000e-01
+146 362  3.6475180000000e-01
+151 363  1.7257450000000e+02
+154 363  1.4917610000000e+01
+152 364  1.6158450000000e+02
+155 364  1.2093800000000e+01
+153 365  1.4531450000000e+02
+156 365  5.7400960000000e+00
+157 366  4.5018890000000e-03
+158 366  9.5263590000000e-01
+159 366 -1.0000000000000e+00
+158 367  9.4488160000000e-01
+163 367  1.9882060000000e+01
+164 367  1.5998700000000e+01
+165 367  7.7694990000000e+00
+159 368  1.0081400000000e+00
+163 368  9.8828980000000e+01
+164 368  1.4755580000000e+02
+165 368  1.3084370000000e+02
+160 369  1.0000000000000e+00
+163 369  1.8011980000000e+00
+161 370  1.0000000000000e+00
+164 370  2.1962210000000e+00
+162 371  1.0000000000000e+00
+165 371  2.0607380000000e+00
+163 372  1.9882060000000e+01
+166 372  9.7404530000000e-01
+164 373  1.5998700000000e+01
+167 373  9.3133780000000e-01
+165 374  7.7694990000000e+00
+168 374  8.2771400000000e-01
+169 375 -1.0000000000000e+00
+172 375 -1.0000000000000e+00
+175 375  5.6357910000000e-02
+176 375  5.6357910000000e-02
+177 375  5.6357910000000e-02
+170 376 -1.0000000000000e+00
+173 376 -1.0000000000000e+00
+175 376  7.3959730000000e-01
+176 376  7.3959730000000e-01
+177 376  7.3959730000000e-01
+171 377 -1.0000000000000e+00
+174 377 -1.0000000000000e+00
+175 377  2.0404480000000e-01
+176 377  2.0404480000000e-01
+177 377  2.0404480000000e-01
+172 378  1.0000000000000e+00
+175 378 -1.0000000000000e+00
+173 379  1.0000000000000e+00
+176 379 -1.0000000000000e+00
+174 380  1.0000000000000e+00
+177 380 -1.0000000000000e+00
+175 381  1.0000000000000e+00
+178 381  1.0000000000000e+00
+176 382  1.0000000000000e+00
+179 382  1.0000000000000e+00
+177 383  1.0000000000000e+00
+180 383  1.0000000000000e+00
+102 384 -1.9453890000000e+01
+418 384  1.0000000000000e+00
+424 384 -9.5304210000000e-02
+103 385 -2.2090310000000e+01
+419 385  1.0000000000000e+00
+424 385 -8.8197620000000e-02
+104 386 -4.9563590000000e+01
+420 386  1.0000000000000e+00
+424 386 -1.0690420000000e-04
+421 387  1.7973450000000e+02
+422 387 -2.5957400000000e+00
+422 388  1.0000000000000e+00
+423 388 -9.6216520000000e-02
+102 389 -1.0000000000000e+00
+103 389 -1.0000000000000e+00
+104 389 -1.0000000000000e+00
+423 389  9.6216520000000e-02
+424 389 -8.8937280000000e-03
+126 390  9.3082790000000e-01
+127 390  9.3082790000000e-01
+128 390  9.3082790000000e-01
+425 390 -1.1383520000000e+00
+436 390  9.5341780000000e-02
+126 391  8.1769790000000e-01
+426 391 -5.5083520000000e-01
+436 391  4.6134780000000e-02
+127 392  8.1769790000000e-01
+427 392 -4.4892230000000e-01
+436 392  3.7599150000000e-02
+128 393  6.8068650000000e+00
+428 393 -2.0188420000000e-03
+436 393  1.6908660000000e-04
+429 394 -6.0313590000000e-01
+430 394 -1.1914260000000e+00
+431 394 -2.0901010000000e-01
+432 394 -2.3236640000000e-01
+126 395 -1.5881990000000e+00
+430 395  1.0000000000000e+00
+436 395 -8.9606730000000e-02
+127 396 -1.7894780000000e+00
+431 396  1.0000000000000e+00
+436 396 -8.2283250000000e-02
+128 397 -4.0128040000000e+00
+432 397  1.0000000000000e+00
+436 397 -9.9680420000000e-05
+433 398  1.1868740000000e+00
+435 398 -8.7134320000000e-01
+434 399  9.9186010000000e-01
+435 399 -7.3414950000000e-01
+126 400 -1.0000000000000e+00
+127 400 -1.0000000000000e+00
+128 400 -1.0000000000000e+00
+435 400  8.9782490000000e-01
+436 400 -1.0242690000000e-01
+185 401  2.6330250000000e+02
+188 401  1.6710230000000e+01
+186 402  2.5231250000000e+02
+189 402  1.5091380000000e+01
+187 403  2.3604250000000e+02
+190 403  1.1440290000000e+01
+191 404  6.8429330000000e-03
+192 404  9.6227440000000e-01
+193 404 -1.0000000000000e+00
+192 405  9.5486020000000e-01
+197 405  3.5042120000000e+01
+198 405  2.8167190000000e+01
+199 405  1.3668540000000e+01
+193 406  1.0077050000000e+00
+197 406  8.5846760000000e+01
+198 406  1.4416210000000e+02
+199 406  1.3040540000000e+02
+194 407  1.0000000000000e+00
+197 407  1.6589050000000e+00
+195 408  1.0000000000000e+00
+198 408  2.1064970000000e+00
+196 409  1.0000000000000e+00
+199 409  2.0009090000000e+00
+197 410  3.5042120000000e+01
+200 410  1.0000000000000e+00
+198 411  2.8167190000000e+01
+201 411  9.7782690000000e-01
+199 412  1.3668540000000e+01
+202 412  9.1623940000000e-01
+203 413 -1.0000000000000e+00
+206 413 -1.0000000000000e+00
+209 413  3.4351900000000e-03
+210 413  3.4351900000000e-03
+211 413  3.4351900000000e-03
+204 414 -1.0000000000000e+00
+207 414 -1.0000000000000e+00
+209 414  4.3016970000000e-02
+210 414  4.3016970000000e-02
+211 414  4.3016970000000e-02
+205 415 -1.0000000000000e+00
+208 415 -1.0000000000000e+00
+209 415  9.5354780000000e-01
+210 415  9.5354780000000e-01
+211 415  9.5354780000000e-01
+206 416  1.0000000000000e+00
+209 416 -1.0000000000000e+00
+207 417  1.0000000000000e+00
+210 417 -1.0000000000000e+00
+208 418  1.0000000000000e+00
+211 418 -1.0000000000000e+00
+209 419  1.0000000000000e+00
+212 419  1.0000000000000e+00
+210 420  1.0000000000000e+00
+213 420  1.0000000000000e+00
+211 421  1.0000000000000e+00
+214 421  1.0000000000000e+00
+90 422 -4.7613130000000e-02
+461 422  1.0000000000000e+00
+467 422 -2.3334700000000e-05
+91 423 -5.7464350000000e-02
+462 423  1.0000000000000e+00
+467 423 -3.5266560000000e-04
+92 424 -1.2956040000000e-01
+463 424  1.0000000000000e+00
+467 424 -1.7625420000000e-02
+464 425  2.7046250000000e+02
+465 425 -2.8000670000000e+00
+465 426  1.0000000000000e+00
+466 426 -1.6856930000000e+00
+90 427 -1.0000000000000e+00
+91 427 -1.0000000000000e+00
+92 427 -1.0000000000000e+00
+466 427  1.6856930000000e+00
+467 427 -1.4266740000000e-01
+114 428  1.2149740000000e-01
+115 428  1.2149740000000e-01
+116 428  1.2149740000000e-01
+468 428 -1.1383520000000e+00
+479 428  2.1230520000000e-02
+114 429  6.0555750000000e-01
+469 429 -1.9490180000000e-02
+479 429  3.6349630000000e-04
+115 430  3.3579270000000e-01
+470 430 -1.3533830000000e-01
+479 430  2.5240900000000e-03
+116 431  1.0673090000000e-01
+471 431 -9.5354780000000e-01
+479 431  1.7783880000000e-02
+472 432 -9.0759220000000e-01
+473 432 -5.7118220000000e+00
+474 432 -9.3568410000000e-01
+475 432 -1.0346550000000e+00
+114 433 -4.3240930000000e-02
+473 433  1.0000000000000e+00
+479 433 -2.5956110000000e-05
+115 434 -5.2174910000000e-02
+474 434  1.0000000000000e+00
+479 434 -3.9218900000000e-04
+116 435 -1.1763140000000e-01
+475 435  1.0000000000000e+00
+479 435 -1.9600160000000e-02
+476 436  5.3140780000000e+00
+478 436 -1.0021840000000e+00
+477 437  3.4483720000000e-01
+478 437 -2.6478620000000e-01
+114 438 -1.0000000000000e+00
+115 438 -1.0000000000000e+00
+116 438 -1.0000000000000e+00
+478 438  1.7669710000000e+00
+479 438 -1.7474060000000e-01
+438 439  9.9149730000000e+01
+444 439 -1.0000000000000e+00
+447 439 -3.3113980000000e-05
+439 440  1.7263960000000e+02
+445 440 -1.0000000000000e+00
+448 440 -4.1108120000000e-05
+440 441  3.5663980000000e+02
+446 441 -1.0000000000000e+00
+449 441 -8.4587180000000e-05
+441 442  2.0000080000000e+02
+444 442  2.5000000000000e+00
+447 442  3.3113980000000e-05
+442 443  3.4900330000000e+02
+445 443  2.5000000000000e+00
+448 443  4.1108120000000e-05
+443 444  7.2206780000000e+02
+446 444  2.5000000000000e+00
+449 444  8.4587180000000e-05
+444 445  1.0000000000000e+00
+453 445 -1.4485650000000e-06
+445 446  1.0000000000000e+00
+453 446 -5.1132920000000e-04
+446 447  1.0000000000000e+00
+453 447 -9.5438870000000e-01
+447 448  1.0050250000000e+00
+454 448 -3.4351900000000e-03
+448 449  1.0028740000000e+00
+454 449 -4.3016970000000e-02
+449 450  1.0013870000000e+00
+454 450 -9.5354780000000e-01
+450 451  1.0000000000000e+00
+453 451 -4.9455600000000e-05
+451 452  1.0000000000000e+00
+453 452 -2.1775570000000e-03
+452 453  1.0000000000000e+00
+453 453 -4.2871530000000e-02
+453 454  1.0000000000000e+00
+455 454 -1.0000000000000e+00
+466 454  1.5000000000000e+00
+478 454  5.0000000000000e-01
+454 455  1.0000000000000e+00
+456 455 -3.1622000000000e+05
+459 455 -1.2132580000000e+04
+460 455 -1.0000000000000e+00
+466 455 -2.0451810000000e+04
+477 455  9.1527510000000e+03
+455 456  9.1463570000000e+00
+457 456  3.7734920000000e-03
+456 457  2.2487060000000e+03
+457 457 -1.2505330000000e-01
+457 458  6.7588380000000e-02
+458 458  6.5087120000000e+01
+466 458 -1.8859040000000e-01
+458 459 -9.1527510000000e+03
+460 459  7.5439430000000e-01
+476 459 -9.1527510000000e+03
+477 459 -6.9047830000000e+03
+459 460  1.0000000000000e+00
+466 460  1.8569290000000e-01
+478 460 -5.0000000000000e-01
+460 461  1.9167940000000e-04
+466 461  2.6684520000000e+00
+478 461  8.8948400000000e-01
+266 462  5.2397100000000e-01
+269 462  2.5902730000000e+00
+267 463  1.2090360000000e-01
+270 463  1.0000000000000e+00
+268 464  3.6607730000000e-01
+271 464  1.8323330000000e-02
+288 465  5.3070830000000e-01
+291 465  2.6120320000000e+00
+289 466  1.2143810000000e-01
+292 466  1.0000000000000e+00
+290 467  3.6327480000000e-01
+293 467  1.9398480000000e-02
+310 468  5.3114850000000e-01
+313 468  2.6134470000000e+00
+311 469  1.2147310000000e-01
+314 469  1.0000000000000e+00
+312 470  3.6309170000000e-01
+315 470  1.9470450000000e-02
+332 471  5.3131620000000e-01
+335 471  2.6139860000000e+00
+333 472  1.2148640000000e-01
+336 472  1.0000000000000e+00
+334 473  3.6302190000000e-01
+337 473  1.9497930000000e-02
+354 474  5.3753340000000e-01
+357 474  2.6338800000000e+00
+355 475  1.2197960000000e-01
+358 475  1.0000000000000e+00
+356 476  3.6043580000000e-01
+359 476  2.0538460000000e-02
+376 477  7.1092830000000e-01
+379 477  3.1304670000000e+00
+377 478  1.3573580000000e-01
+380 478  1.0000000000000e+00
+378 479  2.8830910000000e-01
+381 479  7.1489880000000e-02
--- a/examples/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/examples/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -1,84 +1,9 @@
 %canon_reldir%_EXTRA_DIST =
 
-%canon_reldir%_CLEANFILES =
-%canon_reldir%_DISTCLEANFILES =
-%canon_reldir%_MAINTAINERCLEANFILES =
-
-%canon_reldir%_data_SRC = \
-   %reldir%/data/penny.mat
-
-octdata_DATA += \
-  $(%canon_reldir%_data_SRC)
-
-%canon_reldir%_code_SRC = \
-  %reldir%/code/@FIRfilter/FIRfilter.m \
-  %reldir%/code/@FIRfilter/FIRfilter_aggregation.m \
-  %reldir%/code/@FIRfilter/display.m \
-  %reldir%/code/@FIRfilter/subsasgn.m \
-  %reldir%/code/@FIRfilter/subsref.m \
-  %reldir%/code/@polynomial/disp.m \
-  %reldir%/code/@polynomial/double.m \
-  %reldir%/code/@polynomial/end.m \
-  %reldir%/code/@polynomial/get.m \
-  %reldir%/code/@polynomial/mtimes.m \
-  %reldir%/code/@polynomial/numel.m \
-  %reldir%/code/@polynomial/plot.m \
-  %reldir%/code/@polynomial/polynomial.m \
-  %reldir%/code/@polynomial/polynomial_superiorto.m \
-  %reldir%/code/@polynomial/polyval.m \
-  %reldir%/code/@polynomial/roots.m \
-  %reldir%/code/@polynomial/set.m \
-  %reldir%/code/@polynomial/subsasgn.m \
-  %reldir%/code/@polynomial/subsref.m \
-  %reldir%/code/addtwomatrices.cc \
-  %reldir%/code/celldemo.cc \
-  %reldir%/code/embedded.cc \
-  %reldir%/code/fortrandemo.cc \
-  %reldir%/code/fortransub.f \
-  %reldir%/code/funcdemo.cc \
-  %reldir%/code/globaldemo.cc \
-  %reldir%/code/helloworld.cc \
-  %reldir%/code/make_int.cc \
-  %reldir%/code/mex_demo.c \
-  %reldir%/code/mycell.c \
-  %reldir%/code/myfeval.c \
-  %reldir%/code/myfevalf.f \
-  %reldir%/code/myfunc.c \
-  %reldir%/code/myhello.c \
-  %reldir%/code/mypow2.c \
-  %reldir%/code/myprop.c \
-  %reldir%/code/myset.c \
-  %reldir%/code/mysparse.c \
-  %reldir%/code/mystring.c \
-  %reldir%/code/mystruct.c \
-  %reldir%/code/oct_demo.cc \
-  %reldir%/code/oregonator.cc \
-  %reldir%/code/oregonator.m \
-  %reldir%/code/paramdemo.cc \
-  %reldir%/code/polynomial2.m \
-  %reldir%/code/standalone.cc \
-  %reldir%/code/standalonebuiltin.cc \
-  %reldir%/code/stringdemo.cc \
-  %reldir%/code/structdemo.cc \
-  %reldir%/code/unwinddemo.cc
+include %reldir%/code/module.mk
+include %reldir%/data/module.mk
 
 %canon_reldir%_EXTRA_DIST += \
-  $(%canon_reldir%_data_SRC) \
-  $(%canon_reldir%_code_SRC) \
-  %reldir%/code/COPYING \
-  %reldir%/module.mk
+  %reldir%/code/COPYING
 
 EXTRA_DIST += $(%canon_reldir%_EXTRA_DIST)
-
-CLEANFILES += $(%canon_reldir%_CLEANFILES)
-DISTCLEANFILES += $(%canon_reldir%_DISTCLEANFILES)
-MAINTAINERCLEANFILES += $(%canon_reldir%_MAINTAINERCLEANFILES)
-
-examples-clean:
-	rm -f $(%canon_reldir%_CLEANFILES)
-
-examples-distclean: examples-clean
-	rm -f $(%canon_reldir%_DISTCLEANFILES)
-
-examples-maintainer-clean: examples-distclean
-	rm -f $(%canon_reldir%_MAINTAINERCLEANFILES)
--- a/libgui/graphics/BaseControl.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/graphics/BaseControl.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -50,18 +50,30 @@
     if (props.style_is ("edit")
         || props.style_is ("listbox"))
       {
-        p.setColor (QPalette::Base,
-                    Utils::fromRgb (props.get_backgroundcolor_rgb ()));
-        p.setColor (QPalette::Text,
+        Matrix bg_color = props.get_backgroundcolor_rgb ();
+        // Matlab compatibility: Default color is ignored, and rendered as
+        // white ([1.0, 1.0, 1.0]).  See bug #58261.
+        if (bg_color(0) == bg_color(1) && bg_color(0) == bg_color(2)
+            && (std::abs (bg_color(1) - 0.94) < .005))
+          bg_color.fill (1.0);
+
+        p.setColor (QPalette::Active, QPalette::Base,
+                    Utils::fromRgb (bg_color));
+        p.setColor (QPalette::Inactive, QPalette::Base,
+                    Utils::fromRgb (bg_color));
+        p.setColor (QPalette::Active, QPalette::Text,
+                    Utils::fromRgb (props.get_foregroundcolor_rgb ()));
+        p.setColor (QPalette::Inactive, QPalette::Text,
                     Utils::fromRgb (props.get_foregroundcolor_rgb ()));
       }
     else if (props.style_is ("popupmenu"))
       {
-        // popumenu (QComboBox) is a listbox with a button, so needs set colors for both
+        // popupmenu (QComboBox) is a listbox with a button.
+        // This requires setting colors for both.
         QColor bcol = Utils::fromRgb (props.get_backgroundcolor_rgb ());
         QColor fcol = Utils::fromRgb (props.get_foregroundcolor_rgb ());
-        QString qss = QString ("background: %1 none;\n"
-                               "color: %2;")
+        QString qss = QString (":enabled { background: %1 none;\n"
+                                          "color: %2; }")
                       .arg(bcol.name ()).arg (fcol.name ());
         w->setStyleSheet(qss);
         return;
@@ -69,9 +81,13 @@
     else if (props.style_is ("radiobutton")
              || props.style_is ("checkbox"))
       {
-        p.setColor (QPalette::Button,
+        p.setColor (QPalette::Active, QPalette::Button,
+                    Utils::fromRgb (props.get_backgroundcolor_rgb ()));
+        p.setColor (QPalette::Inactive, QPalette::Button,
                     Utils::fromRgb (props.get_backgroundcolor_rgb ()));
-        p.setColor (QPalette::WindowText,
+        p.setColor (QPalette::Active, QPalette::WindowText,
+                    Utils::fromRgb (props.get_foregroundcolor_rgb ()));
+        p.setColor (QPalette::Inactive, QPalette::WindowText,
                     Utils::fromRgb (props.get_foregroundcolor_rgb ()));
       }
     else if (props.style_is ("pushbutton")
@@ -79,17 +95,21 @@
       {
         QColor bcol = Utils::fromRgb (props.get_backgroundcolor_rgb ());
         QColor fcol = Utils::fromRgb (props.get_foregroundcolor_rgb ());
-        QString qss = QString ("background: %1 none;\n"
-                               "color: %2;")
+        QString qss = QString (":enabled { background: %1 none;\n"
+                                          "color: %2; }")
                       .arg(bcol.name ()).arg (fcol.name ());
         w->setStyleSheet(qss);
         return;
       }
     else
       {
-        p.setColor (QPalette::Window,
+        p.setColor (QPalette::Active, QPalette::Window,
+                    Utils::fromRgb (props.get_backgroundcolor_rgb ()));
+        p.setColor (QPalette::Inactive, QPalette::Window,
                     Utils::fromRgb (props.get_backgroundcolor_rgb ()));
-        p.setColor (QPalette::WindowText,
+        p.setColor (QPalette::Active, QPalette::WindowText,
+                    Utils::fromRgb (props.get_foregroundcolor_rgb ()));
+        p.setColor (QPalette::Inactive, QPalette::WindowText,
                     Utils::fromRgb (props.get_foregroundcolor_rgb ()));
       }
 
@@ -119,7 +139,10 @@
                     octave::math::round (bb(2)), octave::math::round (bb(3)));
     w->setFont (Utils::computeFont<uicontrol> (up, bb(3)));
     updatePalette (up, w);
-    w->setEnabled (up.enable_is ("on"));
+    if (up.enable_is ("inactive"))
+      w->blockSignals (true);
+    else
+      w->setEnabled (up.enable_is ("on"));
     w->setToolTip (Utils::fromStdString (up.get_tooltipstring ()));
     w->setVisible (up.is_visible ());
     m_keyPressHandlerDefined = ! up.get_keypressfcn ().isempty ();
@@ -174,7 +197,16 @@
         break;
 
       case uicontrol::properties::ID_ENABLE:
-        w->setEnabled (up.enable_is ("on"));
+        if (up.enable_is ("inactive"))
+          {
+            w->blockSignals (true);
+            w->setEnabled (true);
+          }
+        else
+          {
+            w->blockSignals (false);
+            w->setEnabled (up.enable_is ("on"));
+          }
         break;
 
       case uicontrol::properties::ID_TOOLTIPSTRING:
--- a/libgui/graphics/Canvas.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/graphics/Canvas.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -371,11 +371,7 @@
 
             r.adjust (-5, -5, 5, 5);
 
-#if defined (HAVE_QMOUSEEVENT_LOCALPOS)
             bool rect_contains_pos = r.contains (event->localPos ());
-#else
-            bool rect_contains_pos = r.contains (event->posF ());
-#endif
             if (rect_contains_pos)
               {
                 currentObj = childObj;
@@ -429,11 +425,7 @@
                 // the axes and still select it.
                 r.adjust (-20, -20, 20, 20);
 
-#if defined (HAVE_QMOUSEEVENT_LOCALPOS)
                 bool rect_contains_pos = r.contains (event->localPos ());
-#else
-                bool rect_contains_pos = r.contains (event->posF ());
-#endif
                 if (rect_contains_pos)
                   axesObj = *it;
               }
@@ -885,7 +877,7 @@
                     props.prepend (figObj.get_handle ().as_octave_value ());
 
                     emit interpreter_event
-                      ([this, props] (octave::interpreter& interp)
+                      ([=] (octave::interpreter& interp)
                        {
                          // INTERPRETER THREAD
 
--- a/libgui/graphics/CheckBoxControl.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/graphics/CheckBoxControl.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -61,10 +61,37 @@
                                     const graphics_object& go, QCheckBox *box)
     : ButtonControl (oct_obj, interp, go, box)
   {
+    uicontrol::properties& up = properties<uicontrol> ();
+
     box->setAutoFillBackground (true);
+    if (up.enable_is ("inactive"))
+      box->setCheckable (false);
   }
 
   CheckBoxControl::~CheckBoxControl (void)
   { }
 
+  void
+  CheckBoxControl::update (int pId)
+  {
+    uicontrol::properties& up = properties<uicontrol> ();
+    QCheckBox *box = qWidget<QCheckBox> ();
+
+    switch (pId)
+      {
+      case uicontrol::properties::ID_ENABLE:
+        {
+          if (up.enable_is ("inactive"))
+            box->setCheckable (false);
+          else
+            box->setCheckable (true);
+          ButtonControl::update (pId);
+        }
+        break;
+
+      default:
+        ButtonControl::update (pId);
+        break;
+      }
+  }
 };
--- a/libgui/graphics/CheckBoxControl.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/graphics/CheckBoxControl.h	Thu Nov 19 13:08:00 2020 -0800
@@ -50,6 +50,9 @@
     static CheckBoxControl *
     create (octave::base_qobject& oct_qobj, octave::interpreter& interp,
             const graphics_object& go);
+
+  protected:
+    void update (int pId);
   };
 
 }
--- a/libgui/graphics/EditControl.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/graphics/EditControl.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -85,6 +85,10 @@
 
     uicontrol::properties& up = properties<uicontrol> ();
 
+    if (up.enable_is ("inactive"))
+      edit->setReadOnly (true);
+    else
+      edit->setEnabled (up.enable_is ("on"));
     edit->setText (Utils::fromStdString (up.get_string_string ()));
     edit->setAlignment (Utils::fromHVAlign (up.get_horizontalalignment (),
                                             up.get_verticalalignment ()));
@@ -117,9 +121,15 @@
 
     uicontrol::properties& up = properties<uicontrol> ();
 
+    if (up.enable_is ("inactive"))
+      edit->setReadOnly (true);
+    else
+      edit->setEnabled (up.enable_is ("on"));
     edit->setAcceptRichText (false);
     edit->setPlainText (Utils::fromStringVector
                         (up.get_string_vector ()).join ("\n"));
+    edit->setAlignment (Utils::fromHVAlign (up.get_horizontalalignment (),
+                                            up.get_verticalalignment ()));
 
     connect (edit, SIGNAL (textChanged (void)),
              SLOT (textChanged (void)));
@@ -177,6 +187,16 @@
                                                 up.get_verticalalignment ()));
         return true;
 
+      case uicontrol::properties::ID_ENABLE:
+        if (up.enable_is ("inactive"))
+          edit->setReadOnly (true);
+        else
+          {
+            edit->setReadOnly (false);
+            edit->setEnabled (up.enable_is ("on"));
+          }
+        return true;
+
       case uicontrol::properties::ID_MIN:
       case uicontrol::properties::ID_MAX:
         if ((up.get_max () - up.get_min ()) > 1)
@@ -208,6 +228,22 @@
                             (up.get_string_vector ()).join ("\n"));
         return true;
 
+      case uicontrol::properties::ID_HORIZONTALALIGNMENT:
+      case uicontrol::properties::ID_VERTICALALIGNMENT:
+        edit->setAlignment (Utils::fromHVAlign (up.get_horizontalalignment (),
+                                                up.get_verticalalignment ()));
+        return true;
+
+      case uicontrol::properties::ID_ENABLE:
+        if (up.enable_is ("inactive"))
+          edit->setReadOnly (true);
+        else
+          {
+            edit->setReadOnly (false);
+            edit->setEnabled (up.enable_is ("on"));
+          }
+        return true;
+
       case uicontrol::properties::ID_MIN:
       case uicontrol::properties::ID_MAX:
         if ((up.get_max () - up.get_min ()) <= 1)
--- a/libgui/graphics/GLCanvas.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/graphics/GLCanvas.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -188,7 +188,7 @@
         catch (octave::execution_exception& ee)
           {
             emit interpreter_event
-              ([ee] (void)
+              ([=] (void)
                {
                  // INTERPRETER THREAD
 
--- a/libgui/graphics/PushButtonControl.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/graphics/PushButtonControl.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -71,6 +71,7 @@
     QImage img = Utils::makeImageFromCData (cdat,
                                             cdat.columns (), cdat.rows ());
     btn->setIcon (QIcon (QPixmap::fromImage (img)));
+    btn->setIconSize (QSize (cdat.columns (), cdat.rows ()));
   }
 
   PushButtonControl::~PushButtonControl (void)
--- a/libgui/graphics/QtHandlesUtils.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/graphics/QtHandlesUtils.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -288,8 +288,12 @@
           int w = qMin (dv(1), static_cast<octave_idx_type> (width));
           int h = qMin (dv(0), static_cast<octave_idx_type> (height));
 
-          int x_off = (w < width ? (width - w) / 2 : 0);
-          int y_off = (h < height ? (height - h) / 2 : 0);
+          // If size mismatch, take data from center of CDATA and
+          // place in in center of QImage.
+          int x_img_off = (w < width ? (width - w) / 2 : 0);
+          int y_img_off = (h < height ? (height - h) / 2 : 0);
+          int x_cdat_off = (dv(1) > w ? (dv(1) - w) / 2 : 0);
+          int y_cdat_off = (dv(0) > h ? (dv(0) - h) / 2 : 0);
 
           QImage img (width, height, QImage::Format_ARGB32);
           img.fill (qRgba (0, 0, 0, 0));
@@ -298,23 +302,25 @@
             {
               uint8NDArray d = v.uint8_array_value ();
 
-              for (int i = 0; i < w; i++)
-                for (int j = 0; j < h; j++)
+              for (int i = x_cdat_off; i < w + x_cdat_off; i++)
+                for (int j = y_cdat_off; j < h + y_cdat_off; j++)
                   {
                     int r = d(j, i, 0);
                     int g = d(j, i, 1);
                     int b = d(j, i, 2);
                     int a = 255;
 
-                    img.setPixel (x_off + i, y_off + j, qRgba (r, g, b, a));
+                    img.setPixel (x_img_off + i - x_cdat_off,
+                                  y_img_off + j - y_cdat_off,
+                                  qRgba (r, g, b, a));
                   }
             }
           else if (v.is_single_type ())
             {
               FloatNDArray f = v.float_array_value ();
 
-              for (int i = 0; i < w; i++)
-                for (int j = 0; j < h; j++)
+              for (int i = x_cdat_off; i < w + x_cdat_off; i++)
+                for (int j = y_cdat_off; j < h + y_cdat_off; j++)
                   {
                     float r = f(j, i, 0);
                     float g = f(j, i, 1);
@@ -322,7 +328,8 @@
                     int a = (octave::math::isnan (r) || octave::math::isnan (g)
                              || octave::math::isnan (b) ? 0 : 255);
 
-                    img.setPixel (x_off + i, y_off + j,
+                    img.setPixel (x_img_off + i - x_cdat_off,
+                                  y_img_off + j - y_cdat_off,
                                   qRgba (octave::math::round (r * 255),
                                          octave::math::round (g * 255),
                                          octave::math::round (b * 255),
@@ -333,8 +340,8 @@
             {
               NDArray d = v.array_value ();
 
-              for (int i = 0; i < w; i++)
-                for (int j = 0; j < h; j++)
+              for (int i = x_cdat_off; i < w + x_cdat_off; i++)
+                for (int j = y_cdat_off; j < h + y_cdat_off; j++)
                   {
                     double r = d(j, i, 0);
                     double g = d(j, i, 1);
@@ -342,7 +349,8 @@
                     int a = (octave::math::isnan (r) || octave::math::isnan (g)
                              || octave::math::isnan (b) ? 0 : 255);
 
-                    img.setPixel (x_off + i, y_off + j,
+                    img.setPixel (x_img_off + i - x_cdat_off,
+                                  y_img_off + j - y_cdat_off,
                                   qRgba (octave::math::round (r * 255),
                                          octave::math::round (g * 255),
                                          octave::math::round (b * 255),
@@ -394,12 +402,7 @@
 
       // We assume a standard mouse with 15 degree steps and Qt returns
       // 1/8 of a degree.
-#if defined (HAVE_QWHEELEVENT_ANGLEDELTA)
       int ydelta = -(event->angleDelta().y ());
-#else
-      int ydelta = (event->orientation () == Qt::Vertical
-                    ? -(event->delta ()) : 0);
-#endif
       retval.setfield ("VerticalScrollCount", octave_value (ydelta / 120));
 
       // FIXME: Is there any way to access the number of lines a scroll step
--- a/libgui/graphics/RadioButtonControl.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/graphics/RadioButtonControl.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -69,11 +69,39 @@
     if (btnGroup)
       btnGroup->addButton (radio);
 
+    uicontrol::properties& up = properties<uicontrol> ();
+
     radio->setAutoFillBackground (true);
     radio->setAutoExclusive (false);
+    if (up.enable_is ("inactive"))
+      radio->setCheckable (false);
   }
 
   RadioButtonControl::~RadioButtonControl (void)
   { }
 
+  void
+  RadioButtonControl::update (int pId)
+  {
+    uicontrol::properties& up = properties<uicontrol> ();
+    QRadioButton *btn = qWidget<QRadioButton> ();
+
+    switch (pId)
+      {
+      case uicontrol::properties::ID_ENABLE:
+        {
+          if (up.enable_is ("inactive"))
+            btn->setCheckable (false);
+          else
+            btn->setCheckable (true);
+          ButtonControl::update (pId);
+        }
+        break;
+
+      default:
+        ButtonControl::update (pId);
+        break;
+      }
+  }
+
 };
--- a/libgui/graphics/RadioButtonControl.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/graphics/RadioButtonControl.h	Thu Nov 19 13:08:00 2020 -0800
@@ -50,6 +50,9 @@
     static RadioButtonControl * create (octave::base_qobject& oct_qobj,
                                         octave::interpreter& interp,
                                         const graphics_object& go);
+
+  protected:
+    void update (int pId);
   };
 
 }
--- a/libgui/graphics/Table.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/graphics/Table.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -1321,11 +1321,7 @@
                                      : QAbstractItemView::NoSelection);
 
     // Set rearrangeablecolumns
-    #if defined (HAVE_QT4)
-      m_tableWidget->horizontalHeader ()->setMovable (enabled && rearrangeableColumns);
-    #elif defined (HAVE_QT5)
-      m_tableWidget->horizontalHeader ()->setSectionsMovable (enabled && rearrangeableColumns);
-    #endif
+    m_tableWidget->horizontalHeader ()->setSectionsMovable (enabled && rearrangeableColumns);
     m_tableWidget->horizontalHeader ()->setDragEnabled (enabled && rearrangeableColumns);
     m_tableWidget->horizontalHeader ()->setDragDropMode (QAbstractItemView::InternalMove);
 
@@ -1504,11 +1500,7 @@
     bool rearrangeableColumns = tp.is_rearrangeablecolumns ();
     bool enabled = tp.is_enable ();
 
-  #if defined (HAVE_QT4)
-    m_tableWidget->horizontalHeader ()->setMovable (enabled && rearrangeableColumns);
-  #elif defined (HAVE_QT5)
     m_tableWidget->horizontalHeader ()->setSectionsMovable (enabled && rearrangeableColumns);
-  #endif
     m_tableWidget->horizontalHeader ()->setDragEnabled (enabled && rearrangeableColumns);
     m_tableWidget->horizontalHeader ()->setDragDropMode (QAbstractItemView::InternalMove);
   }
--- a/libgui/graphics/ToggleButtonControl.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/graphics/ToggleButtonControl.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -77,6 +77,7 @@
     QImage img = Utils::makeImageFromCData (cdat,
                                             cdat.columns (), cdat.rows ());
     btn->setIcon (QIcon (QPixmap::fromImage (img)));
+    btn->setIconSize (QSize (cdat.columns (), cdat.rows ()));
   }
 
   ToggleButtonControl::~ToggleButtonControl (void)
--- a/libgui/graphics/ToolBarButton.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/graphics/ToolBarButton.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -49,7 +49,7 @@
     action->setVisible (tp.is_visible ());
 
     // Get the icon data from cdata or as a named icon
-    QImage img = Utils::makeImageFromCData (tp.get_cdata (), 32, 32);
+    QImage img = Utils::makeImageFromCData (tp.get_cdata (), 24, 24);
 
     if (img.width () == 0)
       {
@@ -104,7 +104,7 @@
       case T::properties::ID_CDATA:
         {
           // Get the icon data from cdata or as a named icon
-          QImage img = Utils::makeImageFromCData (tp.get_cdata (), 32, 32);
+          QImage img = Utils::makeImageFromCData (tp.get_cdata (), 24, 24);
 
           if (img.width () == 0)
             {
--- a/libgui/src/files-dock-widget.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/files-dock-widget.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -245,16 +245,8 @@
         (settings->value (fb_column_state.key).toByteArray ());
 
     // Set header properties for sorting
-#if defined (HAVE_QHEADERVIEW_SETSECTIONSCLICKABLE)
     m_file_tree_view->header ()->setSectionsClickable (true);
-#else
-    m_file_tree_view->header ()->setClickable (true);
-#endif
-#if defined (HAVE_QHEADERVIEW_SETSECTIONSMOVABLE)
     m_file_tree_view->header ()->setSectionsMovable (true);
-#else
-    m_file_tree_view->header ()->setMovable (true);
-#endif
     m_file_tree_view->header ()->setSortIndicatorShown (true);
 
     QStringList mru_dirs =
@@ -723,17 +715,38 @@
     QItemSelectionModel *m = m_file_tree_view->selectionModel ();
     QModelIndexList rows = m->selectedRows ();
 
+    int file_cnt = rows.size ();
+    bool multiple_files = (file_cnt > 1);
+
     for (auto it = rows.begin (); it != rows.end (); it++)
       {
         QModelIndex index = *it;
 
         QFileInfo info = m_file_system_model->fileInfo (index);
 
-        if (QMessageBox::question (this, tr ("Delete file/directory"),
-                                   tr ("Are you sure you want to delete\n")
-                                   + info.filePath (),
-                                   QMessageBox::Yes | QMessageBox::No)
-            == QMessageBox::Yes)
+        QMessageBox::StandardButton dlg_answer;
+        if (multiple_files)
+          if (it == rows.begin ())
+            {
+               dlg_answer = QMessageBox::question (this,
+                              tr ("Delete file/directory"),
+                              tr ("Are you sure you want to delete all %1 selected files?\n").arg (file_cnt),
+                              QMessageBox::Yes | QMessageBox::No);
+               if (dlg_answer != QMessageBox::Yes)
+                 return;
+            }
+          else
+            dlg_answer = QMessageBox::Yes;
+        else
+          {
+            dlg_answer = QMessageBox::question (this,
+                           tr ("Delete file/directory"),
+                           tr ("Are you sure you want to delete\n")
+                           + info.filePath (),
+                           QMessageBox::Yes | QMessageBox::No);
+          }
+
+        if (dlg_answer)
           {
             if (info.isDir ())
               {
--- a/libgui/src/find-files-dialog.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/find-files-dialog.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -126,11 +126,7 @@
     m_file_list->setSortingEnabled (true);
     m_file_list->horizontalHeader ()->restoreState (settings->value (ff_column_state.key).toByteArray ());
     m_file_list->horizontalHeader ()->setSortIndicatorShown (true);
-#if defined (HAVE_QHEADERVIEW_SETSECTIONSCLICKABLE)
     m_file_list->horizontalHeader ()->setSectionsClickable (true);
-#else
-    m_file_list->horizontalHeader ()->setClickable (true);
-#endif
     m_file_list->horizontalHeader ()->setStretchLastSection (true);
     m_file_list->sortByColumn (settings->value (ff_sort_files_by_column).toInt (),
                                static_cast<Qt::SortOrder>
--- a/libgui/src/graphics-init.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/graphics-init.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -63,7 +63,7 @@
 
     graphics_toolkit tk (qt_gtk);
 
-    octave::gtk_manager& gtk_mgr = interp.get_gtk_manager ();
+    gtk_manager& gtk_mgr = interp.get_gtk_manager ();
 
     gtk_mgr.register_toolkit ("qt");
 
--- a/libgui/src/gui-preferences-ed.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/gui-preferences-ed.h	Thu Nov 19 13:08:00 2020 -0800
@@ -215,6 +215,12 @@
 const gui_pref
 ed_notebook_tab_width_max ("editor/notebook_tab_width_max", QVariant (300));
 
+const gui_pref
+ed_force_newline ("editor/force_newline", QVariant (true));
+
+const gui_pref
+ed_rm_trailing_spaces ("editor/rm_trailing_spaces", QVariant (true));
+
 #if defined (HAVE_QSCINTILLA)
 #if defined (Q_OS_WIN32)
 const int os_eol_mode = QsciScintilla::EolWindows;
--- a/libgui/src/gui-preferences-global.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/gui-preferences-global.h	Thu Nov 19 13:08:00 2020 -0800
@@ -136,4 +136,13 @@
 const gui_pref
 global_proxy_pass ("proxyPassword", QVariant (QString ()));
 
+const QStringList
+global_proxy_all_types (QStringList ()
+             << "HttpProxy"
+             << "Socks5Proxy"
+             << QT_TRANSLATE_NOOP ("octave::settings_dialog", "Environment Variables")
+);
+const QList<int>
+global_proxy_manual_types (QList<int> () << 0 << 1);
+
 #endif
--- a/libgui/src/gui-preferences-sc.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/gui-preferences-sc.h	Thu Nov 19 13:08:00 2020 -0800
@@ -96,6 +96,13 @@
 const sc_pref sc_main_debug_continue (sc_main_debug + ":continue", PRE + Qt::Key_F5);
 const sc_pref sc_main_debug_quit (sc_main_debug + ":quit", PRE + Qt::ShiftModifier + Qt::Key_F5);
 
+// tools
+const QString sc_main_tools ("main_tools");
+const sc_pref sc_main_tools_start_profiler (sc_main_tools + ":start_profiler", CTRL_SHIFT + Qt::Key_P);
+const sc_pref sc_main_tools_resume_profiler (sc_main_tools + ":resume_profiler", QKeySequence::UnknownKey);
+const sc_pref sc_main_tools_show_profiler (sc_main_tools + ":show_profiler", Qt::AltModifier + Qt::ShiftModifier + Qt::Key_P);
+
+
 // window
 const QString sc_main_window ("main_window");
 const sc_pref sc_main_window_show_command (sc_main_window + ":show_command", PRE + CTRL_SHIFT + Qt::Key_0);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/led-indicator.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,83 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2013-2020 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include <QColor>
+#include "led-indicator.h"
+
+namespace octave
+{
+
+  led_indicator::led_indicator (led_state initial_state, QWidget *p)
+    : QLabel (p)
+  {
+    setFixedSize(12,12);
+    set_state (initial_state);
+  }
+
+  void led_indicator::set_state (led_state state)
+  {
+    QColor col (Qt::gray);
+
+    switch (state)
+      {
+        case LED_STATE_NO:
+          break;
+
+        case LED_STATE_INACTIVE:
+          col = QColor (Qt::darkRed);
+          break;
+
+        case LED_STATE_ACTIVE:
+          col = QColor (Qt::darkGreen);
+          break;
+      }
+
+    setStyleSheet (style_sheet (col));
+  }
+
+  QString led_indicator::style_sheet (const QColor& col)
+  {
+    int h, s, v;
+
+    col.getHsv (&h, &s, &v);
+    s = s/4;
+    v = 232;
+
+    QColor col_light = QColor::fromHsv (h,s,v);
+
+    const QString style = QString (
+        "border-radius: %1; background-color: "
+        "qlineargradient(spread:pad, x1:0.2, y1:0.2, x2:1, y2:1, stop:0 "
+        "%2, stop:1 %3);"
+      ).arg (width ()/2).arg (col_light.name ()).arg (col.name ());
+
+    return style;
+  }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/led-indicator.h	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,61 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2013-2020 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if ! defined (led_indicator_h)
+#define led_indicator_h 1
+
+#include <QLabel>
+
+namespace octave
+{
+
+  class led_indicator: public QLabel
+  {
+    Q_OBJECT
+
+  public:
+
+    enum led_state
+    {
+      LED_STATE_NO = -1,
+      LED_STATE_INACTIVE,
+      LED_STATE_ACTIVE
+    };
+
+    led_indicator (led_state initial_state = LED_STATE_INACTIVE,
+                   QWidget *parent = 0);
+
+  public slots:
+
+    void set_state (led_state state);
+
+  private:
+
+    QString style_sheet (const QColor& col);
+
+  };
+}
+
+#endif
\ No newline at end of file
--- a/libgui/src/m-editor/file-editor-tab.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/m-editor/file-editor-tab.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -44,6 +44,7 @@
 #include <QMessageBox>
 #include <QPrintDialog>
 #include <QPushButton>
+#include <QScrollBar>
 #include <QStyle>
 #include <QTextBlock>
 #include <QTextCodec>
@@ -430,7 +431,7 @@
     if (ok && ! new_cond.isEmpty ())
       {
         emit interpreter_event
-          ([this, line, new_cond] (interpreter& interp)
+          ([=] (interpreter& interp)
            {
              // INTERPRETER THREAD
 
@@ -687,8 +688,11 @@
 
 
   // Update settings, which are lexer related and have to be updated
-  // when a) the lexer changes or b) the settings have changed.
-  void file_editor_tab::update_lexer_settings (void)
+  // when
+  //    a) the lexer changes,
+  //    b) the settings have changed, or
+  //    c) a package was loaded/unloaded
+  void file_editor_tab::update_lexer_settings (bool update_apis_only)
   {
     QsciLexer *lexer = m_edit_area->lexer ();
 
@@ -759,7 +763,8 @@
                 // if the file is older than a few minutes preventing from
                 // re-preparing data when the user opens several files.
                 QDateTime apis_time = apis_file.lastModified ();
-                if (QDateTime::currentDateTime () > apis_time.addSecs (180))
+                if (update_apis_only
+                    || QDateTime::currentDateTime () > apis_time.addSecs (180))
                   update_apis = true;
               }
 
@@ -791,10 +796,12 @@
 
             // create raw apis info
 
+            m_lexer_apis->clear (); // Clear current contents
+
             if (m_is_octave_file)
               {
                 emit interpreter_event
-                  ([this, octave_functions, octave_builtins] (interpreter& interp)
+                  ([=] (interpreter& interp)
                    {
                      // INTERPRETER THREAD
 
@@ -856,6 +863,9 @@
           }
       }
 
+    if (update_apis_only)
+      return;   // We are done here
+
     lexer->readSettings (*settings);
 
     m_edit_area->setCaretForegroundColor (lexer->color (0));
@@ -1159,7 +1169,7 @@
     bp_info info (m_file_name, line);
 
     emit interpreter_event
-      ([info] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -1248,7 +1258,7 @@
     bp_info info (m_file_name);
 
     emit interpreter_event
-      ([info] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -1356,7 +1366,7 @@
   void file_editor_tab::add_breakpoint_event (const bp_info& info)
   {
     emit interpreter_event
-      ([this, info] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -1834,7 +1844,23 @@
     QApplication::setOverrideCursor (Qt::WaitCursor);
 
     // read the file binary, decoding later
-    const QByteArray text_data = file.readAll ();
+    QByteArray text_data = file.readAll ();
+
+    // remove newline at end of file if we add one again when saving
+    resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
+    gui_settings *settings = rmgr.get_settings ();
+
+    if (settings->value (ed_force_newline).toBool ())
+      {
+        const QByteArray eol_lf = QByteArray (1,0x0a);
+        const QByteArray eol_cr = QByteArray (1,0x0d);
+
+        if (text_data.endsWith (eol_lf))
+          text_data.chop (1);   // remove LF
+
+        if (text_data.endsWith (eol_cr)) // remove CR (altogether CRLF, too)
+          text_data.chop (1);
+      }
 
     // decode
     QTextCodec::ConverterState st;
@@ -2015,7 +2041,7 @@
     // Create and queue the command object.
 
     emit interpreter_event
-      ([this] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -2078,7 +2104,7 @@
     if (ans == QMessageBox::Save)
       {
         emit interpreter_event
-          ([this, file_to_save, base_name, remove_on_success, restore_breakpoints] (interpreter& interp)
+          ([=] (interpreter& interp)
            {
              // INTERPRETER THREAD
 
@@ -2133,7 +2159,7 @@
         QString base_name = file_info.baseName ();
 
         emit interpreter_event
-          ([this, file_to_save, base_name, remove_on_success, restore_breakpoints] (interpreter& interp)
+          ([=] (interpreter& interp)
            {
              // INTERPRETER THREAD
 
@@ -2256,10 +2282,23 @@
     if (! codec)
       return;   // No valid codec
 
+    // Remove trailing white spaces if desired
+    resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
+    gui_settings *settings = rmgr.get_settings ();
+
+    if (settings->value (ed_rm_trailing_spaces).toBool ())
+      m_edit_area->replace_all ("[ \\t]+$", "", true, false, false);
+
+    // Save the file
     out.setCodec (codec);
 
     QApplication::setOverrideCursor (Qt::WaitCursor);
+
     out << m_edit_area->text ();
+    if (settings->value (ed_force_newline).toBool ()
+        && m_edit_area->text ().length ())
+      out << m_edit_area->eol_string ();   // Add newline if desired
+
     out.flush ();
     QApplication::restoreOverrideCursor ();
     file.flush ();
@@ -2476,9 +2515,6 @@
 
   void file_editor_tab::handle_save_file_as_answer (const QString& saveFileName)
   {
-    if (m_save_as_desired_eol != m_edit_area->eolMode ())
-      convert_eol (this,m_save_as_desired_eol);
-
     if (saveFileName == m_file_name)
       {
         save_file (saveFileName);
@@ -2495,13 +2531,6 @@
 
   void file_editor_tab::handle_save_file_as_answer_close (const QString& saveFileName)
   {
-    if (m_save_as_desired_eol != m_edit_area->eolMode ())
-      {
-        m_edit_area->setReadOnly (false);  // was set to read-only in save_file_as
-        convert_eol (this,m_save_as_desired_eol);
-        m_edit_area->setReadOnly (true);   // restore read-only mode
-      }
-
     // saveFileName == m_file_name can not happen, because we only can get here
     // when we close a tab and m_file_name is not a valid filename yet
 
@@ -3152,7 +3181,7 @@
 
                 // remember first visible line and x-offset for restoring the view afterwards
                 int first_line = m_edit_area->firstVisibleLine ();
-                int x_offset = m_edit_area->SendScintilla(QsciScintillaBase::SCI_GETXOFFSET);
+                int x_offset = m_edit_area->SendScintilla (QsciScintillaBase::SCI_GETXOFFSET);
 
                 // search for first occurrence of the detected word
                 bool find_result_available
@@ -3187,7 +3216,7 @@
                 // restore the visible area of the file, the cursor position,
                 // and the selection
                 m_edit_area->setFirstVisibleLine (first_line);
-                m_edit_area->SendScintilla(QsciScintillaBase::SCI_SETXOFFSET, x_offset);
+                m_edit_area->SendScintilla (QsciScintillaBase::SCI_SETXOFFSET, x_offset);
                 m_edit_area->setCursorPosition (line, col);
                 m_edit_area->setSelection (line, col - wlen, line, col);
                 m_edit_area->set_word_selection (word);
--- a/libgui/src/m-editor/file-editor-tab.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/m-editor/file-editor-tab.h	Thu Nov 19 13:08:00 2020 -0800
@@ -204,6 +204,8 @@
 
     void update_breakpoints_handler (const octave_value_list& argout);
 
+    void update_lexer_settings (bool update_apis_only = false);
+
   private slots:
 
     // When user closes message box for decoding problems
@@ -281,7 +283,6 @@
     bool unchanged_or_saved (void);
 
     void update_lexer (void);
-    void update_lexer_settings (void);
 
     void show_dialog (QDialog *dlg, bool modal);
   public:
--- a/libgui/src/m-editor/file-editor.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/m-editor/file-editor.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -77,9 +77,7 @@
 
     setTabsClosable (true);
     setUsesScrollButtons (true);
-#if defined (HAVE_QTABWIDGET_SETMOVABLE)
     setMovable (true);
-#endif
   }
 
   tab_bar * file_editor_tab_widget::get_tab_bar (void) const
@@ -193,6 +191,8 @@
       m_run_action->setShortcut (QKeySequence ());  // prevent ambiguous shortcuts
 
     m_run_action->setToolTip (tr ("Continue"));   // update tool tip
+
+    emit enter_debug_mode_signal ();
   }
 
   void file_editor::handle_exit_debug_mode (void)
@@ -200,6 +200,8 @@
     shortcut_manager& scmgr = m_octave_qobj.get_shortcut_manager ();
     scmgr.set_shortcut (m_run_action, sc_edit_run_run_file);
     m_run_action->setToolTip (tr ("Save File and Run"));  // update tool tip
+
+    emit exit_debug_mode_signal ();
   }
 
   void file_editor::check_actions (void)
@@ -631,7 +633,7 @@
   void file_editor::request_run_file (bool)
   {
     emit interpreter_event
-      ([this] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -2372,6 +2374,13 @@
     connect (f->qsci_edit_area (), SIGNAL (SCN_AUTOCCANCELLED (void)),
              this, SLOT (handle_autoc_cancelled (void)));
 
+    // signals from the qscintilla edit area
+    connect (this, SIGNAL (enter_debug_mode_signal (void)),
+             f->qsci_edit_area (), SLOT (handle_enter_debug_mode (void)));
+
+    connect (this, SIGNAL (exit_debug_mode_signal (void)),
+             f->qsci_edit_area (), SLOT (handle_exit_debug_mode (void)));
+
     // Signals from the file editor_tab
     connect (f, SIGNAL (autoc_closed (void)),
              this, SLOT (reset_focus (void)));
@@ -2410,7 +2419,7 @@
     connect (f, SIGNAL (set_focus_editor_signal (QWidget*)),
              this, SLOT (set_focus (QWidget*)));
 
-    // Signals from the file_editor non-trivial operations
+    // Signals from the file_editor or main-win non-trivial operations
     connect (this, SIGNAL (fetab_settings_changed (const gui_settings *)),
              f, SLOT (notice_settings (const gui_settings *)));
 
@@ -2421,6 +2430,9 @@
                                             bool)),
              f, SLOT (save_file (const QWidget*, const QString&, bool)));
 
+    connect (main_win (), SIGNAL (update_gui_lexer_signal (bool)),
+             f, SLOT (update_lexer_settings (bool)));
+
     // Signals from the file_editor trivial operations
     connect (this, SIGNAL (fetab_recover_from_exit (void)),
              f, SLOT (recover_from_exit (void)));
--- a/libgui/src/m-editor/file-editor.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/m-editor/file-editor.h	Thu Nov 19 13:08:00 2020 -0800
@@ -112,9 +112,6 @@
       SELECTALL_ACTION
     };
 
-    void handle_enter_debug_mode (void);
-    void handle_exit_debug_mode (void);
-
     void check_actions (void);
     void empty_script (bool startup, bool visible);
     void restore_session (gui_settings *settings);
@@ -175,6 +172,9 @@
     void editor_tabs_changed_signal (bool);
     void request_dbcont_signal (void);
 
+    void enter_debug_mode_signal (void);
+    void exit_debug_mode_signal (void);
+
   public slots:
 
     void activate (void);
@@ -183,6 +183,9 @@
     bool check_closing (void);
     void handle_tab_ready_to_close (void);
 
+    void handle_enter_debug_mode (void);
+    void handle_exit_debug_mode (void);
+
     void request_new_file (const QString& commands);
     void request_close_file (bool);
     void request_close_all_files (bool);
--- a/libgui/src/m-editor/find-dialog.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/m-editor/find-dialog.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -398,21 +398,7 @@
         int lbeg, lend, cbeg, cend;
         _edit_area->getSelection (&lbeg,&cbeg,&lend,&cend);
         if (lbeg == lend)
-#if defined (HAVE_QCOMBOBOX_SETCURRENTTEXT)
           _search_line_edit->setCurrentText (_edit_area->selectedText ());
-#else
-          if (_search_line_edit->isEditable ())
-            {
-              _search_line_edit->setEditText (_edit_area->selectedText ());
-            }
-          else
-            {
-              int i = _search_line_edit->findText (_edit_area->selectedText ());
-
-              if (i > -1)
-                _search_line_edit->setCurrentIndex (i);
-            }
-#endif
       }
 
     // set focus to "Find what" and select all text
--- a/libgui/src/m-editor/octave-qscintilla.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/m-editor/octave-qscintilla.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -110,9 +110,10 @@
   }
 
   octave_qscintilla::octave_qscintilla (QWidget *p, base_qobject& oct_qobj)
-    : QsciScintilla (p), m_octave_qobj (oct_qobj), m_word_at_cursor (),
-      m_selection (), m_selection_replacement (), m_selection_line (-1),
-      m_selection_col (-1), m_indicator_id (1)
+    : QsciScintilla (p), m_octave_qobj (oct_qobj), m_debug_mode (false),
+      m_word_at_cursor (), m_selection (), m_selection_replacement (),
+      m_selection_line (-1), m_selection_col (-1), m_indicator_id (1),
+      m_tooltip_font (QToolTip::font ())
   {
     connect (this, SIGNAL (textChanged (void)),
              this, SLOT (text_changed (void)));
@@ -381,6 +382,22 @@
     markerDeleteAll (marker::selection);
   }
 
+  QString octave_qscintilla::eol_string (void)
+  {
+    switch (eolMode ())
+      {
+      case QsciScintilla::EolWindows:
+        return ("\r\n");
+      case QsciScintilla::EolMac:
+        return ("\r");
+      case QsciScintilla::EolUnix:
+        return ("\n");
+      }
+
+    // Last resort, if the above goes wrong (should never happen)
+    return ("\r\n");
+  }
+
   // Function returning the true cursor position where the tab length
   // is taken into account.
   void octave_qscintilla::get_current_position (int *pos, int *line, int *col)
@@ -860,7 +877,7 @@
 
     // Add commands to the history
     emit interpreter_event
-      ([tmp_hist] (interpreter& interp)
+      ([=] (interpreter& interp)
         {
           // INTERPRETER THREAD
 
@@ -877,7 +894,7 @@
 
     // Let the interpreter execute the tmp file
     emit interpreter_event
-      ([this, tmp_file, tmp_hist, show_dbg_file] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -957,8 +974,8 @@
                                                 dbg, auto_repeat);
 
              // New exception with updated message and stack
-             octave::execution_exception ee (e.err_type (),e.identifier (),
-                                             new_msg.toStdString (), stack);
+             execution_exception ee (e.err_type (),e.identifier (),
+                                     new_msg.toStdString (), stack);
 
              // Throw
              throw (ee);
@@ -1085,6 +1102,75 @@
     QToolTip::showText (global_pos, msg);
   }
 
+  void octave_qscintilla::replace_all (const QString& o_str, const QString& n_str,
+                                       bool re, bool cs, bool wo)
+  {
+    // get the resulting cursor position
+    int pos, line, col, nline, ncol;
+    get_current_position (&pos, &line, &col);
+
+    // remember first visible line for restoring the view afterwards
+    int first_line = firstVisibleLine ();
+
+    // search for first occurrence of the detected word
+    bool find_result_available = findFirst (o_str, re, cs, wo,
+                                            false, true, 0, 0);
+    // replace and find more occurrences in a loop
+    beginUndoAction ();
+    while (find_result_available)
+      {
+        // findNext doesn't work properly if the length of the replacement
+        // text is different from the original
+        replace (n_str);
+        get_current_position (&pos, &nline, &ncol);
+
+        find_result_available = findFirst (o_str, re, cs, wo,
+                                           false, true, nline, ncol);
+      }
+    endUndoAction ();
+
+      // restore the visible area
+      setFirstVisibleLine (first_line);
+
+      // fix cursor column if outside of new line length
+      int eol_len = eol_string ().length ();
+      if (line == lines () - 1)
+        eol_len = 0;
+      const int col_max = text (line).length () - eol_len;
+      if (col_max < col)
+        col = col_max;
+
+      setCursorPosition (line, col);
+  }
+
+  bool octave_qscintilla::event (QEvent *e)
+  {
+    if (m_debug_mode && e->type() == QEvent::ToolTip)
+      {
+        QHelpEvent *help_e = static_cast<QHelpEvent *>(e);
+        QString variable = wordAtPoint (help_e->pos());
+        QStringList symbol_names
+            = m_octave_qobj.get_workspace_model ()->get_symbol_names ();
+        int symbol_idx = symbol_names.indexOf (variable);
+        if (symbol_idx > -1)
+          {
+            QStringList symbol_values
+                = m_octave_qobj.get_workspace_model ()->get_symbol_values ();
+            QToolTip::showText (help_e->globalPos(), variable
+                                + " = " + symbol_values.at (symbol_idx));
+          }
+        else
+          {
+            QToolTip::hideText();
+            e->ignore();
+          }
+
+        return true;
+      }
+
+    return QsciScintilla::event(e);
+  }
+
   void octave_qscintilla::keyPressEvent (QKeyEvent *key_event)
   {
     if (m_selection.isEmpty ())
@@ -1096,59 +1182,8 @@
 
         if (key == Qt::Key_Return && modifiers == Qt::ShiftModifier)
           {
-            // get the resulting cursor position
-            // (required if click was beyond a line ending)
-            int pos, line, col;
-            get_current_position (&pos, &line, &col);
-
-            // remember first visible line for restoring the view afterwards
-            int first_line = firstVisibleLine ();
-
-            // search for first occurrence of the detected word
-            bool find_result_available
-              = findFirst (m_selection,
-                           false,   // no regexp
-                           true,    // case sensitive
-                           true,    // whole words only
-                           false,   // do not wrap
-                           true,    // forward
-                           0, 0,    // from the beginning
-                           false
-#if defined (HAVE_QSCI_VERSION_2_6_0)
-                           , true
-#endif
-                          );
-
-            while (find_result_available)
-              {
-                replace (m_selection_replacement);
-
-                // FIXME: is this the right thing to do?  findNext doesn't
-                // work properly if the length of the replacement text is
-                // different from the original.
-
-                int new_line, new_col;
-                get_current_position (&pos, &new_line, &new_col);
-
-                find_result_available
-                  = findFirst (m_selection,
-                               false,   // no regexp
-                               true,    // case sensitive
-                               true,    // whole words only
-                               false,   // do not wrap
-                               true,    // forward
-                               new_line, new_col,    // from new pos
-                               false
-#if defined (HAVE_QSCI_VERSION_2_6_0)
-                               , true
-#endif
-                              );
-              }
-
-            // restore the visible area of the file, the cursor position,
-            // and the selection
-            setFirstVisibleLine (first_line);
-            setCursorPosition (line, col);
+            replace_all (m_selection, m_selection_replacement,
+                         false, true, true);
 
             // Clear the selection.
             set_word_selection ();
@@ -1291,6 +1326,24 @@
         e->ignore();
       }
   }
+
+  void octave_qscintilla::handle_enter_debug_mode (void)
+  {
+    // Set tool tip font to the lexers default font
+    m_tooltip_font = QToolTip::font ();   // Save current font
+    QToolTip::setFont (lexer ()->defaultFont ());
+
+    m_debug_mode = true;
+  }
+
+  void octave_qscintilla::handle_exit_debug_mode (void)
+  {
+    m_debug_mode = false;
+
+    // Reset tool tip font
+    QToolTip::setFont (m_tooltip_font);
+  }
+
 }
 
 #endif
--- a/libgui/src/m-editor/octave-qscintilla.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/m-editor/octave-qscintilla.h	Thu Nov 19 13:08:00 2020 -0800
@@ -65,6 +65,7 @@
     void get_global_textcursor_pos (QPoint *global_pos, QPoint *local_pos);
     bool get_actual_word (void);
     void clear_selection_markers (void);
+    QString eol_string (void);
     void get_current_position (int *pos, int *line, int *col);
     QStringList comment_string (bool comment = true);
     int get_style (int pos = -1);
@@ -80,6 +81,9 @@
 
     void set_selection_marker_color (const QColor& c);
 
+    void replace_all (const QString& o_str, const QString& n_str,
+                      bool re, bool cs, bool wo);
+
   signals:
 
     void execute_command_in_terminal_signal (const QString&);
@@ -95,6 +99,11 @@
                                        QTemporaryFile*, bool, bool);
     void focus_console_after_command_signal (void);
 
+  public slots:
+
+    void handle_enter_debug_mode (void);
+    void handle_exit_debug_mode (void);
+
   private slots:
 
     void ctx_menu_run_finished (bool, int, QTemporaryFile*, QTemporaryFile*,
@@ -119,6 +128,8 @@
 
     void show_replace_action_tooltip (void);
 
+    bool event (QEvent *e);
+
     void keyPressEvent (QKeyEvent *e);
 
     void dragEnterEvent (QDragEnterEvent *e);
@@ -130,6 +141,8 @@
 
     base_qobject& m_octave_qobj;
 
+    bool m_debug_mode;
+
     QString m_word_at_cursor;
 
     QString m_selection;
@@ -137,6 +150,8 @@
     int m_selection_line;
     int m_selection_col;
     int m_indicator_id;
+
+    QFont m_tooltip_font;
   };
 }
 
--- a/libgui/src/main-window.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/main-window.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -164,10 +164,16 @@
     shortcut_manager& scmgr = m_octave_qobj.get_shortcut_manager ();
     scmgr.init_data ();
 
+    m_workspace_model = m_octave_qobj.get_workspace_model ();
+
     construct_central_widget ();
 
-    m_workspace_model = new workspace_model (m_octave_qobj);
     m_status_bar = new QStatusBar ();
+    m_profiler_status_indicator = new led_indicator ();
+    QLabel *text = new QLabel (tr ("Profiler"));
+    m_status_bar->addPermanentWidget (text);
+    m_status_bar->addPermanentWidget (m_profiler_status_indicator);
+
     m_command_window = new terminal_dock_widget (this, m_octave_qobj);
     m_history_window = new history_dock_widget (this, m_octave_qobj);
     m_file_browser_window = new files_dock_widget (this, m_octave_qobj);
@@ -251,7 +257,6 @@
     delete m_file_browser_window;
     delete m_history_window;
     delete m_status_bar;
-    delete m_workspace_model;
     delete m_variable_editor_window;
 
     delete m_find_files_dlg;
@@ -405,7 +410,7 @@
     if (! file.isEmpty ())
       {
         emit interpreter_event
-          ([file] (interpreter& interp)
+          ([=] (interpreter& interp)
            {
              // INTERPRETER THREAD
 
@@ -432,7 +437,7 @@
     if (! file.isEmpty ())
       {
         emit interpreter_event
-          ([file] (interpreter& interp)
+          ([=] (interpreter& interp)
            {
              // INTERPRETER THREAD
 
@@ -454,7 +459,7 @@
         std::string file = file_arg.toStdString ();
 
         emit interpreter_event
-          ([file] (interpreter& interp)
+          ([=] (interpreter& interp)
            {
              // INTERPRETER THREAD
 
@@ -532,7 +537,7 @@
     std::string new_name = new_name_arg.toStdString ();
 
     emit interpreter_event
-      ([old_name, new_name] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -558,7 +563,7 @@
                                  bool rm, bool subdirs)
   {
     emit interpreter_event
-      ([dir_list, rm, subdirs, this] (interpreter& interp)
+      ([=] (interpreter& interp)
       {
         // INTERPRETER THREAD
 
@@ -769,9 +774,7 @@
         QTextBrowser *browser
 
           = m_community_news_window->findChild<QTextBrowser *>("OctaveNews"
-#if defined (QOBJECT_FINDCHILDREN_ACCEPTS_FINDCHILDOPTIONS)
                                                                , Qt::FindDirectChildrenOnly
-#endif
                                                               );
         if (browser)
           browser->setHtml (news);
@@ -1025,7 +1028,7 @@
     if (fileInfo.exists () && fileInfo.isDir ())
       {
         emit interpreter_event
-          ([xdir] (interpreter& interp)
+          ([=] (interpreter& interp)
            {
              // INTERPRETER THREAD
 
@@ -1060,7 +1063,7 @@
   void main_window::execute_command_in_terminal (const QString& command)
   {
     emit interpreter_event
-      ([command] (void)
+      ([=] (void)
        {
          // INTERPRETER THREAD
 
@@ -1079,7 +1082,7 @@
   void main_window::run_file_in_terminal (const QFileInfo& info)
   {
     emit interpreter_event
-      ([info] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -1141,10 +1144,6 @@
     m_debug_step_over->setEnabled (true);
     m_debug_step_out->setEnabled (true);
     m_debug_quit->setEnabled (true);
-
-#if defined (HAVE_QSCINTILLA)
-    m_editor_window->handle_enter_debug_mode ();
-#endif
   }
 
   void main_window::handle_exit_debugger (void)
@@ -1156,16 +1155,12 @@
     m_debug_step_over->setEnabled (m_editor_has_tabs);
     m_debug_step_out->setEnabled (false);
     m_debug_quit->setEnabled (false);
-
-#if defined (HAVE_QSCINTILLA)
-    m_editor_window->handle_exit_debug_mode ();
-#endif
   }
 
   void main_window::debug_continue (void)
   {
     emit interpreter_event
-      ([this] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -1179,7 +1174,7 @@
   void main_window::debug_step_into (void)
   {
     emit interpreter_event
-      ([this] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -1197,7 +1192,7 @@
         // We are in debug mode, just call dbstep.
 
         emit interpreter_event
-          ([this] (interpreter& interp)
+          ([=] (interpreter& interp)
            {
              // INTERPRETER THREAD
 
@@ -1218,7 +1213,7 @@
   void main_window::debug_step_out (void)
   {
     emit interpreter_event
-      ([this] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -1329,7 +1324,7 @@
                                                int line)
   {
     emit interpreter_event
-      ([this, fname, ffile, curr_dir, line] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -1653,6 +1648,21 @@
     emit unregister_doc_signal (file);
   }
 
+  void main_window::handle_gui_status_update (const QString& feature,
+                                              const QString& status)
+  {
+    // Put actions that are required for updating a gui features here
+
+    // Profiler on/off
+    if (! feature.compare ("profiler"))
+      {
+        if (! status.compare ("on", Qt::CaseInsensitive))
+          handle_profiler_status_update (true);
+        else if (! status.compare ("off", Qt::CaseInsensitive))
+          handle_profiler_status_update (false);
+      }
+  }
+
   void main_window::handle_octave_ready (void)
   {
     // actions after the startup files are executed
@@ -1832,7 +1842,7 @@
   void main_window::set_screen_size (int ht, int wd)
   {
     emit interpreter_event
-      ([ht, wd] (void)
+      ([=] (void)
        {
          // INTERPRETER THREAD
 
@@ -1931,6 +1941,60 @@
        });
   }
 
+  void main_window::profiler_session (void)
+  {
+    emit interpreter_event
+      ([=] (interpreter& interp)
+        {
+          // INTERPRETER THREAD
+
+          Ffeval (interp, ovl ("profile","on"));
+        });
+  }
+
+  void main_window::profiler_session_resume (void)
+  {
+    emit interpreter_event
+      ([=] (interpreter& interp)
+        {
+          // INTERPRETER THREAD
+
+          Ffeval (interp, ovl ("profile","resume"));
+        });
+  }
+
+  void main_window::profiler_stop (void)
+  {
+    emit interpreter_event
+      ([=] (interpreter& interp)
+        {
+          // INTERPRETER THREAD
+
+          Ffeval (interp, ovl ("profile","off"));
+        });
+  }
+
+  void main_window::handle_profiler_status_update (bool active)
+  {
+    m_profiler_start->setEnabled (! active);
+    m_profiler_resume->setEnabled (! active);
+    m_profiler_stop->setEnabled (active);
+
+    led_indicator::led_state state = led_indicator::LED_STATE_INACTIVE;
+    if (active)
+      state = led_indicator::LED_STATE_ACTIVE;
+    m_profiler_status_indicator->set_state (state);
+  }
+
+  void main_window::profiler_show (void)
+  {
+    // Do not use a separate interpreter event as in the other
+    // profiler slots since the output of the command "profshow"
+    // would obscure the prompt and we do not need to emimt a signal
+    // for action that is required in the gui after rhe command
+    execute_command_in_terminal ("profshow");
+  }
+
   void main_window::closeEvent (QCloseEvent *e)
   {
     if (confirm_shutdown ())
@@ -2150,6 +2214,13 @@
     // Signals for removing/renaming files/dirs in the terminal window
     connect (qt_link, SIGNAL (file_renamed_signal (bool)),
              m_editor_window, SLOT (handle_file_renamed (bool)));
+
+    // Signals for entering/exiting debug mode
+    connect (qt_link, SIGNAL (enter_debugger_signal (void)),
+             m_editor_window, SLOT (handle_enter_debug_mode (void)));
+
+    connect (qt_link, SIGNAL (exit_debugger_signal (void)),
+             m_editor_window, SLOT (handle_exit_debug_mode (void)));
 #endif
 
     // Signals for removing/renaming files/dirs in the temrinal window
@@ -2256,6 +2327,14 @@
     connect (qt_link,
              SIGNAL (unregister_doc_signal (const QString &)),
              this, SLOT (handle_unregister_doc (const QString &)));
+
+    connect (qt_link, SIGNAL (gui_status_update_signal (const QString &,
+                                                        const QString &)),
+             this, SLOT (handle_gui_status_update (const QString &,
+                                                   const QString &)));
+
+    connect (qt_link, SIGNAL (update_gui_lexer_signal (bool)),
+             this, SIGNAL (update_gui_lexer_signal (bool)));
   }
 
   QAction* main_window::add_action (QMenu *menu, const QIcon& icon,
@@ -2302,6 +2381,8 @@
 
     construct_debug_menu (menu_bar);
 
+    construct_tools_menu (menu_bar);
+
     construct_window_menu (menu_bar);
 
     construct_help_menu (menu_bar);
@@ -2539,6 +2620,24 @@
                                    SLOT (debug_quit (void)));
   }
 
+  void main_window::construct_tools_menu (QMenuBar *p)
+  {
+    QMenu *tools_menu = m_add_menu (p, tr ("&Tools"));
+
+    m_profiler_start = add_action (tools_menu, QIcon (),
+          tr ("Start &Profiler Session"), SLOT (profiler_session ()));
+
+    m_profiler_resume = add_action (tools_menu, QIcon (),
+          tr ("&Resume Profiler Session"), SLOT (profiler_session_resume ()));
+
+    m_profiler_stop = add_action (tools_menu, QIcon (),
+          tr ("&Stop Profiler"), SLOT (profiler_stop ()));
+    m_profiler_stop->setEnabled (false);
+
+    m_profiler_show = add_action (tools_menu, QIcon (),
+          tr ("&Show Profile Data"), SLOT (profiler_show ()));
+  }
+
   void main_window::editor_tabs_changed (bool have_tabs)
   {
     // Set state of actions which depend on the existence of editor tabs
@@ -2787,6 +2886,12 @@
     scmgr.set_shortcut (m_debug_continue, sc_main_debug_continue);
     scmgr.set_shortcut (m_debug_quit, sc_main_debug_quit);
 
+    // tools menu
+    scmgr.set_shortcut (m_profiler_start, sc_main_tools_start_profiler);
+    scmgr.set_shortcut (m_profiler_resume, sc_main_tools_resume_profiler);
+    scmgr.set_shortcut (m_profiler_stop, sc_main_tools_start_profiler); // same, toggling
+    scmgr.set_shortcut (m_profiler_show, sc_main_tools_show_profiler);
+
     // window menu
     scmgr.set_shortcut (m_show_command_window_action, sc_main_window_show_command);
     scmgr.set_shortcut (m_show_history_action, sc_main_window_show_history);
@@ -2842,7 +2947,7 @@
       mfile_encoding = "SYSTEM";
 
     emit interpreter_event
-      ([mfile_encoding] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
--- a/libgui/src/main-window.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/main-window.h	Thu Nov 19 13:08:00 2020 -0800
@@ -53,6 +53,7 @@
 #include "find-files-dialog.h"
 #include "history-dock-widget.h"
 #include "interpreter-qobject.h"
+#include "led-indicator.h"
 #include "octave-dock-widget.h"
 #include "octave-qobject.h"
 #include "qt-interpreter-events.h"
@@ -106,6 +107,7 @@
     void show_doc_signal (const QString&);
     void register_doc_signal (const QString&);
     void unregister_doc_signal (const QString&);
+    void update_gui_lexer_signal (bool);
 
     void insert_debugger_pointer_signal (const QString& file, int line);
     void delete_debugger_pointer_signal (const QString& file, int line);
@@ -205,11 +207,19 @@
     void pasteClipboard (void);
     void selectAll (void);
 
+    void handle_gui_status_update (const QString& feature, const QString& status);
+
     void focus_console_after_command (void);
     void handle_show_doc (const QString& file);
     void handle_register_doc (const QString& file);
     void handle_unregister_doc (const QString& file);
 
+    void profiler_session (void);
+    void profiler_session_resume (void);
+    void profiler_stop (void);
+    void handle_profiler_status_update (bool);
+    void profiler_show (void);
+
     void handle_octave_ready ();
 
     void handle_set_path_dialog_request (void);
@@ -282,6 +292,7 @@
     void construct_debug_menu (QMenuBar *p);
     QAction * construct_window_menu_item (QMenu *p, const QString& item,
                                           bool checkable, QWidget*);
+    void construct_tools_menu (QMenuBar *p);
     void construct_window_menu (QMenuBar *p);
     void construct_help_menu (QMenuBar *p);
     void construct_documentation_menu (QMenu *p);
@@ -309,6 +320,7 @@
     //! Toolbar.
 
     QStatusBar *m_status_bar;
+    led_indicator *m_profiler_status_indicator;
 
     //! Dock widgets.
     //!@{
@@ -359,6 +371,11 @@
     QAction *m_find_files_action;
     QAction *m_select_all_action;
 
+    QAction *m_profiler_start;
+    QAction *m_profiler_resume;
+    QAction *m_profiler_stop;
+    QAction *m_profiler_show;
+
     QAction *m_show_command_window_action;
     QAction *m_show_history_action;
     QAction *m_show_workspace_action;
--- a/libgui/src/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -140,6 +140,7 @@
   %reldir%/moc-gui-settings.cc \
   %reldir%/moc-history-dock-widget.cc \
   %reldir%/moc-interpreter-qobject.cc \
+  %reldir%/moc-led-indicator.cc \
   %reldir%/moc-main-window.cc \
   %reldir%/moc-news-reader.cc \
   %reldir%/moc-octave-qobject.cc \
@@ -210,6 +211,7 @@
   %reldir%/graphics-init.h \
   %reldir%/history-dock-widget.h \
   %reldir%/interpreter-qobject.h \
+  %reldir%/led-indicator.h \
   %reldir%/m-editor/file-editor-interface.h \
   %reldir%/m-editor/file-editor-tab.h \
   %reldir%/m-editor/file-editor.h \
@@ -251,6 +253,7 @@
   %reldir%/gui-settings.cc \
   %reldir%/history-dock-widget.cc \
   %reldir%/interpreter-qobject.cc \
+  %reldir%/led-indicator.cc \
   %reldir%/m-editor/file-editor-tab.cc \
   %reldir%/m-editor/file-editor.cc \
   %reldir%/m-editor/find-dialog.cc \
--- a/libgui/src/octave-qobject.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/octave-qobject.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -119,11 +119,7 @@
   // Disable all Qt messages by default.
 
   static void
-#if defined (QTMESSAGEHANDLER_ACCEPTS_QMESSAGELOGCONTEXT)
   message_handler (QtMsgType, const QMessageLogContext &, const QString &)
-#else
-  message_handler (QtMsgType, const char *)
-#endif
   { }
 
   //! Reimplement QApplication::notify.  Octave's own exceptions are
@@ -138,7 +134,7 @@
     catch (execution_exception& ee)
       {
         emit interpreter_event
-          ([ee] (void)
+          ([=] (void)
            {
              // INTERPRETER THREAD
 
@@ -164,6 +160,7 @@
       m_argv (m_app_context.sys_argv ()),
       m_qapplication (new octave_qapplication (m_argc, m_argv)),
       m_resource_manager (), m_shortcut_manager (*this),
+      m_workspace_model (new workspace_model (*this)),
       m_qt_tr (new QTranslator ()), m_gui_tr (new QTranslator ()),
       m_qsci_tr (new QTranslator ()), m_translators_installed (false),
       m_qt_interpreter_events (new qt_interpreter_events (*this)),
@@ -177,11 +174,7 @@
 
     if (show_gui_msgs.empty ())
       {
-#if defined (HAVE_QINSTALLMESSAGEHANDLER)
         qInstallMessageHandler (message_handler);
-#else
-        qInstallMsgHandler (message_handler);
-#endif
       }
 
     // Set the codec for all strings (before wizard or any GUI object)
@@ -189,10 +182,6 @@
     QTextCodec::setCodecForLocale (QTextCodec::codecForName ("UTF-8"));
 #endif
 
-#if defined (HAVE_QT4)
-    QTextCodec::setCodecForCStrings (QTextCodec::codecForName ("UTF-8"));
-#endif
-
     // Initialize global Qt application metadata.
 
     QCoreApplication::setApplicationName ("GNU Octave");
@@ -202,7 +191,6 @@
 
     qRegisterMetaType<octave_value_list> ("octave_value_list");
 
-
 // Bug #55940 (Disable App Nap on Mac)
 #if defined (Q_OS_MAC)
     // Mac App Nap feature causes pause() and sleep() to misbehave.
@@ -250,6 +238,7 @@
     delete m_gui_tr;
     delete m_qt_tr;
     delete m_qapplication;
+    delete m_workspace_model;
 
     string_vector::delete_c_str_vec (m_argv);
   }
--- a/libgui/src/octave-qobject.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/octave-qobject.h	Thu Nov 19 13:08:00 2020 -0800
@@ -37,6 +37,7 @@
 #include "interpreter-qobject.h"
 #include "resource-manager.h"
 #include "shortcut-manager.h"
+#include "workspace-model.h"
 
 namespace octave
 {
@@ -48,7 +49,7 @@
   //! reimplement QApplication::notify.  The octave_qapplication object
   //! should behave identically to a QApplication object except that it
   //! overrides the notify method so we can handle forward Octave
-  //! octave::execution_exception exceptions from the GUI thread to the
+  //! execution_exception exceptions from the GUI thread to the
   //! interpreter thread.
 
   class octave_qapplication : public QApplication
@@ -108,6 +109,11 @@
       return m_shortcut_manager;
     }
 
+    workspace_model * get_workspace_model (void)
+    {
+      return m_workspace_model;
+    }
+
     std::shared_ptr<qt_interpreter_events> get_qt_interpreter_events (void)
     {
       return m_qt_interpreter_events;
@@ -159,6 +165,8 @@
 
     shortcut_manager m_shortcut_manager;
 
+    workspace_model *m_workspace_model;
+
     QTranslator *m_qt_tr;
     QTranslator *m_gui_tr;
     QTranslator *m_qsci_tr;
--- a/libgui/src/qt-application.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/qt-application.h	Thu Nov 19 13:08:00 2020 -0800
@@ -35,7 +35,7 @@
   // must be included only in the corresponding .cc file.
 
   //! This class inherits from the pure-virtual base class
-  //! octave::application and provides an implementation of the
+  //! application and provides an implementation of the
   //! application::execute method that starts an interface to Octave
   //! that is based on Qt.  It may start a command-line interface that
   //! allows Qt graphics to be used or it may start an interface that
--- a/libgui/src/qt-interpreter-events.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/qt-interpreter-events.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -447,6 +447,18 @@
     emit unregister_doc_signal (QString::fromStdString (file));
   }
 
+  void qt_interpreter_events::gui_status_update (const std::string& feature,
+                                                 const std::string& status)
+  {
+    emit gui_status_update_signal (QString::fromStdString (feature),
+                                   QString::fromStdString (status));
+  }
+
+  void qt_interpreter_events::update_gui_lexer (void)
+  {
+    emit update_gui_lexer_signal (true);
+  }
+
   void qt_interpreter_events::directory_changed (const std::string& dir)
   {
     emit directory_changed_signal (QString::fromStdString (dir));
--- a/libgui/src/qt-interpreter-events.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/qt-interpreter-events.h	Thu Nov 19 13:08:00 2020 -0800
@@ -141,6 +141,10 @@
 
     void unregister_doc (const std::string& file);
 
+    void gui_status_update (const std::string& feature, const std::string& status);
+
+    void update_gui_lexer (void);
+
     void directory_changed (const std::string& dir);
 
     void file_remove (const std::string& old_name,
@@ -240,6 +244,10 @@
 
     void unregister_doc_signal (const QString& file);
 
+    void gui_status_update_signal (const QString& feature, const QString& status);
+
+    void update_gui_lexer_signal (bool update_apis_only);
+
     void edit_variable_signal (const QString& name, const octave_value& val);
 
     void refresh_variable_editor_signal (void);
--- a/libgui/src/resource-manager.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/resource-manager.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -28,6 +28,7 @@
 #endif
 
 #include <algorithm>
+#include <array>
 #include <string>
 
 #include <QDir>
@@ -221,30 +222,30 @@
     QString default_family;
 
 #if defined (Q_OS_MAC)
-  // Use hard coded default on macOS, since selection of fixed width
-  // default font is unreliable (see bug #59128).
+    // Use hard coded default on macOS, since selection of fixed width
+    // default font is unreliable (see bug #59128).
 
-  // Get all available fixed width fonts via a font combobox
-  QFontComboBox font_combo_box;
-  font_combo_box.setFontFilters (QFontComboBox::MonospacedFonts);
-  QStringList fonts;
+    // Get all available fixed width fonts via a font combobox
+    QFontComboBox font_combo_box;
+    font_combo_box.setFontFilters (QFontComboBox::MonospacedFonts);
+    QStringList fonts;
 
-  for (int index = 0; index < font_combo_box.count(); index++)
-    fonts << font_combo_box.itemText(index);
+    for (int index = 0; index < font_combo_box.count(); index++)
+      fonts << font_combo_box.itemText(index);
 
-  // Test for macOS default fixed width font
-  if (fonts.contains (global_mono_font.def.toString ()))
-    default_family = global_mono_font.def.toString ();
+    // Test for macOS default fixed width font
+    if (fonts.contains (global_mono_font.def.toString ()))
+      default_family = global_mono_font.def.toString ();
 #endif
 
-  // If default font is still empty (on all other platforms or
-  // if macOS default font is not available): use QFontDatabase
-  if (default_family.isEmpty ())
-    {
-      // Get the system's default monospaced font
-      QFont fixed_font = QFontDatabase::systemFont (QFontDatabase::FixedFont);
-      default_family = fixed_font.defaultFamily ();
-    }
+    // If default font is still empty (on all other platforms or
+    // if macOS default font is not available): use QFontDatabase
+    if (default_family.isEmpty ())
+      {
+        // Get the system's default monospaced font
+        QFont fixed_font = QFontDatabase::systemFont (QFontDatabase::FixedFont);
+        default_family = fixed_font.defaultFamily ();
+      }
 
     // Test env variable which has preference
     std::string env_default_family = sys::env::getenv ("OCTAVE_DEFAULT_FONT");
@@ -363,39 +364,108 @@
 
   void resource_manager::update_network_settings (void)
   {
-    if (m_settings)
+    if (! m_settings)
+      return;
+
+    QNetworkProxy proxy;
+
+    // Assume no proxy and empty proxy data
+    QNetworkProxy::ProxyType proxy_type = QNetworkProxy::NoProxy;
+    QString scheme;
+    QString host;
+    int port = 0;
+    QString user;
+    QString pass;
+    QUrl proxy_url = QUrl ();
+
+    if (m_settings->value (global_use_proxy.key, global_use_proxy.def).toBool ())
       {
-        QNetworkProxy::ProxyType proxyType = QNetworkProxy::NoProxy;
+        // Use a proxy, collect all required information
+        QString proxy_type_string
+            = m_settings->value (global_proxy_type.key, global_proxy_type.def).toString ();
 
-        if (m_settings->value (global_use_proxy.key, global_use_proxy.def).toBool ())
+        // The proxy type for the Qt proxy settings
+        if (proxy_type_string == "Socks5Proxy")
+          proxy_type = QNetworkProxy::Socks5Proxy;
+        else if (proxy_type_string == "HttpProxy")
+          proxy_type = QNetworkProxy::HttpProxy;
+
+        // The proxy data from the settings
+        if (proxy_type_string == "HttpProxy"
+            || proxy_type_string == "Socks5Proxy")
           {
-            QString proxyTypeString
-              = m_settings->value (global_proxy_type.key, global_proxy_type.def).toString ();
+            host = m_settings->value (global_proxy_host.key,
+                                      global_proxy_host.def).toString ();
+            port = m_settings->value (global_proxy_port.key,
+                                      global_proxy_port.def).toInt ();
+            user = m_settings->value (global_proxy_user.key,
+                                      global_proxy_user.def).toString ();
+            pass = m_settings->value (global_proxy_pass.key,
+                                      global_proxy_pass.def).toString ();
+            if (proxy_type_string == "HttpProxy")
+              scheme = "http";
+            else if (proxy_type_string == "Socks5Proxy")
+              scheme = "socks5";
 
-            if (proxyTypeString == "Socks5Proxy")
-              proxyType = QNetworkProxy::Socks5Proxy;
-            else if (proxyTypeString == "HttpProxy")
-              proxyType = QNetworkProxy::HttpProxy;
+            QUrl env_var_url = QUrl ();
+            proxy_url.setScheme (scheme);
+            proxy_url.setHost (host);
+            proxy_url.setPort (port);
+            if (! user.isEmpty ())
+              proxy_url.setUserName (user);
+            if (! pass.isEmpty ())
+              proxy_url.setPassword (pass);
           }
 
-        QNetworkProxy proxy;
+        // The proxy data from environment variables
+        if (proxy_type_string == global_proxy_all_types.at (2))
+          {
+            const std::array<std::string, 6> env_vars =
+                { "ALL_PROXY", "all_proxy",
+                  "HTTP_PROXY", "http_proxy",
+                  "HTTPS_PROXY", "https_proxy" };
+
+            unsigned int count = 0;
+            while (! proxy_url.isValid () && count < env_vars.size ())
+              {
+                proxy_url = QUrl (QString::fromStdString
+                                    (sys::env::getenv (env_vars[count])));
+                count++;
+              }
+
+            if (proxy_url.isValid ())
+              {
+                // Found an entry, get the data from the string
+                scheme = proxy_url.scheme ();
 
-        proxy.setType (proxyType);
-        proxy.setHostName (m_settings->value (global_proxy_host.key,
-                                              global_proxy_host.def).toString ());
-        proxy.setPort (m_settings->value (global_proxy_port.key,
-                                          global_proxy_port.def).toInt ());
-        proxy.setUser (m_settings->value (global_proxy_user.key,
-                                          global_proxy_user.def).toString ());
-        proxy.setPassword (m_settings->value (global_proxy_pass.key,
-                                              global_proxy_pass.def).toString ());
+                if (scheme.contains ("socks", Qt::CaseInsensitive))
+                  proxy_type = QNetworkProxy::Socks5Proxy;
+                else
+                  proxy_type = QNetworkProxy::HttpProxy;
+
+                host = proxy_url.host ();
+                port = proxy_url.port ();
+                user = proxy_url.userName ();
+                pass = proxy_url.password ();
+              }
+          }
+      }
 
-        QNetworkProxy::setApplicationProxy (proxy);
-      }
-    else
-      {
-        // FIXME: Is this an error?  If so, what should we do?
-      }
+    // Set proxy for Qt framework
+    proxy.setType (proxy_type);
+    proxy.setHostName (host);
+    proxy.setPort (port);
+    proxy.setUser (user);
+    proxy.setPassword (pass);
+
+    QNetworkProxy::setApplicationProxy (proxy);
+
+    // Set proxy for curl library if not based on environment variables
+    std::string proxy_url_str = proxy_url.toString().toStdString ();
+    sys::env::putenv ("http_proxy", proxy_url_str);
+    sys::env::putenv ("HTTP_PROXY", proxy_url_str);
+    sys::env::putenv ("https_proxy", proxy_url_str);
+    sys::env::putenv ("HTTPS_PROXY", proxy_url_str);
   }
 
   QIcon resource_manager::icon (const QString& icon_name, bool fallback)
--- a/libgui/src/set-path-model.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/set-path-model.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -77,7 +77,7 @@
     std::string path_str = to_string ();
 
     emit interpreter_event
-      ([path_str] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -283,7 +283,7 @@
   void set_path_model::path_to_model (void)
   {
     emit interpreter_event
-      ([this] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
--- a/libgui/src/settings-dialog.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/settings-dialog.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -350,6 +350,8 @@
     editor_restoreSession->setChecked (settings->value (ed_restore_session).toBool ());
     editor_create_new_file->setChecked (settings->value (ed_create_new_file).toBool ());
     editor_reload_changed_files->setChecked (settings->value (ed_always_reload_changed_files).toBool ());
+    editor_force_newline->setChecked (settings->value (ed_force_newline).toBool ());
+    editor_remove_trailing_spaces->setChecked (settings->value (ed_rm_trailing_spaces).toBool ());
     editor_hiding_closes_files->setChecked (settings->value (ed_hiding_closes_files).toBool ());
     editor_show_dbg_file->setChecked (settings->value (ed_show_dbg_file).toBool ());
 
@@ -395,21 +397,33 @@
     le_file_browser_extensions->setText (settings->value (fb_txt_file_ext).toString ());
 
     checkbox_allow_web_connect->setChecked (settings->value (nr_allow_connection).toBool ());
-    useProxyServer->setChecked (
-        settings->value (global_use_proxy.key, global_use_proxy.def).toBool ());
-    proxyHostName->setText (settings->value (global_proxy_host.key, global_proxy_host.def).toString ());
 
-    int currentIndex = 0;
-    QString proxyTypeString = settings->value (global_proxy_type.key, global_proxy_type.def).toString ();
-    while ((currentIndex < proxyType->count ())
-           && (proxyType->currentText () != proxyTypeString))
+    // Proxy
+    bool use_proxy = settings->value (global_use_proxy.key, global_use_proxy.def).toBool ();
+    use_proxy_server->setChecked (use_proxy);
+    // Fill combo box and activate current one
+    QString proxy_type_string = settings->value (global_proxy_type.key, global_proxy_type.def).toString ();
+    proxy_type->addItems (global_proxy_all_types);
+    for (int i = 0; i < global_proxy_all_types.length (); i++)
       {
-        currentIndex++;
-        proxyType->setCurrentIndex (currentIndex);
+        if (proxy_type->itemText (i) == proxy_type_string)
+          {
+            proxy_type->setCurrentIndex (i);
+            break;
+          }
       }
-    proxyPort->setText (settings->value (global_proxy_port.key, global_proxy_port.def).toString ());
-    proxyUserName->setText (settings->value (global_proxy_user.key, global_proxy_user.def).toString ());
-    proxyPassword->setText (settings->value (global_proxy_pass.key, global_proxy_pass.def).toString ());
+    // Fill all line edits
+    proxy_host_name->setText (settings->value (global_proxy_host.key, global_proxy_host.def).toString ());
+    proxy_port->setText (settings->value (global_proxy_port.key, global_proxy_port.def).toString ());
+    proxy_username->setText (settings->value (global_proxy_user.key, global_proxy_user.def).toString ());
+    proxy_password->setText (settings->value (global_proxy_pass.key, global_proxy_pass.def).toString ());
+    // Connect relevant signals for dis-/enabling some elements
+    connect (proxy_type, SIGNAL (currentIndexChanged (int)),
+             this, SLOT (proxy_items_update (void)));
+    connect (use_proxy_server, SIGNAL (toggled (bool)),
+             this, SLOT (proxy_items_update (void)));
+    // Check whehter line edits have to be enabled
+    proxy_items_update ();
 
     // Workspace
     read_workspace_colors (settings);
@@ -594,6 +608,32 @@
       }
   }
 
+  // slot for updating enabled state of proxy settings
+  void settings_dialog::proxy_items_update (void)
+  {
+    bool use_proxy = use_proxy_server->isChecked ();
+
+    bool manual = false;
+    for (int i = 0; i < global_proxy_manual_types.length (); i++)
+      {
+        if (proxy_type->currentIndex () == global_proxy_manual_types.at (i))
+          {
+            manual = true;
+            break;
+          }
+      }
+
+    proxy_type->setEnabled (use_proxy);
+    proxy_host_name_label->setEnabled (use_proxy && manual);
+    proxy_host_name->setEnabled (use_proxy && manual);
+    proxy_port_label->setEnabled (use_proxy && manual);
+    proxy_port->setEnabled (use_proxy && manual);
+    proxy_username_label->setEnabled (use_proxy && manual);
+    proxy_username->setEnabled (use_proxy && manual);
+    proxy_password_label->setEnabled (use_proxy && manual);
+    proxy_password->setEnabled (use_proxy && manual);
+  }
+
   // slots for import/export of shortcut sets
 
   void settings_dialog::import_shortcut_set (void)
@@ -935,6 +975,8 @@
     settings->setValue (ed_create_new_file.key, editor_create_new_file->isChecked ());
     settings->setValue (ed_hiding_closes_files.key, editor_hiding_closes_files->isChecked ());
     settings->setValue (ed_always_reload_changed_files.key, editor_reload_changed_files->isChecked ());
+    settings->setValue (ed_force_newline.key, editor_force_newline->isChecked ());
+    settings->setValue (ed_rm_trailing_spaces.key, editor_remove_trailing_spaces->isChecked ());
     settings->setValue (ed_show_dbg_file.key, editor_show_dbg_file->isChecked ());
 
     settings->setValue (cs_font_size.key, terminal_fontSize->value ());
@@ -947,12 +989,12 @@
     settings->setValue (fb_txt_file_ext.key, le_file_browser_extensions->text ());
 
     settings->setValue (nr_allow_connection.key, checkbox_allow_web_connect->isChecked ());
-    settings->setValue (global_use_proxy.key, useProxyServer->isChecked ());
-    settings->setValue (global_proxy_type.key, proxyType->currentText ());
-    settings->setValue (global_proxy_host.key, proxyHostName->text ());
-    settings->setValue (global_proxy_port.key, proxyPort->text ());
-    settings->setValue (global_proxy_user.key, proxyUserName->text ());
-    settings->setValue (global_proxy_pass.key, proxyPassword->text ());
+    settings->setValue (global_use_proxy.key, use_proxy_server->isChecked ());
+    settings->setValue (global_proxy_type.key, proxy_type->currentText ());
+    settings->setValue (global_proxy_host.key, proxy_host_name->text ());
+    settings->setValue (global_proxy_port.key, proxy_port->text ());
+    settings->setValue (global_proxy_user.key, proxy_username->text ());
+    settings->setValue (global_proxy_pass.key, proxy_password->text ());
     settings->setValue (cs_cursor_use_fgcol.key, terminal_cursorUseForegroundColor->isChecked ());
     settings->setValue (mw_dir_list.key, terminal_focus_command->isChecked ());
     settings->setValue (cs_dbg_location.key, terminal_print_dbg_location->isChecked ());
--- a/libgui/src/settings-dialog.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/settings-dialog.h	Thu Nov 19 13:08:00 2020 -0800
@@ -65,6 +65,7 @@
     void get_file_browser_dir (void);
     void get_dir (QLineEdit*, const QString&);
     void set_disabled_pref_file_browser_dir (bool disable);
+    void proxy_items_update (void);
 
     // slots for dialog's buttons
     void button_clicked (QAbstractButton *button);
--- a/libgui/src/settings-dialog.ui	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/settings-dialog.ui	Thu Nov 19 13:08:00 2020 -0800
@@ -32,7 +32,7 @@
       </size>
      </property>
      <property name="currentIndex">
-      <number>5</number>
+      <number>7</number>
      </property>
      <widget class="QWidget" name="tab_general">
       <property name="enabled">
@@ -843,7 +843,7 @@
             <x>0</x>
             <y>0</y>
             <width>1021</width>
-            <height>1467</height>
+            <height>1529</height>
            </rect>
           </property>
           <layout class="QVBoxLayout" name="verticalLayout_16">
@@ -2053,7 +2053,7 @@
                     </property>
                    </widget>
                   </item>
-                  <item row="8" column="0">
+                  <item row="10" column="0">
                    <layout class="QHBoxLayout" name="horizontalLayout_2">
                     <property name="topMargin">
                      <number>0</number>
@@ -2111,7 +2111,7 @@
                     </item>
                    </layout>
                   </item>
-                  <item row="10" column="0">
+                  <item row="12" column="0">
                    <layout class="QHBoxLayout" name="horizontalLayout_16">
                     <item>
                      <widget class="QLabel" name="label_16">
@@ -2138,7 +2138,7 @@
                     </item>
                    </layout>
                   </item>
-                  <item row="7" column="0">
+                  <item row="9" column="0">
                    <widget class="QCheckBox" name="editor_hiding_closes_files">
                     <property name="text">
                      <string>Close all files when the editor widget is closed/hidden</string>
@@ -2148,6 +2148,26 @@
                     </property>
                    </widget>
                   </item>
+                  <item row="5" column="0">
+                   <widget class="QCheckBox" name="editor_force_newline">
+                    <property name="text">
+                     <string>Force newline at end when saving file</string>
+                    </property>
+                    <property name="checked">
+                     <bool>true</bool>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="6" column="0">
+                   <widget class="QCheckBox" name="editor_remove_trailing_spaces">
+                    <property name="text">
+                     <string>Remove trailing spaces when saving file</string>
+                    </property>
+                    <property name="checked">
+                     <bool>true</bool>
+                    </property>
+                   </widget>
+                  </item>
                  </layout>
                 </item>
                </layout>
@@ -2809,124 +2829,151 @@
           </property>
           <layout class="QVBoxLayout" name="verticalLayout_20">
            <item>
-            <layout class="QVBoxLayout" name="verticalLayout">
-             <item>
-              <widget class="QCheckBox" name="checkbox_allow_web_connect">
-               <property name="text">
-                <string>Allow Octave to connect to the Octave web site to display current news and information</string>
-               </property>
-              </widget>
-             </item>
-             <item>
-              <layout class="QGridLayout" name="gridLayout_5">
-               <item row="1" column="1">
-                <widget class="QLabel" name="label_4">
-                 <property name="enabled">
-                  <bool>false</bool>
-                 </property>
-                 <property name="text">
-                  <string>Hostname:</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="2">
-                <widget class="QComboBox" name="proxyType">
-                 <property name="enabled">
-                  <bool>false</bool>
-                 </property>
-                 <item>
-                  <property name="text">
-                   <string>HttpProxy</string>
-                  </property>
-                 </item>
-                 <item>
-                  <property name="text">
-                   <string>Socks5Proxy</string>
-                  </property>
-                 </item>
-                </widget>
-               </item>
-               <item row="3" column="1">
-                <widget class="QLabel" name="label_6">
-                 <property name="enabled">
-                  <bool>false</bool>
-                 </property>
-                 <property name="text">
-                  <string>Username:</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="0">
-                <widget class="QCheckBox" name="useProxyServer">
-                 <property name="text">
-                  <string>Use proxy server</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="1">
-                <widget class="QLabel" name="label_3">
-                 <property name="enabled">
-                  <bool>false</bool>
-                 </property>
-                 <property name="text">
-                  <string>Proxy type:</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="2" column="1">
-                <widget class="QLabel" name="label_5">
-                 <property name="enabled">
-                  <bool>false</bool>
-                 </property>
-                 <property name="text">
-                  <string>Port:</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="4" column="1">
-                <widget class="QLabel" name="label_7">
-                 <property name="enabled">
-                  <bool>false</bool>
-                 </property>
-                 <property name="text">
-                  <string>Password:</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="1" column="2">
-                <widget class="QLineEdit" name="proxyHostName">
-                 <property name="enabled">
-                  <bool>false</bool>
-                 </property>
-                </widget>
-               </item>
-               <item row="2" column="2">
-                <widget class="QLineEdit" name="proxyPort">
-                 <property name="enabled">
-                  <bool>false</bool>
-                 </property>
-                </widget>
-               </item>
-               <item row="3" column="2">
-                <widget class="QLineEdit" name="proxyUserName">
-                 <property name="enabled">
-                  <bool>false</bool>
-                 </property>
-                </widget>
-               </item>
-               <item row="4" column="2">
-                <widget class="QLineEdit" name="proxyPassword">
-                 <property name="enabled">
-                  <bool>false</bool>
-                 </property>
-                 <property name="echoMode">
-                  <enum>QLineEdit::Password</enum>
-                 </property>
-                </widget>
-               </item>
-              </layout>
-             </item>
-            </layout>
+            <widget class="QGroupBox" name="groupBox_12">
+             <property name="title">
+              <string>General</string>
+             </property>
+             <layout class="QVBoxLayout" name="verticalLayout_33">
+              <item>
+               <widget class="QCheckBox" name="checkbox_allow_web_connect">
+                <property name="text">
+                 <string>Allow Octave to connect to the Octave web site to display current news and information</string>
+                </property>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+           </item>
+           <item>
+            <widget class="QGroupBox" name="groupBox_13">
+             <property name="title">
+              <string>Proxy Server</string>
+             </property>
+             <layout class="QVBoxLayout" name="verticalLayout_34">
+              <item>
+               <layout class="QVBoxLayout" name="verticalLayout">
+                <item>
+                 <layout class="QGridLayout" name="gridLayout_5">
+                  <item row="1" column="2">
+                   <widget class="QLabel" name="proxy_host_name_label">
+                    <property name="enabled">
+                     <bool>false</bool>
+                    </property>
+                    <property name="text">
+                     <string>Hostname:</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="0" column="3">
+                   <widget class="QComboBox" name="proxy_type">
+                    <property name="enabled">
+                     <bool>true</bool>
+                    </property>
+                    <property name="toolTip">
+                     <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Select &lt;span style=&quot; font-style:italic;&quot;&gt;HttpProxy&lt;/span&gt;, &lt;span style=&quot; font-style:italic;&quot;&gt;Sock5Proxy&lt;/span&gt; or &lt;span style=&quot; font-style:italic;&quot;&gt;Environment Variables&lt;/span&gt;. With the last selection, the proxy is taken from the first non-empty environment variable ALL_PROXY, HTTP_PROXY or HTTPS_PROXY .&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="3" column="2">
+                   <widget class="QLabel" name="proxy_username_label">
+                    <property name="enabled">
+                     <bool>false</bool>
+                    </property>
+                    <property name="text">
+                     <string>Username:</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="0" column="2">
+                   <widget class="QLabel" name="proxy_type_label">
+                    <property name="enabled">
+                     <bool>true</bool>
+                    </property>
+                    <property name="text">
+                     <string>Proxy type:</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="2" column="2">
+                   <widget class="QLabel" name="proxy_port_label">
+                    <property name="enabled">
+                     <bool>false</bool>
+                    </property>
+                    <property name="text">
+                     <string>Port:</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="4" column="2">
+                   <widget class="QLabel" name="proxy_password_label">
+                    <property name="enabled">
+                     <bool>false</bool>
+                    </property>
+                    <property name="text">
+                     <string>Password:</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="1" column="3">
+                   <widget class="QLineEdit" name="proxy_host_name">
+                    <property name="enabled">
+                     <bool>false</bool>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="2" column="3">
+                   <widget class="QLineEdit" name="proxy_port">
+                    <property name="enabled">
+                     <bool>false</bool>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="3" column="3">
+                   <widget class="QLineEdit" name="proxy_username">
+                    <property name="enabled">
+                     <bool>false</bool>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="4" column="3">
+                   <widget class="QLineEdit" name="proxy_password">
+                    <property name="enabled">
+                     <bool>false</bool>
+                    </property>
+                    <property name="echoMode">
+                     <enum>QLineEdit::Password</enum>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="0" column="0">
+                   <widget class="QCheckBox" name="use_proxy_server">
+                    <property name="text">
+                     <string>Use proxy server</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="0" column="1">
+                   <spacer name="horizontalSpacer_30">
+                    <property name="orientation">
+                     <enum>Qt::Horizontal</enum>
+                    </property>
+                    <property name="sizeType">
+                     <enum>QSizePolicy::Fixed</enum>
+                    </property>
+                    <property name="sizeHint" stdset="0">
+                     <size>
+                      <width>20</width>
+                      <height>20</height>
+                     </size>
+                    </property>
+                   </spacer>
+                  </item>
+                 </layout>
+                </item>
+               </layout>
+              </item>
+             </layout>
+            </widget>
            </item>
            <item>
             <spacer name="verticalSpacer_5">
@@ -2961,102 +3008,6 @@
  <resources/>
  <connections>
   <connection>
-   <sender>useProxyServer</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>label_4</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>249</x>
-     <y>59</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>69</x>
-     <y>122</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>useProxyServer</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>label_3</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>249</x>
-     <y>59</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>59</x>
-     <y>91</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>useProxyServer</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>proxyHostName</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>249</x>
-     <y>59</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>291</x>
-     <y>124</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>useProxyServer</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>label_5</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>249</x>
-     <y>59</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>44</x>
-     <y>152</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>useProxyServer</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>proxyType</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>249</x>
-     <y>59</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>291</x>
-     <y>91</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>useProxyServer</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>proxyPort</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>249</x>
-     <y>59</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>364</x>
-     <y>154</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
    <sender>useCustomFileEditor</sender>
    <signal>toggled(bool)</signal>
    <receiver>customFileEditor</receiver>
@@ -3073,70 +3024,6 @@
    </hints>
   </connection>
   <connection>
-   <sender>useProxyServer</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>label_7</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>249</x>
-     <y>59</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>67</x>
-     <y>212</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>useProxyServer</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>label_6</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>249</x>
-     <y>59</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>68</x>
-     <y>182</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>useProxyServer</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>proxyPassword</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>249</x>
-     <y>59</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>364</x>
-     <y>214</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>useProxyServer</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>proxyUserName</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>249</x>
-     <y>59</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>364</x>
-     <y>184</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
    <sender>useCustomFileEditor</sender>
    <signal>toggled(bool)</signal>
    <receiver>customEditorLabel</receiver>
--- a/libgui/src/shortcut-manager.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/shortcut-manager.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -75,11 +75,7 @@
         if (key == Qt::Key_unknown || key == 0)
           return;
 
-#if defined (HAVE_QGUIAPPLICATION)
         Qt::KeyboardModifiers modifiers = QGuiApplication::keyboardModifiers (); //e->modifiers ();
-#else
-        Qt::KeyboardModifiers modifiers = QApplication::keyboardModifiers (); //e->modifiers ();
-#endif
 
         if (m_shift_modifier || (modifiers & Qt::ShiftModifier))
           key += Qt::SHIFT;
@@ -168,6 +164,11 @@
     init (tr ("Continue"), sc_main_debug_continue);
     init (tr ("Quit Debug Mode"), sc_main_debug_quit);
 
+    // tools
+    init (tr ("Start/Stop Profiler Session"), sc_main_tools_start_profiler);
+    init (tr ("Resume Profiler Session"), sc_main_tools_resume_profiler);
+    init (tr ("Show Profile Data"), sc_main_tools_show_profiler);
+
     // window
     init (tr ("Show Command Window"), sc_main_window_show_command);
     init (tr ("Show Command History"), sc_main_window_show_history);
@@ -372,11 +373,7 @@
     m_dialog = nullptr;
     m_level_hash.clear ();
 
-#if defined (HAVE_QHEADERVIEW_SETSECTIONRESIZEMODE)
     tree_view->header ()->setSectionResizeMode (QHeaderView::ResizeToContents);
-#else
-    tree_view->header ()->setResizeMode (QHeaderView::ResizeToContents);
-#endif
 
     QTreeWidgetItem *main = new QTreeWidgetItem (tree_view);
     main->setText (0, tr ("Global"));
@@ -387,6 +384,8 @@
     main_edit->setText (0, tr ("Edit Menu"));
     QTreeWidgetItem *main_debug = new QTreeWidgetItem (main);
     main_debug->setText (0, tr ("Debug Menu"));
+    QTreeWidgetItem *main_tools = new QTreeWidgetItem (main);
+    main_tools->setText (0, tr ("Tools Menu"));
     QTreeWidgetItem *main_window = new QTreeWidgetItem (main);
     main_window->setText (0, tr ("Window Menu"));
     QTreeWidgetItem *main_help = new QTreeWidgetItem (main);
@@ -405,6 +404,7 @@
     m_level_hash[sc_main_file]   = main_file;
     m_level_hash[sc_main_edit]   = main_edit;
     m_level_hash[sc_main_debug]   = main_debug;
+    m_level_hash[sc_main_tools]   = main_tools;
     m_level_hash[sc_main_window]   = main_window;
     m_level_hash[sc_main_help]   = main_help;
     m_level_hash[sc_main_news]   = main_news;
--- a/libgui/src/tab-bar.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/tab-bar.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -56,16 +56,12 @@
 
   void tab_bar::move_tab_left (void)
   {
-#if defined (HAVE_QTABWIDGET_SETMOVABLE)
     switch_tab (-1, true);
-#endif
   }
 
   void tab_bar::move_tab_right (void)
   {
-#if defined (HAVE_QTABWIDGET_SETMOVABLE)
     switch_tab (1, true);
-#endif
   }
 
   void tab_bar::switch_tab (int direction, bool movetab)
@@ -83,11 +79,9 @@
 
     if (movetab)
       {
-#if defined (HAVE_QTABWIDGET_SETMOVABLE)
         moveTab (old_pos, new_pos);
         setCurrentIndex (old_pos);
         setCurrentIndex (new_pos);
-#endif
       }
     else
       setCurrentIndex (new_pos);
--- a/libgui/src/variable-editor-model.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/variable-editor-model.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -1024,7 +1024,7 @@
     std::string expr = os.str ();
 
     emit interpreter_event
-      ([this, nm, expr, idx] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -1173,7 +1173,7 @@
     std::string expr = expr_arg.toStdString ();
 
     emit interpreter_event
-      ([this, expr] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -1245,7 +1245,7 @@
   variable_editor_model::update_data_cache (void)
   {
     emit interpreter_event
-      ([this] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER_THREAD
 
--- a/libgui/src/variable-editor-model.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/variable-editor-model.h	Thu Nov 19 13:08:00 2020 -0800
@@ -263,11 +263,21 @@
       return rep->display_rows ();
     }
 
+    octave_idx_type data_rows (void) const
+    {
+      return rep->data_rows ();
+    }
+
     int display_columns (void) const
     {
       return rep->display_columns ();
     }
 
+    octave_idx_type data_columns (void) const
+    {
+      return rep->data_columns ();
+    }
+
     void maybe_resize_rows (int rows);
 
     void maybe_resize_columns (int cols);
@@ -318,16 +328,6 @@
       return rep->is_valid ();
     }
 
-    octave_idx_type data_rows (void) const
-    {
-      return rep->data_rows ();
-    }
-
-    octave_idx_type data_columns (void) const
-    {
-      return rep->data_columns ();
-    }
-
     void change_display_size (int old_rows, int old_cols,
                               int new_rows, int new_cols);
 
--- a/libgui/src/variable-editor.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/variable-editor.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -40,7 +40,6 @@
 #include <QPalette>
 #include <QScreen>
 #include <QScrollBar>
-#include <QSignalMapper>
 #include <QStackedWidget>
 #include <QTabWidget>
 #include <QTableView>
@@ -63,14 +62,6 @@
 {
   // Code reuse functions
 
-  static QString
-  idx_to_expr (int32_t from, int32_t to)
-  {
-    return (from == to
-            ? QString ("%1").arg (from)
-            : QString ("%1:%2").arg (from).arg (to));
-  }
-
   static QSignalMapper *
   make_plot_mapper (QMenu *menu)
   {
@@ -80,11 +71,8 @@
     QSignalMapper *plot_mapper = new QSignalMapper (menu);
 
     for (int i = 0; i < list.size(); ++i)
-      {
-        plot_mapper->setMapping
-          (menu->addAction (list.at (i), plot_mapper, SLOT (map ())),
-           "figure (); " + list.at (i) + " (%1); title (\"%1\");");
-      }
+      plot_mapper->setMapping
+        (menu->addAction (list.at (i), plot_mapper, SLOT (map ())), list.at (i));
 
     return plot_mapper;
   }
@@ -112,7 +100,6 @@
     connect (p, SIGNAL (visibilityChanged (bool)),
              this, SLOT (setVisible (bool)));
 
-#if defined (HAVE_QGUIAPPLICATION)
 #define DOCKED_FULLSCREEN_BUTTON_TOOLTIP "Fullscreen undock"
 #define UNDOCKED_FULLSCREEN_BUTTON_TOOLTIP "Fullscreen"
     // Add a fullscreen button
@@ -142,7 +129,6 @@
     if (first != nullptr)
       index = h_layout->indexOf (first);
     h_layout->insertWidget (index, fullscreen_button);
-#endif
 
     // Custom title bars cause loss of decorations, add a frame
     m_frame = new QFrame (this);
@@ -154,7 +140,6 @@
   void
   variable_dock_widget::change_floating (bool)
   {
-#if defined (HAVE_QGUIAPPLICATION)
     if (isFloating ())
       {
         if (m_full_screen)
@@ -168,7 +153,6 @@
       }
     else
       m_fullscreen_action->setToolTip (tr (UNDOCKED_FULLSCREEN_BUTTON_TOOLTIP));
-#endif
 
     setFloating (! isFloating ());
   }
@@ -218,7 +202,6 @@
   void
   variable_dock_widget::change_fullscreen (void)
   {
-#if defined (HAVE_QGUIAPPLICATION)
     resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
 
     if (! m_full_screen)
@@ -258,7 +241,6 @@
       }
 #undef DOCKED_FULLSCREEN_BUTTON_TOOLTIP
 #undef UNDOCKED_FULLSCREEN_BUTTON_TOOLTIP
-#endif
   }
 
   void
@@ -502,11 +484,7 @@
     setHorizontalScrollMode (QAbstractItemView::ScrollPerPixel);
     setVerticalScrollMode (QAbstractItemView::ScrollPerPixel);
 
-#if defined (HAVE_QHEADERVIEW_SETSECTIONRESIZEMODE)
     verticalHeader ()->setSectionResizeMode (QHeaderView::Interactive);
-#else
-    verticalHeader ()->setResizeMode (QHeaderView::Interactive);
-#endif
   }
 
   void
@@ -514,11 +492,7 @@
   {
     QTableView::setModel (model);
 
-#if defined (HAVE_QHEADERVIEW_SETSECTIONRESIZEMODE)
     horizontalHeader ()->setSectionResizeMode (QHeaderView::Interactive);
-#else
-    horizontalHeader ()->setResizeMode (QHeaderView::Interactive);
-#endif
 
     m_var_model = parent ()->findChild<variable_editor_model *> ();
 
@@ -567,30 +541,39 @@
     return range;
   }
 
-  QString
-  variable_editor_view::selected_to_octave (void)
-  {
-    QList<int> range = range_selected ();
-    if (range.isEmpty ())
-      return objectName ();
-
-    QString rows = idx_to_expr (range.at (0), range.at (1));
-    QString cols = idx_to_expr (range.at (2), range.at (3));
-
-    // FIXME: Does cell need separate handling?  Maybe use '{.,.}'?
-
-    return QString ("%1(%2, %3)").arg (objectName ()).arg (rows).arg (cols);
-  }
-
   void
   variable_editor_view::selected_command_requested (const QString& cmd)
   {
     if (! hasFocus ())
       return;
 
-    QString selarg = selected_to_octave ();
-    if (! selarg.isEmpty ())
-      emit command_signal (cmd.arg (selarg));
+    QList<int> range = range_selected ();
+    if (range.isEmpty ())
+      return;
+
+    int s1 = m_var_model->data_rows ();
+    int s2 = m_var_model->data_columns ();
+    if (s1 < range.at (0) || s2 < range.at (2))
+      return; // Selected range does not contain data
+
+    s1 = std::min (s1, range.at (1));
+    s2 = std::min (s2, range.at (3));
+
+    // Variable with desired range as string
+    QString variable = QString ("%1(%2:%3,%4:%5)")
+                                .arg (objectName ())
+                                .arg (range.at (0)).arg (s1)
+                                .arg (range.at (2)).arg (s2);
+
+    // Desired command as string
+    QString command;
+    if (cmd == "create")
+      command = QString ("unnamed = %1;").arg (variable);
+    else
+      command = QString ("figure (); %1 (%2); title ('%2');")
+                          .arg (cmd).arg (variable);
+
+    emit command_signal (command);
   }
 
   void
@@ -765,7 +748,7 @@
   {
     // FIXME: Create unnamed1..n if exist ('unnamed', 'var') is true.
 
-    selected_command_requested ("unnamed = %1");
+    selected_command_requested ("create");
   }
 
   void
@@ -1064,6 +1047,7 @@
       m_table_colors (),
       m_current_focus_vname (""),
       m_hovered_focus_vname (""),
+      m_plot_mapper (nullptr),
       m_focus_widget (nullptr),
       m_focus_widget_vdw (nullptr)
   {
@@ -1142,29 +1126,6 @@
       }
   }
 
-  // Add an action to a menu or the widget itself.
-
-  QAction*
-  variable_editor::add_action (QMenu *menu, const QIcon& icon,
-                               const QString& text,
-                               const char *member)
-  {
-    QAction *a;
-
-    if (menu)
-      a = menu->addAction (icon, text, this, member);
-    else
-      {
-        a = new QAction (this);
-        connect (a, SIGNAL (triggered ()), this, member);
-      }
-
-    addAction (a);  // important for shortcut context
-    a->setShortcutContext (Qt::WidgetWithChildrenShortcut);
-
-    return a;
-  }
-
   void
   variable_editor::edit_variable (const QString& name, const octave_value& val)
   {
@@ -1244,6 +1205,9 @@
     edit_view->verticalHeader ()->setDefaultSectionSize (m_default_height
                                                          + m_add_font_height);
 
+    connect (m_plot_mapper, SIGNAL (mapped (const QString&)),
+             edit_view, SLOT (selected_command_requested (const QString&)));
+
     connect (edit_view, SIGNAL (command_signal (const QString&)),
              this, SIGNAL (command_signal (const QString&)));
     connect (this, SIGNAL (delete_selected_signal ()),
@@ -1254,8 +1218,6 @@
              edit_view, SLOT (copyClipboard ()));
     connect (this, SIGNAL (paste_clipboard_signal ()),
              edit_view, SLOT (pasteClipboard ()));
-    connect (this, SIGNAL (selected_command_signal (const QString&)),
-             edit_view, SLOT (selected_command_requested (const QString&)));
     connect (edit_view->horizontalHeader (),
              SIGNAL (customContextMenuRequested (const QPoint&)),
              edit_view, SLOT (createColumnMenu (const QPoint&)));
@@ -1523,12 +1485,6 @@
     emit level_up_signal ();
   }
 
-  void
-  variable_editor::relay_selected_command (const QString& cmd)
-  {
-    emit selected_command_signal (cmd);
-  }
-
   // Also updates the font.
 
   void variable_editor::update_colors (void)
@@ -1647,10 +1603,7 @@
     plot_menu->setTitle (tr ("Plot"));
     plot_menu->setSeparatorsCollapsible (false);
 
-    QSignalMapper *plot_mapper = make_plot_mapper (plot_menu);
-
-    connect (plot_mapper, SIGNAL (mapped (const QString&)),
-             this, SLOT (relay_selected_command (const QString&)));
+    m_plot_mapper = make_plot_mapper (plot_menu);
 
     plot_tool_button->setMenu (plot_menu);
 
@@ -1667,9 +1620,7 @@
     // that restores active window and focus before acting.
     QList<HoverToolButton *> hbuttonlist
       = m_tool_bar->findChildren<HoverToolButton *> (""
-#if defined (QOBJECT_FINDCHILDREN_ACCEPTS_FINDCHILDOPTIONS)
                                                      , Qt::FindDirectChildrenOnly
-#endif
                                                     );
     for (int i = 0; i < hbuttonlist.size (); i++)
       {
@@ -1681,9 +1632,7 @@
 
     QList<ReturnFocusToolButton *> rfbuttonlist
       = m_tool_bar->findChildren<ReturnFocusToolButton *> (""
-#if defined (QOBJECT_FINDCHILDREN_ACCEPTS_FINDCHILDOPTIONS)
                                                            , Qt::FindDirectChildrenOnly
-#endif
                                                           );
     for (int i = 0; i < rfbuttonlist.size (); i++)
       {
--- a/libgui/src/variable-editor.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/variable-editor.h	Thu Nov 19 13:08:00 2020 -0800
@@ -27,6 +27,7 @@
 #define octave_variable_editor_h 1
 
 #include <QHeaderView>
+#include <QSignalMapper>
 #include <QStackedWidget>
 #include <QTableView>
 
@@ -86,8 +87,6 @@
 
     QFrame *m_frame;
 
-#if defined (HAVE_QGUIAPPLICATION)
-
     QAction *m_fullscreen_action;
 
     bool m_full_screen;
@@ -96,8 +95,6 @@
 
     QRect m_prev_geom;
 
-#endif
-
 // See Octave bug #53807 and https://bugreports.qt.io/browse/QTBUG-44813
 #define QTBUG_44813_FIX_VERSION 0x999999
   signals:
@@ -207,9 +204,6 @@
 
     void createRowMenu (const QPoint& pt);
 
-    // Convert selection to an Octave expression.
-    QString selected_to_octave (void);
-
     void selected_command_requested (const QString& cmd);
 
   private:
@@ -321,8 +315,6 @@
 
     void delete_selected_signal (void);
 
-    void selected_command_signal (const QString& cmd);
-
   public slots:
 
     void callUpdate (const QModelIndex&, const QModelIndex&);
@@ -353,19 +345,12 @@
 
     void levelUp (void);
 
-    // Send command to Octave interpreter.
-    // %1 in CMD is replaced with the value of selected_to_octave.
-    void relay_selected_command (const QString& cmd);
-
   protected:
 
     void focusInEvent (QFocusEvent *ev);
 
   private:
 
-    QAction * add_action (QMenu *menu, const QIcon& icon, const QString& text,
-                          const char *member);
-
     dw_main_window *m_main;
 
     QToolBar *m_tool_bar;
@@ -401,6 +386,8 @@
 
     QString m_hovered_focus_vname;
 
+    QSignalMapper *m_plot_mapper;
+
     QWidget *m_focus_widget;
 
     variable_dock_widget *m_focus_widget_vdw;
--- a/libgui/src/workspace-model.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/workspace-model.h	Thu Nov 19 13:08:00 2020 -0800
@@ -75,6 +75,9 @@
 
     symbol_info_list get_symbol_info (void) const { return m_syminfo_list; }
 
+    QStringList get_symbol_names (void) const { return m_symbols; }
+    QStringList get_symbol_values (void) const { return m_values; }
+
   signals:
 
     void model_changed (void);
--- a/libgui/src/workspace-view.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libgui/src/workspace-view.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -120,16 +120,8 @@
           (settings->value (ws_column_state.key).toByteArray ());
 
         // Set header properties for sorting
-#if defined (HAVE_QHEADERVIEW_SETSECTIONSCLICKABLE)
         m_view->horizontalHeader ()->setSectionsClickable (true);
-#else
-        m_view->horizontalHeader ()->setClickable (true);
-#endif
-#if defined (HAVE_QHEADERVIEW_SETSECTIONSMOVABLE)
         m_view->horizontalHeader ()->setSectionsMovable (true);
-#else
-        m_view->horizontalHeader ()->setMovable (true);
-#endif
         m_view->horizontalHeader ()->setSortIndicator (
           settings->value (ws_sort_column).toInt (),
           static_cast<Qt::SortOrder> (settings->value (ws_sort_order).toUInt ()));
@@ -217,7 +209,7 @@
               .arg (m_model->storage_class_color (i).name ())
               .arg (m_model->storage_class_color (i + ws_colors_count).name ())
               .arg (QCoreApplication::translate ("octave::settings_dialog",
-                                ws_color_names.at (i).toStdString ().data ()));
+                                                 ws_color_names.at (i).toStdString ().data ()));
           }
       }
 
@@ -413,7 +405,7 @@
         QString var_name = get_var_name (index);
 
         emit interpreter_event
-          ([var_name] (interpreter& interp)
+          ([=] (interpreter& interp)
            {
              // INTERPRETER THREAD
 
--- a/libinterp/corefcn/Cell.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/Cell.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -234,7 +234,7 @@
 %% This behavior is required for Matlab compatibility.
 %!shared a
 %! a = {"foo", "bar"};
-%!assert (a(), a);
+%!assert (a(), a)
 %!error <invalid empty index expression> a{}
 */
 
--- a/libinterp/corefcn/__betainc__.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/__betainc__.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -37,9 +37,7 @@
 Continued fraction for incomplete beta function.
 @end deftypefn */)
 {
-  int nargin = args.length ();
-
-  if (nargin != 3)
+  if (args.length () != 3)
     print_usage ();
 
   bool is_single = (args(0).is_single_type () || args(1).is_single_type ()
--- a/libinterp/corefcn/__dsearchn__.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/__dsearchn__.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -48,7 +48,7 @@
   Matrix xi = args(1).matrix_value ().transpose ();
 
   if (x.rows () != xi.rows () || x.columns () < 1)
-    error ("__dsearch__: number of rows of X and XI must match");
+    error ("__dsearchn__: number of rows of X and XI must match");
 
   octave_idx_type n = x.rows ();
   octave_idx_type nx = x.columns ();
--- a/libinterp/corefcn/__eigs__.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/__eigs__.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -199,9 +199,7 @@
 
   warned_imaginary = false;
 
-  octave::unwind_protect frame;
-
-  frame.protect_var (call_depth);
+  octave::unwind_protect_var<int> restore_var (call_depth);
   call_depth++;
 
   if (call_depth > 1)
--- a/libinterp/corefcn/__expint__.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/__expint__.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -37,9 +37,7 @@
 Continued fraction expansion for the exponential integral.
 @end deftypefn */)
 {
-  int nargin = args.length ();
-
-  if (nargin != 1)
+  if (args.length () != 1)
     print_usage ();
 
   octave_value_list retval;
--- a/libinterp/corefcn/__ftp__.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/__ftp__.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -425,7 +425,7 @@
       else
         {
           // FIXME: Does ascii mode need to be flagged here?
-          std::ifstream ifile = 
+          std::ifstream ifile =
             octave::sys::ifstream (file.c_str (),
                                    std::ios::in | std::ios::binary);
 
--- a/libinterp/corefcn/__gammainc__.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/__gammainc__.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -36,9 +36,7 @@
 Continued fraction for incomplete gamma function.
 @end deftypefn */)
 {
-  int nargin = args.length ();
-
-  if (nargin != 2)
+  if (args.length () != 2)
     print_usage ();
 
   bool is_single = args(0).is_single_type () || args(1).is_single_type ();
--- a/libinterp/corefcn/__magick_read__.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/__magick_read__.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -28,6 +28,7 @@
 #endif
 
 #include "file-stat.h"
+#include "lo-sysdep.h"
 #include "oct-env.h"
 #include "oct-time.h"
 
@@ -140,17 +141,17 @@
 // width 1.  In those cases, the type will come as scalar instead of range
 // since that's the behavior of the colon operator (1:1:1 will be a scalar,
 // not a range).
-static Range
+static octave::range<double>
 get_region_range (const octave_value& region)
 {
-  Range output;
+  octave::range<double> output;
 
   if (region.is_range ())
     output = region.range_value ();
   else if (region.is_scalar_type ())
     {
       double value = region.scalar_value ();
-      output = Range (value, value);
+      output = octave::range<double> (value, value);
     }
   else if (region.is_matrix_type ())
     {
@@ -158,7 +159,7 @@
       double base = array(0);
       double limit = array(array.numel () - 1);
       double incr = array(1) - base;
-      output = Range (base, limit, incr);
+      output = octave::range<double> (base, incr, limit);
     }
   else
     error ("__magick_read__: unknown datatype for Region option");
@@ -180,8 +181,8 @@
 
     // Subtract 1 to account for 0 indexing.
 
-    const Range rows = get_region_range (pixel_region (0));
-    const Range cols = get_region_range (pixel_region (1));
+    const octave::range<double> rows = get_region_range (pixel_region (0));
+    const octave::range<double> cols = get_region_range (pixel_region (1));
 
     m_row_start = rows.base () - 1;
     m_col_start = cols.base () - 1;
@@ -191,8 +192,8 @@
     m_row_cache = m_row_end - m_row_start + 1;
     m_col_cache = m_col_end - m_col_start + 1;
 
-    m_row_shift = m_col_cache * rows.inc ();
-    m_col_shift = m_col_cache * (m_row_cache + rows.inc () - 1) - cols.inc ();
+    m_row_shift = m_col_cache * rows.increment ();
+    m_col_shift = m_col_cache * (m_row_cache + rows.increment () - 1) - cols.increment ();
 
     m_row_out = rows.numel ();
     m_col_out = cols.numel ();
@@ -754,9 +755,15 @@
 void static
 read_file (const std::string& filename, std::vector<Magick::Image>& imvec)
 {
+  // FIXME: We need this on Windows because GraphicsMagick uses the ANSI API
+  // to open files on disc.  In contrast, the API of ImageMagick uses UTF-8
+  // encoded strings.  Should we somehow detect which is used on runtime and
+  // pass the file names accordingly? (See also bug #58493.)
+  std::string ascii_fname = octave::sys::get_ASCII_filename (filename, true);
+
   try
     {
-      Magick::readImages (&imvec, filename);
+      Magick::readImages (&imvec, ascii_fname);
     }
   catch (Magick::Warning& w)
     {
@@ -1551,7 +1558,7 @@
         encode_indexed_images<uint16NDArray> (imvec, img.uint16_array_value (),
                                               cmap);
       else
-        error ("__magick_write__: indexed image must be uint8, uint16 or float.");
+        error ("__magick_write__: indexed image must be uint8, uint16 or float");
     }
   static std::map<std::string, octave_idx_type> disposal_methods
     = init_reverse_disposal_methods ();
@@ -1687,9 +1694,16 @@
   Magick::Image img;
   img.subImage (idx); // start ping from this image (in case of multi-page)
   img.subRange (1);   // ping only one of them
+
+  // FIXME: We need this on Windows because GraphicsMagick uses the ANSI API
+  // to open files on disc.  In contrast, the API of ImageMagick uses UTF-8
+  // encoded strings.  Should we somehow detect which is used on runtime and
+  // pass the file names accordingly? (See also bug #58493.)
+  std::string ascii_fname = octave::sys::get_ASCII_filename (filename, true);
+
   try
     {
-      img.ping (filename);
+      img.ping (ascii_fname);
     }
   catch (Magick::Warning& w)
     {
--- a/libinterp/corefcn/besselj.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/besselj.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -737,12 +737,12 @@
 %!assert (besselh (alpha,1,x), jx + I*yx, 100*eps)
 %!assert (besselh (alpha,2,x), jx - I*yx, 100*eps)
 %!
-%!assert (besselj (alpha,x,1), jx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (alpha,x,1), yx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (alpha,x,1), ix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (alpha,x,1), jx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (alpha,x,1), yx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (alpha,x,1), ix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp (I*x), 100*eps)
 %!
 %!assert (besselj (-alpha,x), jx, 100*eps)
 %!assert (bessely (-alpha,x), yx, 100*eps)
@@ -751,12 +751,12 @@
 %!assert (besselh (-alpha,1,x), jx + I*yx, 100*eps)
 %!assert (besselh (-alpha,2,x), jx - I*yx, 100*eps)
 %!
-%!assert (besselj (-alpha,x,1), jx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (-alpha,x,1), yx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (-alpha,x,1), ix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (-alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (-alpha,1,x,1), (jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (-alpha,2,x,1), (jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (-alpha,x,1), jx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (-alpha,x,1), yx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (-alpha,x,1), ix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (-alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (-alpha,1,x,1), (jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (-alpha,2,x,1), (jx - I*yx)*exp (I*x), 100*eps)
 %!
 %! x *= -1;
 %! yx = -1.193199310178553861283790424 + 0.3421822624810469647226182835*I;
@@ -769,12 +769,12 @@
 %!assert (besselh (alpha,1,x), jx + I*yx, 100*eps)
 %!assert (besselh (alpha,2,x), jx - I*yx, 100*eps)
 %!
-%!assert (besselj (alpha,x,1), jx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (alpha,x,1), yx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (alpha,x,1), ix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (alpha,x,1), jx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (alpha,x,1), yx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (alpha,x,1), ix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp (I*x), 100*eps)
 %!
 %! ## Bessel functions, odd order, positive and negative x
 %! alpha = 3;  x = 2.5;
@@ -790,12 +790,12 @@
 %!assert (besselh (alpha,1,x), jx + I*yx, 100*eps)
 %!assert (besselh (alpha,2,x), jx - I*yx, 100*eps)
 %!
-%!assert (besselj (alpha,x,1), jx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (alpha,x,1), yx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (alpha,x,1), ix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (alpha,x,1), jx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (alpha,x,1), yx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (alpha,x,1), ix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp (I*x), 100*eps)
 %!
 %!assert (besselj (-alpha,x), -jx, 100*eps)
 %!assert (bessely (-alpha,x), -yx, 100*eps)
@@ -804,12 +804,12 @@
 %!assert (besselh (-alpha,1,x), -(jx + I*yx), 100*eps)
 %!assert (besselh (-alpha,2,x), -(jx - I*yx), 100*eps)
 %!
-%!assert (besselj (-alpha,x,1), -jx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (-alpha,x,1), -yx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (-alpha,x,1), ix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (-alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (-alpha,1,x,1), -(jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (-alpha,2,x,1), -(jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (-alpha,x,1), -jx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (-alpha,x,1), -yx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (-alpha,x,1), ix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (-alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (-alpha,1,x,1), -(jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (-alpha,2,x,1), -(jx - I*yx)*exp (I*x), 100*eps)
 %!
 %! x *= -1;
 %! jx = -jx;
@@ -824,12 +824,12 @@
 %!assert (besselh (alpha,1,x), jx + I*yx, 100*eps)
 %!assert (besselh (alpha,2,x), jx - I*yx, 100*eps)
 %!
-%!assert (besselj (alpha,x,1), jx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (alpha,x,1), yx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (alpha,x,1), ix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (alpha,x,1), jx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (alpha,x,1), yx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (alpha,x,1), ix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp (I*x), 100*eps)
 %!
 %! ## Bessel functions, fractional order, positive and negative x
 %!
@@ -846,12 +846,12 @@
 %!assert (besselh (alpha,1,x), jx + I*yx, 100*eps)
 %!assert (besselh (alpha,2,x), jx - I*yx, 100*eps)
 %!
-%!assert (besselj (alpha,x,1), jx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (alpha,x,1), yx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (alpha,x,1), ix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (alpha,x,1), jx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (alpha,x,1), yx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (alpha,x,1), ix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp (I*x), 100*eps)
 %!
 %! nix = 0.2119931212254662995364461998;
 %!
@@ -862,12 +862,12 @@
 %!assert (besselh (-alpha,1,x), -I*(jx + I*yx), 100*eps)
 %!assert (besselh (-alpha,2,x), I*(jx - I*yx), 100*eps)
 %!
-%!assert (besselj (-alpha,x,1), yx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (-alpha,x,1), -jx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (-alpha,x,1), nix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (-alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (-alpha,1,x,1), -I*(jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (-alpha,2,x,1), I*(jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (-alpha,x,1), yx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (-alpha,x,1), -jx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (-alpha,x,1), nix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (-alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (-alpha,1,x,1), -I*(jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (-alpha,2,x,1), I*(jx - I*yx)*exp (I*x), 100*eps)
 %!
 %! x *= -1;
 %! jx *= -I;
@@ -882,12 +882,12 @@
 %!assert (besselh (alpha,1,x), jx + I*yx, 100*eps)
 %!assert (besselh (alpha,2,x), jx - I*yx, 100*eps)
 %!
-%!assert (besselj (alpha,x,1), jx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (alpha,x,1), yx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (alpha,x,1), ix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (alpha,x,1), jx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (alpha,x,1), yx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (alpha,x,1), ix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp (I*x), 100*eps)
 %!
 %! ## Bessel functions, even order, complex x
 %!
@@ -904,12 +904,12 @@
 %!assert (besselh (alpha,1,x), jx + I*yx, 100*eps)
 %!assert (besselh (alpha,2,x), jx - I*yx, 100*eps)
 %!
-%!assert (besselj (alpha,x,1), jx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (alpha,x,1), yx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (alpha,x,1), ix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (alpha,x,1), jx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (alpha,x,1), yx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (alpha,x,1), ix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp (I*x), 100*eps)
 %!
 %!assert (besselj (-alpha,x), jx, 100*eps)
 %!assert (bessely (-alpha,x), yx, 100*eps)
@@ -918,12 +918,12 @@
 %!assert (besselh (-alpha,1,x), jx + I*yx, 100*eps)
 %!assert (besselh (-alpha,2,x), jx - I*yx, 100*eps)
 %!
-%!assert (besselj (-alpha,x,1), jx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (-alpha,x,1), yx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (-alpha,x,1), ix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (-alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (-alpha,1,x,1), (jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (-alpha,2,x,1), (jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (-alpha,x,1), jx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (-alpha,x,1), yx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (-alpha,x,1), ix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (-alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (-alpha,1,x,1), (jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (-alpha,2,x,1), (jx - I*yx)*exp (I*x), 100*eps)
 %!
 %! ## Bessel functions, odd order, complex x
 %!
@@ -940,12 +940,12 @@
 %!assert (besselh (alpha,1,x), jx + I*yx, 100*eps)
 %!assert (besselh (alpha,2,x), jx - I*yx, 100*eps)
 %!
-%!assert (besselj (alpha,x,1), jx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (alpha,x,1), yx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (alpha,x,1), ix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (alpha,x,1), jx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (alpha,x,1), yx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (alpha,x,1), ix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp (I*x), 100*eps)
 %!
 %!assert (besselj (-alpha,x), -jx, 100*eps)
 %!assert (bessely (-alpha,x), -yx, 100*eps)
@@ -954,12 +954,12 @@
 %!assert (besselh (-alpha,1,x), -(jx + I*yx), 100*eps)
 %!assert (besselh (-alpha,2,x), -(jx - I*yx), 100*eps)
 %!
-%!assert (besselj (-alpha,x,1), -jx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (-alpha,x,1), -yx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (-alpha,x,1), ix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (-alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (-alpha,1,x,1), -(jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (-alpha,2,x,1), -(jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (-alpha,x,1), -jx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (-alpha,x,1), -yx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (-alpha,x,1), ix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (-alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (-alpha,1,x,1), -(jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (-alpha,2,x,1), -(jx - I*yx)*exp (I*x), 100*eps)
 %!
 %! ## Bessel functions, fractional order, complex x
 %!
@@ -976,12 +976,12 @@
 %!assert (besselh (alpha,1,x), jx + I*yx, 100*eps)
 %!assert (besselh (alpha,2,x), jx - I*yx, 100*eps)
 %!
-%!assert (besselj (alpha,x,1), jx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (alpha,x,1), yx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (alpha,x,1), ix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (alpha,x,1), jx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (alpha,x,1), yx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (alpha,x,1), ix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp (I*x), 100*eps)
 %!
 %! nix = 0.09822388691172060573913739253 - 0.7110230642207380127317227407*I;
 %!
@@ -992,12 +992,12 @@
 %!assert (besselh (-alpha,1,x), -I*(jx + I*yx), 100*eps)
 %!assert (besselh (-alpha,2,x), I*(jx - I*yx), 100*eps)
 %!
-%!assert (besselj (-alpha,x,1), yx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (-alpha,x,1), -jx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (-alpha,x,1), nix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (-alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (-alpha,1,x,1), -I*(jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (-alpha,2,x,1), I*(jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (-alpha,x,1), yx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (-alpha,x,1), -jx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (-alpha,x,1), nix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (-alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (-alpha,1,x,1), -I*(jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (-alpha,2,x,1), I*(jx - I*yx)*exp (I*x), 100*eps)
 
 Tests contributed by Robert T. Short.
 Tests are based on the properties and tables in A&S:
--- a/libinterp/corefcn/bsxfun.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/bsxfun.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -540,7 +540,7 @@
                         {
                           have_NDArray = false;
                           C = result_NDArray;
-                          C = do_cat_op (C, tmp(0), ra_idx);
+                          C = octave::cat_op (C, tmp(0), ra_idx);
                         }
                       else if (tmp(0).isreal ())
                         result_NDArray.insert (tmp(0).array_value (), ra_idx);
@@ -560,7 +560,7 @@
                         {
                           have_FloatNDArray = false;
                           C = result_FloatNDArray;
-                          C = do_cat_op (C, tmp(0), ra_idx);
+                          C = octave::cat_op (C, tmp(0), ra_idx);
                         }
                       else if (tmp(0).isreal ())
                         result_FloatNDArray.insert
@@ -583,7 +583,7 @@
                         {                                               \
                           have_ ## T = false;                           \
                           C = result_ ## T;                             \
-                          C = do_cat_op (C, tmp(0), ra_idx);            \
+                          C = octave::cat_op (C, tmp(0), ra_idx);       \
                         }                                               \
                       else                                              \
                         result_ ## T .insert (tmp(0). EXTRACTOR ## _array_value (), ra_idx); \
@@ -601,7 +601,7 @@
                   else if BSXLOOP(uint32NDArray, "uint32", uint32)
                   else if BSXLOOP(uint64NDArray, "uint64", uint64)
                   else
-                    C = do_cat_op (C, tmp(0), ra_idx);
+                    C = octave::cat_op (C, tmp(0), ra_idx);
                 }
             }
 
@@ -637,12 +637,12 @@
 %! b = mean (a, 1);
 %! c = mean (a, 2);
 %! f = @minus;
-%!error (bsxfun (f))
-%!error (bsxfun (f, a))
-%!error (bsxfun (a, b))
-%!error (bsxfun (a, b, c))
-%!error (bsxfun (f, a, b, c))
-%!error (bsxfun (f, ones (4, 0), ones (4, 4)))
+%!error bsxfun (f)
+%!error bsxfun (f, a)
+%!error bsxfun (a, b)
+%!error bsxfun (a, b, c)
+%!error bsxfun (f, a, b, c)
+%!error bsxfun (f, ones (4, 0), ones (4, 4))
 %!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0))
 %!assert (bsxfun (f, ones (1, 4), ones (4, 1)), zeros (4, 4))
 %!assert (bsxfun (f, a, b), a - repmat (b, 4, 1))
@@ -655,12 +655,12 @@
 %! b = mean (a, 1);
 %! c = mean (a, 2);
 %! f = @minus;
-%!error (bsxfun (f))
-%!error (bsxfun (f, a))
-%!error (bsxfun (a, b))
-%!error (bsxfun (a, b, c))
-%!error (bsxfun (f, a, b, c))
-%!error (bsxfun (f, ones (4, 0), ones (4, 4)))
+%!error bsxfun (f)
+%!error bsxfun (f, a)
+%!error bsxfun (a, b)
+%!error bsxfun (a, b, c)
+%!error bsxfun (f, a, b, c)
+%!error bsxfun (f, ones (4, 0), ones (4, 4))
 %!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0))
 %!assert (bsxfun (f, ones (1, 4), ones (4, 1)), zeros (4, 4))
 %!assert (bsxfun (f, a, b), a - repmat (b, 4, 1))
@@ -673,12 +673,12 @@
 %! b = mean (a, 1);
 %! c = mean (a, 2);
 %! f = @minus;
-%!error (bsxfun (f))
-%!error (bsxfun (f, a))
-%!error (bsxfun (a, b))
-%!error (bsxfun (a, b, c))
-%!error (bsxfun (f, a, b, c))
-%!error (bsxfun (f, ones (4, 0), ones (4, 4)))
+%!error bsxfun (f)
+%!error bsxfun (f, a)
+%!error bsxfun (a, b)
+%!error bsxfun (a, b, c)
+%!error bsxfun (f, a, b, c)
+%!error bsxfun (f, ones (4, 0), ones (4, 4))
 %!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0))
 %!assert (bsxfun (f, ones (1, 4), ones (4, 1)), zeros (4, 4))
 %!assert (bsxfun (f, a, b), a - repmat (b, 4, 1))
@@ -690,12 +690,12 @@
 %! b = a (1, :);
 %! c = a (:, 1);
 %! f = @(x, y) x == y;
-%!error (bsxfun (f))
-%!error (bsxfun (f, a))
-%!error (bsxfun (a, b))
-%!error (bsxfun (a, b, c))
-%!error (bsxfun (f, a, b, c))
-%!error (bsxfun (f, ones (4, 0), ones (4, 4)))
+%!error bsxfun (f)
+%!error bsxfun (f, a)
+%!error bsxfun (a, b)
+%!error bsxfun (a, b, c)
+%!error bsxfun (f, a, b, c)
+%!error bsxfun (f, ones (4, 0), ones (4, 4))
 %!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0, "logical"))
 %!assert (bsxfun (f, ones (1, 4), ones (4, 1)), ones (4, 4, "logical"))
 %!assert (bsxfun (f, a, b), a == repmat (b, 4, 1))
@@ -707,7 +707,7 @@
 %! c = mean (a, 2);
 %! d = mean (a, 3);
 %! f = @minus;
-%!error (bsxfun (f, ones ([4, 0, 4]), ones ([4, 4, 4])))
+%!error bsxfun (f, ones ([4, 0, 4]), ones ([4, 4, 4]))
 %!assert (bsxfun (f, ones ([4, 0, 4]), ones ([4, 1, 4])), zeros ([4, 0, 4]))
 %!assert (bsxfun (f, ones ([4, 4, 0]), ones ([4, 1, 1])), zeros ([4, 4, 0]))
 %!assert (bsxfun (f, ones ([1, 4, 4]), ones ([4, 1, 4])), zeros ([4, 4, 4]))
--- a/libinterp/corefcn/call-stack.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/call-stack.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -823,7 +823,7 @@
 
   void call_stack::clear_global_variable_regexp (const std::string& pattern)
   {
-    octave::regexp pat (pattern);
+    regexp pat (pattern);
 
     for (auto& nm_ov : m_global_values)
       {
@@ -968,14 +968,13 @@
         // implement this option there so that the variables are never
         // stored at all.
 
-        unwind_protect frame;
-
         // Set up temporary scope.
 
         symbol_scope tmp_scope ("$dummy_scope$");
 
         push (tmp_scope);
-        frame.add_method (*this, &call_stack::pop);
+
+        unwind_action restore_scope ([=] (void) { pop (); });
 
         feval ("load", octave_value (file_name), 0);
 
@@ -1025,7 +1024,7 @@
 
         if (have_regexp)
           {
-            octave::regexp pat (pattern);
+            regexp pat (pattern);
 
             for (auto& nm_ov : m_global_values)
               {
@@ -1162,7 +1161,7 @@
 %! max_stack_depth (orig_val);
 %! assert (max_stack_depth (), orig_val);
 
-%!error (max_stack_depth (1, 2))
+%!error max_stack_depth (1, 2)
 */
 
 DEFMETHOD (who, interp, args, nargout,
--- a/libinterp/corefcn/cellfun.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/cellfun.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -1259,7 +1259,7 @@
               for (int j = 0; j < nargin; j++)
                 {
                   if (mask[j])
-                    inputlist.xelem (j) = inputs[j].do_index_op (idx_list);
+                    inputlist.xelem (j) = inputs[j].index_op (idx_list);
                 }
 
               const octave_value_list tmp
@@ -1351,7 +1351,7 @@
               for (int j = 0; j < nargin; j++)
                 {
                   if (mask[j])
-                    inputlist.xelem (j) = inputs[j].do_index_op (idx_list);
+                    inputlist.xelem (j) = inputs[j].index_op (idx_list);
                 }
 
               const octave_value_list tmp
@@ -1579,14 +1579,14 @@
 %! A = arrayfun (@(x,y) x.a:y.a, a, b, "UniformOutput", false);
 %! assert (isequal (A, {[1.1, 2.1, 3.1]}));
 %!test
-%! A = arrayfun (@(x) mat2str(x), "a", "ErrorHandler", @__arrayfunerror);
+%! A = arrayfun (@(x) mat2str (x), "a", "ErrorHandler", @__arrayfunerror);
 %! assert (isfield (A, "identifier"), true);
 %! assert (isfield (A, "message"), true);
 %! assert (isfield (A, "index"), true);
 %! assert (isempty (A.message), false);
 %! assert (A.index, 1);
 %!test  # Overwriting setting of "UniformOutput" true
-%! A = arrayfun (@(x) mat2str(x), "a", "UniformOutput", true, ...
+%! A = arrayfun (@(x) mat2str (x), "a", "UniformOutput", true, ...
 %!               "ErrorHandler", @__arrayfunerror);
 %! assert (isfield (A, "identifier"), true);
 %! assert (isfield (A, "message"), true);
@@ -2100,7 +2100,7 @@
       for (int i = 0; i < nd; i++)
         ra_idx(i) = idx[i][ridx[i]];
 
-      retval.xelem (j) = a.do_index_op (ra_idx);
+      retval.xelem (j) = a.index_op (ra_idx);
 
       rdv.increment_index (ridx);
     }
@@ -2434,8 +2434,8 @@
       octave_value_list idx (ndims, octave_value::magic_colon_t);
       for (octave_idx_type i = 0; i < n; i++)
         {
-          idx(dim) = Range (lb(i), ub(i));
-          retcell.xelem (i) = x.do_index_op (idx);
+          idx(dim) = octave::range<double> (lb(i), ub(i));
+          retcell.xelem (i) = x.index_op (idx);
         }
     }
 
@@ -2486,7 +2486,7 @@
 
       octave_value tmp = x(i);
 
-      y.xelem (i) = tmp.do_index_op (idx);
+      y.xelem (i) = tmp.index_op (idx);
     }
 
   return octave_value (y);
--- a/libinterp/corefcn/chol.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/chol.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -581,11 +581,11 @@
 %! sparse_chol2inv (B, eps*100);
 
 %!testif HAVE_CHOLMOD
-%! C = gallery("tridiag", 5);
+%! C = gallery ("tridiag", 5);
 %! sparse_chol2inv (C, eps*10);
 
 %!testif HAVE_CHOLMOD
-%! D = gallery("wathen", 1, 1);
+%! D = gallery ("wathen", 1, 1);
 %! sparse_chol2inv (D, eps*10^4);
 
 */
--- a/libinterp/corefcn/colamd.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/colamd.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -692,6 +692,15 @@
       ridx = scm.xridx ();
       cidx = scm.xcidx ();
     }
+  else if (args(0).islogical ())
+    {
+      SparseBoolMatrix sbm = args(0).sparse_bool_matrix_value ();
+
+      n_row = sbm.rows ();
+      n_col = sbm.cols ();
+      ridx = sbm.xridx ();
+      cidx = sbm.xcidx ();
+    }
   else
     {
       SparseMatrix sm = args(0).sparse_matrix_value ();
@@ -763,8 +772,10 @@
 }
 
 /*
-%!assert (etree (speye (2)), [0, 0]);
-%!assert (etree (gallery ("poisson", 16)), [2:256, 0]);
+%!assert (etree (sparse ([1,2], [1,2], [1,1], 2, 2)), [0, 0])
+%!assert (etree (sparse ([1,2], [1,2], [true, true], 2, 2)), [0, 0])
+%!assert (etree (sparse ([1,2], [1,2], [i,i], 2, 2)), [0, 0])
+%!assert (etree (gallery ("poisson", 16)), [2:256, 0])
 
 %!error etree ()
 %!error etree (1, 2, 3)
--- a/libinterp/corefcn/conv2.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/conv2.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -550,18 +550,18 @@
 %!    925  1976  2363  1971  1636  1600  1844  2239  1664   626
 %!    372  1133  1558  1687  1570  1401  1243  1122   883   264
 %!     60   270   556   857  1024   870   569   282    66     0];
-%!assert (convn(a, b, "full"), c)
-%!assert (convn(a, b, "same"), c(3:6,2:9,2:5,:))
-%!assert (convn(a, b, "valid"), c(4,3:8,3:4,:))
+%!assert (convn (a, b, "full"), c)
+%!assert (convn (a, b, "same"), c(3:6,2:9,2:5,:))
+%!assert (convn (a, b, "valid"), c(4,3:8,3:4,:))
 
 ## test correct class
-%!assert (class (convn (rand(5), rand(3))), "double")
-%!assert (class (convn (rand(5, "single"), rand(3))), "single")
-%!assert (class (convn (rand(5), rand(3, "single"))), "single")
-%!assert (class (convn (true (5), rand(3))), "double")
-%!assert (class (convn (true (5), rand(3, "single"))), "single")
-%!assert (class (convn (ones(5, "uint8"), rand(3))), "double")
-%!assert (class (convn (rand (3, "single"), ones(5, "uint8"))), "single")
+%!assert (class (convn (rand (5), rand (3))), "double")
+%!assert (class (convn (rand (5, "single"), rand (3))), "single")
+%!assert (class (convn (rand (5), rand (3, "single"))), "single")
+%!assert (class (convn (true (5), rand (3))), "double")
+%!assert (class (convn (true (5), rand (3, "single"))), "single")
+%!assert (class (convn (ones (5, "uint8"), rand (3))), "double")
+%!assert (class (convn (rand (3, "single"), ones (5, "uint8"))), "single")
 
 %!error convn ()
 %!error convn (1)
--- a/libinterp/corefcn/daspk.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/daspk.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -269,9 +269,7 @@
 
   octave_value_list retval (4);
 
-  octave::unwind_protect frame;
-
-  frame.protect_var (call_depth);
+  octave::unwind_protect_var<int> restore_var (call_depth);
   call_depth++;
 
   if (call_depth > 1)
--- a/libinterp/corefcn/dasrt.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/dasrt.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -348,9 +348,7 @@
 
   octave_value_list retval (5);
 
-  octave::unwind_protect frame;
-
-  frame.protect_var (call_depth);
+  octave::unwind_protect_var<int> restore_var (call_depth);
   call_depth++;
 
   if (call_depth > 1)
--- a/libinterp/corefcn/dassl.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/dassl.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -269,9 +269,7 @@
 
   octave_value_list retval (4);
 
-  octave::unwind_protect frame;
-
-  frame.protect_var (call_depth);
+  octave::unwind_protect_var<int> restore_var (call_depth);
   call_depth++;
 
   if (call_depth > 1)
--- a/libinterp/corefcn/data.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/data.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -889,7 +889,7 @@
 %!assert (mod (uint8 (5), uint8 (4)), uint8 (1))
 %!assert (mod (uint8 ([1:5]), uint8 (4)), uint8 ([1,2,3,0,1]))
 %!assert (mod (uint8 ([1:5]), uint8 (0)), uint8 ([1:5]))
-%!error (mod (uint8 (5), int8 (4)))
+%!error mod (uint8 (5), int8 (4))
 
 ## mixed integer/real types
 %!assert (mod (uint8 (5), 4), uint8 (1))
@@ -1040,8 +1040,8 @@
 @end group
 @end example
 
-See @code{sum} for an explanation of the optional parameters @qcode{"native"}
-and @qcode{"double"}.
+For an explanation of the optional parameters @qcode{"native"} and
+@qcode{"double"}, @pxref{XREFsum,,@code{sum}}.
 @seealso{sum, cumprod}
 @end deftypefn */)
 {
@@ -1955,7 +1955,7 @@
               // Can't fast return here to skip empty matrices as something
               // like cat (1,[],single ([])) must return an empty matrix of
               // the right type.
-              tmp = do_cat_op (tmp, args(j), ra_idx);
+              tmp = octave::cat_op (tmp, args(j), ra_idx);
 
               dim_vector dv_tmp = args(j).dims ();
 
@@ -2213,8 +2213,8 @@
 
 %!error horzcat (struct ("foo", "bar"), cell (1))
 
-%!test <*39041> assert (class (horzcat (cell(0), struct())), "cell")
-%!test <51086> assert (class (horzcat (struct(), cell(0))), "struct")
+%!test <*39041> assert (class (horzcat (cell (0), struct ())), "cell")
+%!test <51086> assert (class (horzcat (struct (), cell (0))), "struct")
 */
 
 DEFUN (vertcat, args, ,
@@ -2796,10 +2796,10 @@
 %!assert (nnz (-5:0), 5)
 %!assert (nnz (-5:5), 10)
 %!assert (nnz (-2:1:2), 4)
-%!assert (nnz (-2+eps(2):1:2), 5)
-%!assert (nnz (-2-eps(2):1:2), 5)
-%!assert (nnz (-2:1+eps(1):2), 5)
-%!assert (nnz (-2:1-eps(1):2), 5)
+%!assert (nnz (-2+eps (2):1:2), 5)
+%!assert (nnz (-2-eps (2):1:2), 5)
+%!assert (nnz (-2:1+eps (1):2), 5)
+%!assert (nnz (-2:1-eps (1):2), 5)
 %!assert (nnz ([1:5] * 0), 0)
 %!assert (nnz ([-5:-1] * 0), 0)
 %!assert (nnz ([-1:1] * 0), 0)
@@ -3631,7 +3631,7 @@
 
 /*
 ## Debian bug #706376
-%!assert (isempty (speye(2^16)), false)
+%!assert (isempty (speye (2^16)), false)
 */
 
 DEFUN (isnumeric, args, ,
@@ -4023,7 +4023,13 @@
     case oct_data_conv::dt_double:
       {
         if (dims.ndims () == 2 && dims(0) == 1)
-          retval = Range (static_cast<double> (val), 0.0, dims(1));
+          {
+            // FIXME: If this optimization provides a significant
+            // benefit, then maybe there should be a special storage
+            // type for constant value arrays.
+            double dval = static_cast<double> (val);
+            retval = octave::range<double>::make_constant (dval, dims(1));
+          }
         else
           retval = NDArray (dims, val);
       }
@@ -4095,7 +4101,10 @@
 
     case oct_data_conv::dt_double:
       if (dims.ndims () == 2 && dims(0) == 1 && octave::math::isfinite (val))
-        retval = Range (val, 0.0, dims(1));  // Packed form
+        // FIXME: If this optimization provides a significant benefit,
+        // then maybe there should be a special storage type for
+        // constant value arrays.
+        retval = octave::range<double>::make_constant (val, dims(1));
       else
         retval = NDArray (dims, val);
       break;
@@ -4161,7 +4170,10 @@
 
     case oct_data_conv::dt_double:
       if (dims.ndims () == 2 && dims(0) == 1 && octave::math::isfinite (val))
-        retval = Range (val, 0.0, dims(1));  // Packed form
+        // FIXME: If this optimization provides a significant benefit,
+        // then maybe there should be a special storage type for
+        // constant value arrays.
+        retval = octave::range<double>::make_constant (val, dims(1));
       else
         retval = NDArray (dims, val);
       break;
@@ -4248,6 +4260,18 @@
 
   dim_vector dims (1, 1);
 
+  // The TYPE argument is required to be "logical" if present.  This
+  // feature appears to be undocumented in Matlab.
+
+  if (nargin > 0 && args(nargin-1).is_string ())
+    {
+      std::string nm = args(nargin-1).string_value ();
+      nargin--;
+
+      if (oct_data_conv::string_to_data_type (nm) != oct_data_conv::dt_logical)
+        error ("%s: invalid data type '%s'", fcn, nm.c_str ());
+    }
+
   switch (nargin)
     {
     case 0:
@@ -4461,10 +4485,10 @@
 %!assert (inf (3, 2, "single"), single ([Inf, Inf; Inf, Inf; Inf, Inf]))
 %!assert (size (inf (3, 4, 5, "single")), [3, 4, 5])
 
-%!error (inf (3, "int8"))
-%!error (inf (2, 3, "int8"))
-%!error (inf (3, 2, "int8"))
-%!error (inf (3, 4, 5, "int8"))
+%!error inf (3, "int8")
+%!error inf (2, 3, "int8")
+%!error inf (3, 2, "int8")
+%!error inf (3, 4, 5, "int8")
 */
 
 DEFUN (NaN, args, ,
@@ -4526,10 +4550,10 @@
 %!assert (NaN (3, 2, "single"), single ([NaN, NaN; NaN, NaN; NaN, NaN]))
 %!assert (size (NaN (3, 4, 5, "single")), [3, 4, 5])
 
-%!error (NaN (3, "int8"))
-%!error (NaN (2, 3, "int8"))
-%!error (NaN (3, 2, "int8"))
-%!error (NaN (3, 4, 5, "int8"))
+%!error NaN (3, "int8")
+%!error NaN (2, 3, "int8")
+%!error NaN (3, 2, "int8")
+%!error NaN (3, 4, 5, "int8")
 */
 
 DEFUN (e, args, ,
@@ -4908,6 +4932,12 @@
   return fill_matrix (args, false, "false");
 }
 
+/*
+%!assert (false (2, 3), logical (zeros (2, 3)))
+%!assert (false (2, 3, "logical"), logical (zeros (2, 3)))
+%!error false (2, 3, "double")
+*/
+
 DEFUN (true, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn  {} {} true (@var{x})
@@ -4926,6 +4956,12 @@
   return fill_matrix (args, true, "true");
 }
 
+/*
+%!assert (true (2, 3), logical (ones (2, 3)))
+%!assert (true (2, 3, "logical"), logical (ones (2, 3)))
+%!error true (2, 3, "double")
+*/
+
 template <typename MT>
 octave_value
 identity_matrix (int nr, int nc)
@@ -5931,7 +5967,7 @@
   if (args.length () != 1)
     print_usage ();
 
-  return do_unary_op (op, args(0));
+  return octave::unary_op (op, args(0));
 }
 
 DEFUN (not, args, ,
@@ -6037,7 +6073,7 @@
   if (args.length () != 2)
     print_usage ();
 
-  return do_binary_op (op, args(0), args(1));
+  return octave::binary_op (op, args(0), args(1));
 }
 
 static octave_value
@@ -6053,10 +6089,10 @@
   octave_value retval;
 
   if (nargin == 2)
-    retval = do_binary_op (op, args(0), args(1));
+    retval = octave::binary_op (op, args(0), args(1));
   else
     {
-      retval = do_binary_op (op, args(0), args(1));
+      retval = octave::binary_op (op, args(0), args(1));
 
       for (int i = 2; i < nargin; i++)
         retval.assign (aop, args(i));
@@ -6351,8 +6387,9 @@
   if (nargin < 2 || nargin > 3)
     print_usage ();
 
-  return (nargin == 2 ? do_colon_op (args(0), args(1))
-                      : do_colon_op (args(0), args(1), args(2)));
+  return (nargin == 2
+          ? octave::colon_op (args(0), args(1))
+          : octave::colon_op (args(0), args(1), args(2)));
 }
 
 static double tic_toc_timestamp = -1.0;
@@ -6471,7 +6508,7 @@
     }
 
   if (start_time < 0)
-    error ("toc called before timer set");
+    error ("toc: function called before timer initialization with tic()");
 
   octave::sys::time now;
 
@@ -7195,8 +7232,8 @@
 
       if (vals.is_range ())
         {
-          Range r = vals.range_value ();
-          if (r.inc () == 0)
+          octave::range<double> r = vals.range_value ();
+          if (r.increment () == 0)
             vals = r.base ();
         }
 
@@ -7941,7 +7978,7 @@
 Encode a double matrix or array @var{x} into the base64 format string
 @var{s}.
 
-@seealso{base64_decode}
+@seealso{base64_decode, matlab.net.base64decode, matlab.net.base64encode}
 @end deftypefn */)
 {
   if (args.length () != 1)
@@ -8049,7 +8086,7 @@
 
 The optional input parameter @var{dims} should be a vector containing the
 dimensions of the decoded array.
-@seealso{base64_encode}
+@seealso{base64_encode, matlab.net.base64decode, matlab.net.base64encode}
 @end deftypefn */)
 {
   int nargin = args.length ();
@@ -8095,3 +8132,57 @@
 %!error <input was not valid base64> base64_decode ("AQ=")
 %!error <incorrect input size> base64_decode ("AQ==")
 */
+
+DEFUN (__base64_decode_bytes__, args, ,
+       doc: /* -*- texinfo -*-
+@deftypefn  {} {@var{x} =} base64_decode_bytes (@var{s})
+@deftypefnx {} {@var{x} =} base64_decode_bytes (@var{s}, @var{dims})
+Decode the uint8 matrix or array @var{x} from the base64 encoded string
+@var{s}.
+
+The optional input parameter @var{dims} should be a vector containing the
+dimensions of the decoded array.
+@seealso{base64_decode}
+@end deftypefn */)
+{
+  int nargin = args.length ();
+
+  if (nargin < 1 || nargin > 2)
+    print_usage ();
+
+  std::string str = args(0).string_value ();
+
+  intNDArray<octave_uint8> retval = octave::base64_decode_bytes (str);
+
+  if (nargin == 2)
+    {
+      dim_vector dims;
+
+      const Array<octave_idx_type> size
+        = args(1).octave_idx_type_vector_value ();
+
+      dims = dim_vector::alloc (size.numel ());
+      for (octave_idx_type i = 0; i < size.numel (); i++)
+        dims(i) = size(i);
+
+      retval = retval.reshape (dims);
+    }
+
+  return ovl (retval);
+}
+
+/*
+%!assert (__base64_decode_bytes__ (base64_encode (uint8 (1))), uint8 (1))
+
+%!test
+%! in   = uint8 (rand (10)*255);
+%! outv = __base64_decode_bytes__ (base64_encode (in));
+%! outm = __base64_decode_bytes__ (base64_encode (in), size (in));
+%! assert (outv, in(:).');
+%! assert (outm, in);
+
+%!error __base64_decode_bytes__ ()
+%!error __base64_decode_bytes__ (1,2,3)
+%!error __base64_decode_bytes__ (1, "this is not a valid set of dimensions")
+%!error <input was not valid base64> __base64_decode_bytes__ (1)
+*/
--- a/libinterp/corefcn/debug.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/debug.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -222,10 +222,7 @@
                   && bkpt.cell_value () (0).isstruct ())
                 mv = bkpt.cell_value () (0).map_value ();
               else
-                {
-                  error ("dbstop: invalid 'bkpt' field");
-                  mv = octave_map ();
-                }
+                error ("dbstop: invalid 'bkpt' field");
             }
         }
       if (mv.isempty ())
@@ -235,7 +232,6 @@
       else if (! mv.isfield ("name") || ! mv.isfield ("line"))
         {
           error ("dbstop: Cell array must contain fields 'name' and 'line'");
-          retval = octave_value (0);
         }
       else
         {
@@ -293,7 +289,7 @@
 
 @item event
 An event such as @code{error}, @code{interrupt}, or @code{warning}
-(@pxref{XREFdbstop,,dbstop} for details).
+(@pxref{XREFdbstop,,@code{dbstop}} for details).
 @end table
 
 When called without a line number specification all breakpoints in the named
@@ -838,8 +834,6 @@
 
   octave_value_list retval;
 
-  octave::unwind_protect frame;
-
   octave_idx_type curr_frame = -1;
 
   size_t nskip = 0;
--- a/libinterp/corefcn/dirfns.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/dirfns.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -224,7 +224,7 @@
     }
 }
 
-DEFMETHODX ("rmdir", Frmdir, interp, args, ,
+DEFMETHODX ("rmdir", Frmdir, interp, args, nargout,
             doc: /* -*- texinfo -*-
 @deftypefn  {} {} rmdir @var{dir}
 @deftypefnx {} {} rmdir (@var{dir}, "s")
@@ -250,6 +250,7 @@
   std::string dirname = args(0).xstring_value ("rmdir: DIR must be a string");
 
   std::string fulldir = octave::sys::file_ops::tilde_expand (dirname);
+  octave_value_list retval;
   int status = -1;
   std::string msg;
 
@@ -287,20 +288,30 @@
 
   evmgr.file_renamed (status >= 0);
 
-  if (status < 0)
-    return ovl (false, msg, "rmdir");
+  if (nargout == 0)
+    {
+      if (status < 0)
+        error ("rmdir: operation failed: %s", msg.c_str ());
+    }
   else
-    return ovl (true, "", "");
+    {
+      if (status < 0)
+        retval = ovl (0.0, msg, "rmdir");
+      else
+        retval = ovl (1.0, "", "");
+    }
+
+  return retval;
 }
 
-DEFUNX ("link", Flink, args, ,
+DEFUNX ("link", Flink, args, nargout,
         doc: /* -*- texinfo -*-
 @deftypefn  {} {} link @var{old} @var{new}
-@deftypefnx {} {[@var{err}, @var{msg}] =} link (@var{old}, @var{new})
+@deftypefnx {} {[@var{status}, @var{msg}] =} link (@var{old}, @var{new})
 Create a new link (also known as a hard link) to an existing file.
 
-If successful, @var{err} is 0 and @var{msg} is an empty string.
-Otherwise, @var{err} is nonzero and @var{msg} contains a system-dependent
+If successful, @var{status} is 0 and @var{msg} is an empty string.
+Otherwise, @var{status} is -1 and @var{msg} contains a system-dependent
 error message.
 @seealso{symlink, unlink, readlink, lstat}
 @end deftypefn */)
@@ -314,24 +325,35 @@
   from = octave::sys::file_ops::tilde_expand (from);
   to = octave::sys::file_ops::tilde_expand (to);
 
+  octave_value_list retval;
   std::string msg;
 
   int status = octave::sys::link (from, to, msg);
 
-  if (status < 0)
-    return ovl (-1.0, msg);
+  if (nargout == 0)
+    {
+      if (status < 0)
+        error ("link: operation failed: %s", msg.c_str ());
+    }
   else
-    return ovl (status, "");
+    {
+      if (status < 0)
+        retval = ovl (-1.0, msg);
+      else
+        retval = ovl (0.0, "");
+    }
+
+  return retval;
 }
 
-DEFUNX ("symlink", Fsymlink, args, ,
+DEFUNX ("symlink", Fsymlink, args, nargout,
         doc: /* -*- texinfo -*-
 @deftypefn  {} {} symlink @var{old} @var{new}
-@deftypefnx {} {[@var{err}, @var{msg}] =} symlink (@var{old}, @var{new})
+@deftypefnx {} {[@var{status}, @var{msg}] =} symlink (@var{old}, @var{new})
 Create a symbolic link @var{new} which contains the string @var{old}.
 
-If successful, @var{err} is 0 and @var{msg} is an empty string.
-Otherwise, @var{err} is nonzero and @var{msg} contains a system-dependent
+If successful, @var{status} is 0 and @var{msg} is an empty string.
+Otherwise, @var{status} is -1 and @var{msg} contains a system-dependent
 error message.
 @seealso{link, unlink, readlink, lstat}
 @end deftypefn */)
@@ -345,14 +367,25 @@
   from = octave::sys::file_ops::tilde_expand (from);
   to = octave::sys::file_ops::tilde_expand (to);
 
+  octave_value_list retval;
   std::string msg;
 
   int status = octave::sys::symlink (from, to, msg);
 
-  if (status < 0)
-    return ovl (-1.0, msg);
+  if (nargout == 0)
+    {
+      if (status < 0)
+        error ("symlink: operation failed: %s", msg.c_str ());
+    }
   else
-    return ovl (status, "");
+    {
+      if (status < 0)
+        retval = ovl (-1.0, msg);
+      else
+        retval = ovl (0.0, "");
+    }
+
+  return retval;
 }
 
 DEFUNX ("readlink", Freadlink, args, ,
@@ -385,14 +418,14 @@
     return ovl (result, status, "");
 }
 
-DEFMETHODX ("rename", Frename, interp, args, ,
+DEFMETHODX ("rename", Frename, interp, args, nargout,
             doc: /* -*- texinfo -*-
 @deftypefn  {} {} rename @var{old} @var{new}
-@deftypefnx {} {[@var{err}, @var{msg}] =} rename (@var{old}, @var{new})
+@deftypefnx {} {[@var{status}, @var{msg}] =} rename (@var{old}, @var{new})
 Change the name of file @var{old} to @var{new}.
 
-If successful, @var{err} is 0 and @var{msg} is an empty string.
-Otherwise, @var{err} is nonzero and @var{msg} contains a system-dependent
+If successful, @var{status} is 0 and @var{msg} is an empty string.
+Otherwise, @var{status} is -1 and @var{msg} contains a system-dependent
 error message.
 @seealso{movefile, copyfile, ls, dir}
 @end deftypefn */)
@@ -406,6 +439,7 @@
   from = octave::sys::file_ops::tilde_expand (from);
   to = octave::sys::file_ops::tilde_expand (to);
 
+  octave_value_list retval;
   std::string msg;
 
   octave::event_manager& evmgr = interp.get_event_manager ();
@@ -414,16 +448,22 @@
 
   int status = octave::sys::rename (from, to, msg);
 
-  if (status < 0)
+  evmgr.file_renamed (status >= 0);
+
+  if (nargout == 0)
     {
-      evmgr.file_renamed (false);
-      return ovl (-1.0, msg);
+      if (status < 0)
+        error ("rename: operation failed: %s", msg.c_str ());
     }
   else
     {
-      evmgr.file_renamed (true);
-      return ovl (status, "");
+      if (status < 0)
+        retval = ovl (-1.0, msg);
+      else
+        retval = ovl (0.0, "");
     }
+
+  return retval;
 }
 
 DEFUN (glob, args, ,
@@ -474,13 +514,18 @@
         [2,1] = file2
       @}
 @end example
+
+Note: On Windows, patterns that contain non-ASCII characters are not
+supported.
+
 @seealso{ls, dir, readdir, what}
 @end deftypefn */)
 {
   if (args.length () != 1)
     print_usage ();
 
-  string_vector pat = args(0).xstring_vector_value ("glob: PATTERN must be a string");
+  string_vector pat
+    = args(0).xstring_vector_value ("glob: PATTERN must be a string");
 
   glob_match pattern (octave::sys::file_ops::tilde_expand (pat));
 
@@ -556,10 +601,10 @@
 
 /*
 %!test
-%! tmpdir = tempname;
+%! tmpdir = tempname ();
 %! filename = {"file1", "file2", "file3", "myfile1", "myfile1b"};
 %! if (mkdir (tmpdir))
-%!   cwd = pwd;
+%!   cwd = pwd ();
 %!   cd (tmpdir);
 %!   if (strcmp (canonicalize_file_name (pwd), canonicalize_file_name (tmpdir)))
 %!     a = 0;
@@ -567,8 +612,8 @@
 %!       save (filename{n}, "a");
 %!     endfor
 %!   else
-%!     rmdir (tmpdir);
-%!     error ("Couldn't change to temporary dir");
+%!     sts = rmdir (tmpdir);
+%!     error ("Couldn't change to temporary directory");
 %!   endif
 %! else
 %!   error ("Couldn't create temporary directory");
@@ -580,7 +625,7 @@
 %!   delete (filename{n});
 %! endfor
 %! cd (cwd);
-%! rmdir (tmpdir);
+%! sts = rmdir (tmpdir);
 %! assert (result1, {"file1"; "myfile1"});
 %! assert (result2, {"myfile1"});
 %! assert (result3, {"file1"; "file2"});
@@ -656,9 +701,7 @@
 @seealso{filesep}
 @end deftypefn */)
 {
-  int nargin = args.length ();
-
-  if (nargin > 0)
+  if (args.length () > 0)
     print_usage ();
 
   return ovl (octave::directory_path::path_sep_str ());
--- a/libinterp/corefcn/dlmread.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/dlmread.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -305,6 +305,32 @@
   bool sep_is_wspace = (sep.find_first_of (" \t") != std::string::npos);
   bool auto_sep_is_wspace = false;
 
+  if (r0 == 0)
+    {
+      // Peek into stream and potentially strip Byte Order Mark (BOM)
+      const char BOM[3] = {'\xEF', '\xBB', '\xBF'};
+      char buf[3];
+      int i_bom;
+      bool found_bom = true;
+      for (i_bom = 0; i_bom < 3; i_bom++)
+        {
+          char ch_p = input->peek ();
+          if (ch_p == BOM[i_bom])
+            buf[i_bom] = input->get ();
+          else
+            {
+              found_bom = false;
+              break;
+            }
+        }
+      // Put back read characters if it wasn't a BOM
+      if (! found_bom)
+        {
+          for (int i_ret = i_bom-1; i_ret >= 0; i_ret--)
+            input->putback (buf[i_ret]);
+        }
+    }
+
   std::string line;
 
   // Skip the r0 leading lines
@@ -443,7 +469,7 @@
           tmp_stream.str (str);
           tmp_stream.clear ();
 
-          double x = octave_read_double (tmp_stream);
+          double x = octave::read_value<double> (tmp_stream);
           if (tmp_stream)
             {
               if (tmp_stream.eof ())
@@ -485,7 +511,7 @@
                     }
                   else
                     {
-                      double y = octave_read_double (tmp_stream);
+                      double y = octave::read_value<double> (tmp_stream);
 
                       if (! iscmplx && y != 0.0)
                         {
@@ -502,7 +528,7 @@
             }
           else
             {
-              // octave_read_double() parsing failed
+              // octave::read_value<double>() parsing failed
               j++;  // Leave data initialized to empty_value
             }
 
@@ -713,4 +739,18 @@
 %!   unlink (file);
 %! end_unwind_protect
 
+## Verify UTF-8 Byte Order Mark does not cause problems with reading
+%!test <*58813>
+%! file = tempname ();
+%! unwind_protect
+%!   fid = fopen (file, "wt");
+%!   fwrite (fid, char ([0xEF, 0xBB, 0xBF]));  # UTF-8 BOM
+%!   fwrite (fid, "1,2\n3,4");
+%!   fclose (fid);
+%!
+%!   assert (dlmread (file), [1, 2; 3, 4]);
+%! unwind_protect_cleanup
+%!   unlink (file);
+%! end_unwind_protect
+
 */
--- a/libinterp/corefcn/dmperm.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/dmperm.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -103,10 +103,9 @@
     {
       CXSPARSE_NAME (d) *dm = CXSPARSE_NAME(_dmperm) (&csm, 0);
 
-      //retval(5) = put_int (dm->rr, 5);
-      //retval(4) = put_int (dm->cc, 5);
       retval = ovl (put_int (dm->p, nr), put_int (dm->q, nc),
-                    put_int (dm->r, dm->nb+1), put_int (dm->s, dm->nb+1));
+                    put_int (dm->r, dm->nb+1), put_int (dm->s, dm->nb+1),
+                    put_int (dm->cc, 5), put_int (dm->rr, 5));
 
       CXSPARSE_NAME (_dfree) (dm);
     }
@@ -116,23 +115,68 @@
 
 #endif
 
+// NOTE: the docstring for dmperm is adapted from the text found in the
+// file cs_dmperm.m that is distributed with the CSparse portion of the
+// SuiteSparse library, version 5.6.0.  CSparse is distributed under the
+// terms of the LGPL v2.1 or any later version.
+
 DEFUN (dmperm, args, nargout,
        doc: /* -*- texinfo -*-
-@deftypefn  {} {@var{p} =} dmperm (@var{S})
-@deftypefnx {} {[@var{p}, @var{q}, @var{r}, @var{S}] =} dmperm (@var{S})
+@deftypefn  {} {@var{p} =} dmperm (@var{A})
+@deftypefnx {} {[@var{p}, @var{q}, @var{r}, @var{s}, @var{cc}, @var{rr}] =} dmperm (@var{A})
 
 @cindex @nospell{Dulmage-Mendelsohn} decomposition
 Perform a @nospell{Dulmage-Mendelsohn} permutation of the sparse matrix
-@var{S}.
+@var{A}.
+
+With a single output argument @code{dmperm}, return a maximum matching @var{p}
+such that @code{p(j) = i} if column @var{j} is matched to row @var{i}, or 0 if
+column @var{j} is unmatched.  If @var{A} is square and full structural rank,
+@var{p} is a row permutation and @code{A(p,:)} has a zero-free diagonal.  The
+structural rank of @var{A} is @code{sprank(A) = sum(p>0)}.
+
+Called with two or more output arguments, return the
+@nospell{Dulmage-Mendelsohn} decomposition of @var{A}.  @var{p} and @var{q} are
+permutation vectors.  @var{cc} and @var{rr} are vectors of length 5.
+@code{c = A(p,q)} is split into a 4-by-4 set of coarse blocks:
+
+@example
+@group
+   A11 A12 A13 A14
+    0  0   A23 A24
+    0  0    0  A34
+    0  0    0  A44
+@end group
+@end example
 
-With a single output argument @code{dmperm} performs the row permutations
-@var{p} such that @code{@var{S}(@var{p},:)} has no zero elements on the
-diagonal.
+@noindent
+where @code{A12}, @code{A23}, and @code{A34} are square with zero-free
+diagonals.  The columns of @code{A11} are the unmatched columns, and the rows
+of @code{A44} are the unmatched rows.  Any of these blocks can be empty.  In
+the "coarse" decomposition, the (i,j)-th block is
+@code{C(rr(i):rr(i+1)-1,cc(j):cc(j+1)-1)}.  In terms of a linear system,
+@code{[A11 A12]} is the underdetermined part of the system (it is always
+rectangular and with more columns and rows, or 0-by-0), @code{A23} is the
+well-determined part of the system (it is always square), and
+@code{[A34 ; A44]} is the over-determined part of the system (it is always
+rectangular with more rows than columns, or 0-by-0).
 
-Called with two or more output arguments, returns the row and column
-permutations, such that @code{@var{S}(@var{p}, @var{q})} is in block
-triangular form.  The values of @var{r} and @var{S} define the boundaries
-of the blocks.  If @var{S} is square then @code{@var{r} == @var{S}}.
+The structural rank of @var{A} is @code{sprank (A) = rr(4)-1}, which is an
+upper bound on the numerical rank of @var{A}.
+@code{sprank(A) = rank(full(sprand(A)))} with probability 1 in exact
+arithmetic.
+
+The @code{A23} submatrix is further subdivided into block upper triangular form
+via the "fine" decomposition (the strongly-connected components of @code{A23}).
+If @var{A} is square and structurally non-singular, @code{A23} is the entire
+matrix.
+
+@code{C(r(i):r(i+1)-1,s(j):s(j+1)-1)} is the (i,j)-th block of the fine
+decomposition.  The (1,1) block is the rectangular block @code{[A11 A12]},
+unless this block is 0-by-0.  The (b,b) block is the rectangular block
+@code{[A34 ; A44]}, unless this block is 0-by-0, where @code{b = length(r)-1}.
+All other blocks of the form @code{C(r(i):r(i+1)-1,s(i):s(i+1)-1)} are diagonal
+blocks of @code{A23}, and are square with a zero-free diagonal.
 
 The method used is described in: @nospell{A. Pothen & C.-J. Fan.}
 @cite{Computing the Block Triangular Form of a Sparse Matrix}.
--- a/libinterp/corefcn/dot.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/dot.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -190,7 +190,7 @@
       // exceed intmax.
       octave_value_list tmp;
       tmp(1) = dim + 1;
-      tmp(0) = do_binary_op (octave_value::op_el_mul, argx, argy);
+      tmp(0) = octave::binary_op (octave_value::op_el_mul, argx, argy);
 
       tmp = Fsum (tmp, 1);
       if (! tmp.empty ())
--- a/libinterp/corefcn/dynamic-ld.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/dynamic-ld.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -152,11 +152,7 @@
   {
     octave_function *retval = nullptr;
 
-    unwind_protect frame;
-
-    frame.protect_var (m_doing_load);
-
-    m_doing_load = true;
+    unwind_protect_var<bool> restore_var (m_doing_load, true);
 
     dynamic_library oct_file = m_loaded_shlibs.find_file (file_name);
 
@@ -199,18 +195,42 @@
     return retval;
   }
 
+  void *
+  dynamic_loader::try_load_mex (dynamic_library& mex_file,
+                                const std::string& fcn_name, bool& have_fmex)
+  {
+    // FCN_NAME is not used here, the mangler functions always return
+    // some form of "mexFunction".
+
+    have_fmex = false;
+
+    void *function = mex_file.search (fcn_name, mex_mangler);
+
+    if (! function)
+      {
+        // FIXME: Can we determine this C mangling scheme
+        //        automatically at run time or configure time?
+
+        function = mex_file.search (fcn_name, mex_uscore_mangler);
+
+        if (! function)
+          {
+            function = mex_file.search (fcn_name, mex_f77_mangler);
+
+            if (function)
+              have_fmex = true;
+          }
+      }
+
+    return function;
+  }
+
   octave_function *
   dynamic_loader::load_mex (const std::string& fcn_name,
                             const std::string& file_name,
                             bool /*relative*/)
   {
-    octave_function *retval = nullptr;
-
-    unwind_protect frame;
-
-    frame.protect_var (m_doing_load);
-
-    m_doing_load = true;
+    unwind_protect_var<bool> restore_var (m_doing_load, true);
 
     dynamic_library mex_file = m_loaded_shlibs.find_file (file_name);
 
@@ -230,29 +250,17 @@
 
     bool have_fmex = false;
 
-    void *function = mex_file.search (fcn_name, mex_mangler);
-
-    if (! function)
-      {
-        // FIXME: Can we determine this C mangling scheme
-        //        automatically at run time or configure time?
-        function = mex_file.search (fcn_name, mex_uscore_mangler);
-
-        if (! function)
-          {
-            function = mex_file.search (fcn_name, mex_f77_mangler);
-
-            if (function)
-              have_fmex = true;
-          }
-      }
+    void *function = try_load_mex (mex_file, fcn_name, have_fmex);
 
     if (! function)
       error ("failed to install .mex file function '%s'", fcn_name.c_str ());
 
-    retval = new octave_mex_function (function, have_fmex, mex_file, fcn_name);
+    void *symbol = mex_file.search ("__mx_has_interleaved_complex__");
 
-    return retval;
+    bool interleaved = symbol != nullptr;
+
+    return new octave_mex_function (function, interleaved, have_fmex,
+                                    mex_file, fcn_name);
   }
 
   bool
--- a/libinterp/corefcn/dynamic-ld.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/dynamic-ld.h	Thu Nov 19 13:08:00 2020 -0800
@@ -128,6 +128,9 @@
     static std::string mex_uscore_mangler (const std::string& name);
 
     static std::string mex_f77_mangler (const std::string& name);
+
+    static void * try_load_mex (dynamic_library& mex_file,
+                                const std::string& fcn_name, bool& have_fmex);
   };
 }
 
--- a/libinterp/corefcn/eig.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/eig.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -532,22 +532,22 @@
 ## column vector if 1 output is specified
 %!function test_shapes (args)
 %!  d = eig (args{:});
-%!  assert (isvector(d))
+%!  assert (isvector (d))
 %!  d2 = eig (args{:}, "vector");
-%!  assert (isvector(d2))
+%!  assert (isvector (d2))
 %!  [v, d3] = eig (args{:});
-%!  assert (isdiag(d3))
+%!  assert (isdiag (d3))
 %!  d4 = eig (args{:}, "matrix");
-%!  assert (isdiag(d4))
+%!  assert (isdiag (d4))
 %!  [v, d5, w] = eig (args{:});
-%!  assert (isdiag(d5))
+%!  assert (isdiag (d5))
 %!  d6 = eig (args{:}, "matrix");
-%!  assert (isdiag(d6))
+%!  assert (isdiag (d6))
 %!  assert (d, d2)
 %!  assert (d3, d4)
 %!  assert (d5, d6)
-%!  assert (d, diag(d3))
-%!  assert (d, diag(d5))
+%!  assert (d, diag (d3))
+%!  assert (d, diag (d5))
 %!endfunction
 
 %!function shapes_AEP (A)
--- a/libinterp/corefcn/ellipj.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/ellipj.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -338,7 +338,7 @@
 ## tests taken from inst/test_sncndn.m
 
 %!test
-%! k = (tan(pi/8.))^2;  m = k*k;
+%! k = (tan (pi/8))^2;  m = k*k;
 %! SN = [
 %! -1. + I * 0. ,  -0.8392965923 + 0. * I
 %! -1. + I * 0.2 ,  -0.8559363407 + 0.108250955 * I
@@ -729,13 +729,13 @@
 %! assert ([sn,cn,dn], res1, 10*eps);
 
 %!test
-%! u2 = log(2); m2 = 1;
+%! u2 = log (2); m2 = 1;
 %! res2 = [ 3/5, 4/5, 4/5 ];
 %! [sn,cn,dn] = ellipj (u2,m2);
 %! assert ([sn,cn,dn], res2, 10*eps);
 
 %!test
-%! u3 = log(2)*1i; m3 = 0;
+%! u3 = log (2)*1i; m3 = 0;
 %! res3 = [3i/4,5/4,1];
 %! [sn,cn,dn] = ellipj (u3,m3);
 %! assert ([sn,cn,dn], res3, 10*eps);
@@ -747,7 +747,7 @@
 %! assert ([sn,cn,dn], res4, 1e-10);
 
 %!test
-%! u5 = -0.2 + 0.4i; m5 = tan(pi/8)^4;
+%! u5 = -0.2 + 0.4i; m5 = tan (pi/8)^4;
 %! res5 = [ -0.2152524522 + 0.402598347i, ...
 %!           1.059453907  + 0.08179712295i, ...
 %!           1.001705496  + 0.00254669712i ];
@@ -755,7 +755,7 @@
 %! assert ([sn,cn,dn], res5, 1e-9);
 
 %!test
-%! u6 = 0.2 + 0.6i; m6 = tan(pi/8)^4;
+%! u6 = 0.2 + 0.6i; m6 = tan (pi/8)^4;
 %! res6 = [ 0.2369100139 + 0.624633635i, ...
 %!          1.16200643   - 0.1273503824i, ...
 %!          1.004913944  - 0.004334880912i ];
--- a/libinterp/corefcn/environment.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/environment.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -186,7 +186,7 @@
 %! EDITOR (orig_val);
 %! assert (EDITOR (), orig_val);
 
-%!error (EDITOR (1, 2))
+%!error EDITOR (1, 2)
 */
 
 DEFMETHOD (EXEC_PATH, interp, args, nargout,
@@ -223,7 +223,7 @@
 %! EXEC_PATH (orig_val);
 %! assert (EXEC_PATH (), orig_val);
 
-%!error (EXEC_PATH (1, 2))
+%!error EXEC_PATH (1, 2)
 */
 
 DEFMETHOD (IMAGE_PATH, interp, args, nargout,
@@ -255,5 +255,5 @@
 %! IMAGE_PATH (orig_val);
 %! assert (IMAGE_PATH (), orig_val);
 
-%!error (IMAGE_PATH (1, 2))
+%!error IMAGE_PATH (1, 2)
 */
--- a/libinterp/corefcn/error.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/error.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -368,7 +368,7 @@
   static const octave_fields bt_fields (bt_fieldnames);
 
   octave_map
-  error_system::make_stack_map (const std::list<octave::frame_info>& frames)
+  error_system::make_stack_map (const std::list<frame_info>& frames)
   {
     size_t nframes = frames.size ();
 
@@ -404,10 +404,10 @@
     return retval;
   }
 
-  std::list<octave::frame_info>
+  std::list<frame_info>
   error_system::make_stack_frame_list (const octave_map& stack)
   {
-    std::list<octave::frame_info> frames;
+    std::list<frame_info> frames;
 
     Cell file = stack.contents ("file");
     Cell name = stack.contents ("name");
@@ -423,11 +423,11 @@
     octave_idx_type nel = name.numel ();
 
     for (octave_idx_type i = 0; i < nel; i++)
-      frames.push_back (octave::frame_info (file(i).string_value (),
-                                            name(i).string_value (),
-                                            line(i).int_value (),
-                                            (have_column
-                                             ? column(i).int_value () : -1)));
+      frames.push_back (frame_info (file(i).string_value (),
+                                    name(i).string_value (),
+                                    line(i).int_value (),
+                                    (have_column
+                                     ? column(i).int_value () : -1)));
 
     return frames;
   }
@@ -571,10 +571,7 @@
          || application::forced_interactive ())
         && debug_on_warning () && in_user_code && bptab.debug_on_warn (id))
       {
-        unwind_protect frame;
-
-        frame.protect_var (m_debug_on_warning);
-        m_debug_on_warning = false;
+        unwind_protect_var<bool> restore_var (m_debug_on_warning, false);
 
         tw.enter_debugger ();
       }
@@ -751,9 +748,13 @@
       panic_impossible ();
 
     if (nel > 1)
-      os << "\n\n";
+      {
+        os << "\n";
+        os << "Non-default warning states are:\n\n";
+        os << "  State  Warning ID\n";
+      }
 
-    // The state for all is always supposed to be first in the list.
+    // The state for "all" is always supposed to be first in the list.
 
     for (octave_idx_type i = 1; i < nel; i++)
       {
@@ -1377,7 +1378,7 @@
 The optional warning identifier @var{id} allows users to enable or disable
 warnings tagged by this identifier.  A message identifier is a string of the
 form @qcode{"NAMESPACE:WARNING-NAME"}.  Octave's own warnings use the
-@qcode{"Octave"} namespace (@pxref{XREFwarning_ids,,warning_ids}).  For
+@qcode{"Octave"} namespace (@pxref{XREFwarning_ids,,@code{warning_ids}}).  For
 example:
 
 @example
@@ -1506,7 +1507,6 @@
                   octave_value curr_state = val.contents ("state");
 
                   // FIXME: this might be better with a dictionary object.
-
                   octave::tree_evaluator& tw = interp.get_evaluator ();
 
                   octave_value curr_warning_states
@@ -1560,39 +1560,28 @@
 
                   tw.set_auto_fcn_var (octave::stack_frame::SAVED_WARNING_STATES, m);
 
-                  // Now ignore the "local" argument and continue to
-                  // handle the current setting.
+                  // Now ignore the "local" argument,
+                  // and continue to handle the current setting.
                   nargin--;
                 }
             }
 
-          if (nargin >= 2 && arg2_lc == "all")
+          if ((nargin == 1
+               && (arg1 == "on" || arg1 == "off" || arg1 == "error"))
+              || (nargin >= 2 && arg2_lc == "all"))
             {
-              // If "all" is explicitly given as ID.
+              // If "all" is given implicitly or explicitly as ID.
+              if (arg1 == "error")
+                error (R"(warning: cannot specify "all" warning ID with state "error")");
 
               octave_map tmp;
-              int is_error = (arg1 == "error");
 
-              Cell id (1, 1 + 2*is_error);
-              Cell st (1, 1 + 2*is_error);
+              Cell id (1, 1);
+              Cell st (1, 1);
 
               id(0) = "all";
               st(0) = arg1;
 
-              // Since internal Octave functions are not compatible,
-              // and "all"=="error" causes any "on" to throw an error,
-              // turning all warnings into errors should disable
-              // Octave:language-extension.
-
-              if (is_error)
-                {
-                  id(1) = "Octave:language-extension";
-                  st(1) = "off";
-
-                  id(2) = "Octave:single-quote-string";
-                  st(2) = "off";
-                }
-
               tmp.assign ("identifier", id);
               tmp.assign ("state", st);
 
@@ -1648,25 +1637,63 @@
       else if (arg1 == "query")
         {
           if (arg2_lc == "all")
-            retval = es.warning_options ();
+            {
+              if (nargout > 0)
+                retval = es.warning_options ();
+              else
+                es.display_warning_options (octave_stdout);
+            }
           else if (arg2_lc == "backtrace" || arg2_lc == "debug"
                    || arg2_lc == "verbose" || arg2_lc == "quiet")
             {
-              octave_scalar_map tmp;
-              tmp.assign ("identifier", arg2_lc);
-              if (arg2_lc == "backtrace")
-                tmp.assign ("state", es.backtrace_on_warning () ? "on" : "off");
-              else if (arg2_lc == "debug")
-                tmp.assign ("state", es.debug_on_warning () ? "on" : "off");
-              else if (arg2_lc == "verbose")
-                tmp.assign ("state", es.verbose_warning () ? "on" : "off");
+              if (nargout > 0)
+                {
+                  octave_scalar_map tmp;
+                  tmp.assign ("identifier", arg2_lc);
+                  if (arg2_lc == "backtrace")
+                    tmp.assign ("state", es.backtrace_on_warning () ? "on" : "off");
+                  else if (arg2_lc == "debug")
+                    tmp.assign ("state", es.debug_on_warning () ? "on" : "off");
+                  else if (arg2_lc == "verbose")
+                    tmp.assign ("state", es.verbose_warning () ? "on" : "off");
+                  else
+                    tmp.assign ("state", es.quiet_warning () ? "on" : "off");
+
+                  retval = tmp;
+                }
               else
-                tmp.assign ("state", es.quiet_warning () ? "on" : "off");
-
-              retval = tmp;
+                {
+                  if (arg2_lc == "backtrace")
+                    octave_stdout << R"("backtrace" warning state is ")" <<
+                                  (es.backtrace_on_warning () ? "on" : "off") <<
+                                  "\"\n";
+                  else if (arg2_lc == "debug")
+                    octave_stdout << R"("debug" warning state is ")" <<
+                                  (es.debug_on_warning () ? "on" : "off") <<
+                                  "\"\n";
+                  else if (arg2_lc == "verbose")
+                    octave_stdout << R"("verbose" warning state is ")" <<
+                                  (es.verbose_warning () ? "on" : "off") <<
+                                  "\"\n";
+                  else
+                    octave_stdout << R"("quiet" warning state is ")" <<
+                                  (es.quiet_warning () ? "on" : "off") <<
+                                  "\"\n";
+                }
             }
           else
-            retval = es.warning_query (arg2);
+            {
+              if (nargout > 0)
+                retval = es.warning_query (arg2);
+              else
+                {
+                  octave_scalar_map tmp = es.warning_query (arg2);
+
+                  octave_stdout << '"' << arg2 << R"(" warning state is ")" <<
+                                   tmp.getfield ("state").string_value () <<
+                                   "\"\n";
+                }
+            }
 
           done = true;
         }
@@ -1749,9 +1776,6 @@
 }
 
 /*
-%!test <*45753>
-%! warning ("error");
-%! assert (! isempty (help ("warning")));
 
 %!test <*51997>
 %! id = "Octave:logical-conversion";
@@ -1774,6 +1798,8 @@
 %! idx = strcmp ({warnst.identifier}, "Octave:test-57290-ID");
 %! assert (warnst(idx).state, "off");
 
+%!error <cannot specify "all" warning ID> warning ("error")
+
 */
 
 octave_value_list
--- a/libinterp/corefcn/error.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/error.h	Thu Nov 19 13:08:00 2020 -0800
@@ -239,9 +239,9 @@
     }
 
     static octave_map
-    make_stack_map (const std::list<octave::frame_info>& frames);
+    make_stack_map (const std::list<frame_info>& frames);
 
-    static std::list<octave::frame_info>
+    static std::list<frame_info>
     make_stack_frame_list (const octave_map& stack);
 
     //! For given warning ID, return 0 if warnings are disabled, 1 if
@@ -291,7 +291,7 @@
 
     void initialize_default_warning_state (void);
 
-    void interpreter_try (octave::unwind_protect& frame);
+    void interpreter_try (unwind_protect& frame);
 
     // Throw execution_exception or, if debug_on_error is TRUE, enter
     // debugger.  If stack_info is empty, use current call stack.
--- a/libinterp/corefcn/event-manager.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/event-manager.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -577,6 +577,51 @@
   return ovl (evmgr.unregister_doc (file));
 }
 
+DEFMETHOD (__event_manager_gui_status_update__, interp, args, ,
+           doc: /* -*- texinfo -*-
+@deftypefn {} {} __event_manager_gui_status_update__ (@var{feature}, @var{status})
+Internal function for updating the status of some features in the GUI.
+@end deftypefn */)
+{
+  // This is currently a stub and should only be activated some
+  // interpreter action only implemented in m-files requires to update
+  // a status indicator in the gui. BUT: This internal function can
+  // be activated by the user leading to gui indicators not reflecting
+  // the real state of the related feature.
+  return ovl ();
+
+  std::string feature;
+  std::string status;
+
+  if (! (Fisguirunning ())(0).is_true ())
+    return ovl ();
+
+  if (args.length () < 2)
+    error ("__event_manager_gui_status_update__: two parameters required");
+  if (! (args(0).is_string ()))
+    error ("__event_manager_gui_status_update__: FEATURE must be a string");
+  if (! (args(1).is_string ()))
+    error ("__event_manager_gui_status_update__: STATUS must be a string");
+
+  feature = args(0).string_value ();
+  status = args(1).string_value ();
+
+  octave::event_manager& evmgr = interp.get_event_manager ();
+
+  return ovl (evmgr.gui_status_update (feature, status));
+}
+
+DEFMETHOD (__event_manager_update_gui_lexer__, interp, , ,
+           doc: /* -*- texinfo -*-
+@deftypefn {} {} __event_manager_update_gui_lexer__ ()
+Undocumented internal function.
+@end deftypefn */)
+{
+  octave::event_manager& evmgr = interp.get_event_manager ();
+
+  return ovl (evmgr.update_gui_lexer ());
+}
+
 DEFMETHOD (__event_manager_copy_image_to_clipboard__, interp, args, ,
            doc: /* -*- texinfo -*-
 @deftypefn {} {} __event_manager_copy_image_to_clipboard__ (@var{filename})
--- a/libinterp/corefcn/event-manager.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/event-manager.h	Thu Nov 19 13:08:00 2020 -0800
@@ -44,7 +44,7 @@
 namespace octave
 {
   typedef std::function<void (void)> fcn_callback;
-  typedef std::function<void (octave::interpreter&)> meth_callback;
+  typedef std::function<void (interpreter&)> meth_callback;
 
   class symbol_info_list;
 
@@ -195,6 +195,11 @@
 
     virtual void unregister_doc (const std::string& /*file*/) { }
 
+    virtual void gui_status_update (const std::string& /*feature*/,
+                                    const std::string& /*status*/) { }
+
+    virtual void update_gui_lexer (void) { }
+
     // Notifications of events in the interpreter that a GUI will
     // normally wish to respond to.
 
@@ -208,7 +213,7 @@
 
     virtual void
     set_workspace (bool /*top_level*/, bool /*debug*/,
-                   const octave::symbol_info_list& /*syminfo*/,
+                   const symbol_info_list& /*syminfo*/,
                    bool /*update_variable_editor*/)
     { }
 
@@ -369,7 +374,7 @@
 
     void update_path_dialog (void)
     {
-      if (octave::application::is_gui_running () && enabled ())
+      if (application::is_gui_running () && enabled ())
         instance->update_path_dialog ();
     }
 
@@ -495,7 +500,28 @@
         }
       else
         return false;
+    }
 
+    bool gui_status_update (const std::string& feature, const std::string& status)
+    {
+      if (enabled ())
+        {
+          instance->gui_status_update (feature, status);
+          return true;
+        }
+      else
+        return false;
+    }
+
+    bool update_gui_lexer (void)
+    {
+      if (enabled ())
+        {
+          instance->update_gui_lexer ();
+          return true;
+        }
+      else
+        return false;
     }
 
     void directory_changed (const std::string& dir)
@@ -507,19 +533,19 @@
     // Methods for removing/renaming files which might be open in editor
     void file_remove (const std::string& old_name, const std::string& new_name)
     {
-      if (octave::application::is_gui_running () && enabled ())
+      if (application::is_gui_running () && enabled ())
         instance->file_remove (old_name, new_name);
     }
 
     void file_renamed (bool load_new)
     {
-      if (octave::application::is_gui_running () && enabled ())
+      if (application::is_gui_running () && enabled ())
         instance->file_renamed (load_new);
     }
 
     void set_workspace (void);
 
-    void set_workspace (bool top_level, const octave::symbol_info_list& syminfo,
+    void set_workspace (bool top_level, const symbol_info_list& syminfo,
                         bool update_variable_editor = true)
     {
       if (enabled ())
@@ -609,10 +635,10 @@
   protected:
 
     // Semaphore to lock access to the event queue.
-    octave::mutex *event_queue_mutex;
+    mutex *event_queue_mutex;
 
     // Event Queue.
-    octave::event_queue gui_event_queue;
+    event_queue gui_event_queue;
 
     bool debugging;
     bool link_enabled;
--- a/libinterp/corefcn/fcn-info.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/fcn-info.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -86,7 +86,7 @@
 
     tmpfcn->mark_as_private_function (class_name);
 
-    private_functions[octave::sys::canonicalize_file_name (dir_name)] = ov_fcn;
+    private_functions[sys::canonicalize_file_name (dir_name)] = ov_fcn;
 
     return ov_fcn;
   }
@@ -409,21 +409,59 @@
   // would not check for it when finding symbol definitions.
 
   static inline bool
-  load_out_of_date_fcn (const std::string& ff, const std::string& dir_name,
+  load_out_of_date_fcn (const std::string& file_name,
+                        const std::string& dir_name_arg,
                         octave_value& function,
                         const std::string& dispatch_type = "",
                         const std::string& package_name = "")
   {
     bool retval = false;
 
+    std::string dir_name = dir_name_arg;
+
+    if (dir_name.empty ())
+      {
+        size_t pos = file_name.find_last_of (sys::file_ops::dir_sep_chars ());
+
+        dir_name = file_name.substr (0, pos);
+      }
+
+    // FIXME: do the following job of determining private status and
+    // class membership in a separate function?
+
+    size_t pos = dir_name.find_last_of (sys::file_ops::dir_sep_chars ());
+
+    bool is_private_fcn
+      = pos != std::string::npos && dir_name.substr (pos+1) == "private";
+
+    if (is_private_fcn)
+      dir_name = dir_name.substr (0, pos);
+
+    std::string class_name;
+
+    pos = dir_name.find_last_of (sys::file_ops::dir_sep_chars ());
+
+    if (pos != std::string::npos)
+      {
+        std::string tmp = dir_name.substr (pos+1);
+
+        if (tmp[0] == '@')
+          class_name = tmp.substr (1);
+      }
+
     octave_value ov_fcn
-      = load_fcn_from_file (ff, dir_name, dispatch_type,
+      = load_fcn_from_file (file_name, dir_name, dispatch_type,
                             package_name);
 
     if (ov_fcn.is_defined ())
       {
         retval = true;
 
+        octave_function *fcn = ov_fcn.function_value ();
+
+        if (is_private_fcn)
+          fcn->mark_as_private_function (class_name);
+
         function = ov_fcn;
       }
     else
@@ -1185,7 +1223,7 @@
 %! ignore_function_time_stamp (old_state);
 
 ## Test input validation
-%!error (ignore_function_time_stamp ("all", "all"))
-%!error (ignore_function_time_stamp ("UNKNOWN_VALUE"))
-%!error (ignore_function_time_stamp (42))
+%!error ignore_function_time_stamp ("all", "all")
+%!error ignore_function_time_stamp ("UNKNOWN_VALUE")
+%!error ignore_function_time_stamp (42)
 */
--- a/libinterp/corefcn/fft.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/fft.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -113,7 +113,7 @@
         idx(i) = idx_vector::colon;
       idx(dim) = idx_vector (static_cast<octave_idx_type> (0));
 
-      return arg.do_index_op (idx);
+      return arg.index_op (idx);
     }
 
   if (arg.is_single_type ())
@@ -187,7 +187,7 @@
 %!testif HAVE_FFTW
 %! assert (fft (eye (2,2,"single")), single ([1,1; 1,-1]))
 
-%!error (fft ())
+%!error fft ()
 */
 
 
--- a/libinterp/corefcn/file-io.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/file-io.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -273,7 +273,8 @@
 
 If there are no more characters to read, @code{fgetl} returns @minus{}1.
 
-To read a line and return the terminating newline see @code{fgets}.
+To read a line and return the terminating newline,
+@pxref{XREFfgets,,@code{fgets}}.
 @seealso{fgets, fscanf, fread, fopen}
 @end deftypefn */)
 {
@@ -315,7 +316,8 @@
 
 If there are no more characters to read, @code{fgets} returns @minus{}1.
 
-To read a line and discard the terminating newline see @code{fgetl}.
+To read a line and discard the terminating newline,
+@pxref{XREFfgetl,,@code{fgetl}}.
 @seealso{fputs, fgetl, fscanf, fread, fopen}
 @end deftypefn */)
 {
@@ -1641,8 +1643,10 @@
 %! c = textscan (str, "%4f %f", "delimiter", ";", "collectOutput", 1);
 %! assert (c, {[12, 34; 1234, 56789; 7, NaN]});
 
+## FIXME: Not Matlab compatible.  Matlab prioritizes precision over field width
+## so "12.234e+2", when read with "%10.2f %f", yields "12.23" and "4e+2".
 ## Ignore trailing delimiter, but use leading one
-%!test
+%!#test
 %! str = "12.234e+2,34, \n12345.789-9876j,78\n,10|3";
 %! c = textscan (str, "%10.2f %f", "delimiter", ",", "collectOutput", 1,
 %!                    "expChars", "e|");
@@ -2285,7 +2289,46 @@
 %! obs = textscan (str, "%q", "delimiter", ",");
 %! assert (obs, { { "a,b"; "c" } });
 
+%!test <*58008>
+%! txt = sprintf ('literal_other_1_1;literal_other_1_2\nliteral_other_2_1;literal_other_2_2\nliteral_other_3_1;literal_other_3_2');
+%! nm1 = textscan (txt, 'literal%s literal%s', 'Delimiter', ';');
+%! assert (nm1{1}, {"_other_1_1" ; "_other_2_1" ; "_other_3_1"});
+%! assert (nm1{2}, {"_other_1_2" ; "_other_2_2" ; "_other_3_2"});
+%! nm2 = textscan (txt, 'literal%s;literal%s', 'Delimiter', ';');
+%! assert (nm1, nm2);
+
+%!test <*57612>
+%! str = sprintf (['101,' '\n' '201,']);
+%! C = textscan (str, '%s%q', 'Delimiter', ',');
+%! assert (size (C), [1, 2]);
+%! assert (C{1}, { "101"; "201" });
+%! assert (C{2}, { ""; "" });
+
+%!test <*57612>
+%! str = sprintf (['101,' '\n' '201,']);
+%! C = textscan (str, '%s%f', 'Delimiter', ',');
+%! assert (size (C), [1, 2]);
+%! assert (C{1}, { "101"; "201" });
+%! assert (C{2}, [ NaN; NaN ]);
+
+%!test <*57612>
+%! str = sprintf (['101,' '\n' '201,']);
+%! C = textscan (str, '%s%d', 'Delimiter', ',');
+%! assert (size (C), [1, 2]);
+%! assert (C{1}, { "101"; "201" });
+%! assert (C{2}, int32 ([ 0; 0 ]));
+
+%!test <*51093>
+%! str = sprintf ('a\t\tb\tc');
+%! C = textscan (str, '%s', 'Delimiter', '\t', 'MultipleDelimsAsOne', false);
+%! assert (C{1}, {'a'; ''; 'b'; 'c'});
+
+%!xtest <50743>
+%! C = textscan ('5973459727478852968', '%u64');
+%! assert (C{1}, uint64 (5973459727478852968));
+
 */
+
 // These tests have end-comment sequences, so can't just be in a comment
 #if 0
 ## Test unfinished comment
@@ -2824,7 +2867,7 @@
 Programming Note: Because the named file is not opened by @code{tempname},
 it is possible, though relatively unlikely, that it will not be available
 by the time your program attempts to open it.  If this is a concern,
-see @code{tmpfile}.
+@pxref{XREFtmpfile,,@code{tmpfile}}.
 @seealso{mkstemp, tempdir, P_tmpdir, tmpfile}
 @end deftypefn */)
 {
@@ -2890,7 +2933,7 @@
 %!   assert (tmpdir, tmp_tmpdir);
 %!   assert (tmpfname (1:4), "file");
 %! unwind_protect_cleanup
-%!   rmdir (tmp_tmpdir);
+%!   sts = rmdir (tmp_tmpdir);
 %!   for i = 1:numel (envvar)
 %!     if (isempty (envdir{i}))
 %!       unsetenv (envvar{i});
--- a/libinterp/corefcn/filter.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/filter.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -605,7 +605,7 @@
 %!assert (filter ([1, 1, 1], [1, 1], [1 2], [1, 1]), [2 2])
 %!assert (filter ([1, 1, 1], [1, 1], [1 2], [1, 1]'), [2 2])
 %!assert (filter ([1, 3], [1], [1 2; 3 4; 5 6], [4, 5]), [5 7; 6 10; 14 18])
-%!error (filter ([1, 3], [1], [1 2; 3 4; 5 6], [4, 5]'))
+%!error filter ([1, 3], [1], [1 2; 3 4; 5 6], [4, 5]')
 %!assert (filter ([1, 3, 2], [1], [1 2; 3 4; 5 6], [1 0 0; 1 0 0], 2), [2 6; 3 13; 5 21])
 
 ## Test of DIM parameter
--- a/libinterp/corefcn/ft-text-renderer.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/ft-text-renderer.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -980,9 +980,10 @@
 
     m_strlist = std::list<text_renderer::string> ();
 
-    unwind_protect frame;
-    frame.protect_var (m_do_strlist);
-    frame.protect_var (m_strlist);
+    unwind_protect_var<bool> restore_var1 (m_do_strlist);
+    unwind_protect_var<std::list<text_renderer::string>>
+      restore_var2 (m_strlist);
+
     m_do_strlist = true;
 
     text_to_pixels (txt, pxls, box, ha, va, rot, interp, false);
--- a/libinterp/corefcn/gl-render.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/gl-render.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -27,6 +27,7 @@
 #  include "config.h"
 #endif
 
+#include <limits>
 #include <sstream>
 
 #if defined (HAVE_WINDOWS_H)
@@ -734,6 +735,8 @@
       draw_surface (dynamic_cast<const surface::properties&> (props));
     else if (go.isa ("patch"))
       draw_patch (dynamic_cast<const patch::properties&> (props));
+    else if (go.isa ("scatter"))
+      draw_scatter (dynamic_cast<const scatter::properties&> (props));
     else if (go.isa ("light"))
       draw_light (dynamic_cast<const light::properties&> (props));
     else if (go.isa ("hggroup"))
@@ -1277,8 +1280,21 @@
 
     Matrix x_zlim = props.get_transform_zlim ();
 
-    xZ1 = std::max (-1e6, x_zlim(0)-(x_zlim(1)-x_zlim(0))*100.0);
-    xZ2 = std::min (1e6, x_zlim(1)+(x_zlim(1)-x_zlim(0))*100.0);
+    // Expand the distance between the clipping planes symmetrically by
+    // an arbitrary factor (see bug #54551).
+    const double expansion_fac = 100.0;
+    // Also make sure that the distance between the clipping planes
+    // differs in single precision (see bug #58956).  This factor is also
+    // arbitrary.  Different values (>2) might also work.
+    const double single_prec_fac = 10.0;
+
+    double avgZ = x_zlim(0) / 2.0 + x_zlim(1) / 2.0;
+    double span 
+      = std::max (expansion_fac * (x_zlim(1)-x_zlim(0)),
+                  single_prec_fac * std::abs (avgZ)
+                  * std::numeric_limits<float>::epsilon ());
+    xZ1 = avgZ - span;
+    xZ2 = avgZ + span;
 
     Matrix x_mat1 = props.get_opengl_matrix_1 ();
     Matrix x_mat2 = props.get_opengl_matrix_2 ();
@@ -3695,6 +3711,116 @@
   }
 
   void
+  opengl_renderer::draw_scatter (const scatter::properties& props)
+  {
+#if defined (HAVE_OPENGL)
+
+    // Do not render if the scatter object has incoherent data
+    std::string msg;
+    if (props.has_bad_data (msg))
+      {
+        warning ("opengl_renderer: %s.  Not rendering.", msg.c_str ());
+        return;
+      }
+
+    bool draw_all = selecting;
+
+    if (draw_all || (! props.marker_is ("none")
+                     && ! (props.markeredgecolor_is ("none")
+                           && props.markerfacecolor_is ("none"))))
+      {
+        bool do_edge = draw_all || ! props.markeredgecolor_is ("none");
+        bool do_face = draw_all || ! props.markerfacecolor_is ("none");
+
+        const Matrix x = props.get_xdata ().matrix_value ();
+        const Matrix y = props.get_ydata ().matrix_value ();
+        const Matrix z = props.get_zdata ().matrix_value ();
+        const Matrix c = props.get_color_data ().matrix_value ();
+        const Matrix s = props.get_sizedata ().matrix_value ();
+
+        int np = x.rows ();
+        bool has_z = ! z.isempty ();
+
+        // If markeredgecolor is "flat", mecolor is empty
+        Matrix mecolor = (draw_all ? Matrix (1, 3, 0.0) :
+                          props.get_markeredgecolor_rgb ());
+        Matrix mfcolor = (draw_all ? Matrix (1, 3, 0.0) :
+                          props.get_markerfacecolor_rgb ());
+        const double mea = props.get_markeredgealpha ();
+        const double mfa = props.get_markerfacealpha ();
+
+        if (props.markerfacecolor_is ("auto"))
+          {
+            gh_manager& gh_mgr
+              = __get_gh_manager__ ("opengl_renderer::draw_scatter");
+            graphics_object go = gh_mgr.get_object (props.get___myhandle__ ());
+            graphics_object ax = go.get_ancestor ("axes");
+            const axes::properties& ax_props
+              = dynamic_cast<const axes::properties&> (ax.get_properties ());
+
+            mfcolor = ax_props.get_color ().matrix_value ();
+          }
+
+        init_marker (props.get_marker (), std::sqrt (s(0)),
+                     props.get_linewidth ());
+
+        uint8_t clip_mask = (props.is_clipping () ? 0x7F : 0x40);
+        uint8_t clip_ok = 0x40;
+
+        Matrix cc;
+        if (! c.isempty ())
+          {
+            if (c.rows () == 1)
+              cc = c;
+            else
+              {
+                cc.resize (1, 3);
+                cc(0) = c(0,0);
+                cc(1) = c(0,1);
+                cc(2) = c(0,2);
+              }
+          }
+
+        for (int i = 0; i < np; i++)
+          {
+            if ((clip_code (x(i), y(i), (has_z ? z(i) : 0.0)) & clip_mask)
+                 != clip_ok)
+              continue;
+
+            if (c.rows () > 1)
+              {
+                cc(0) = c(i,0);
+                cc(1) = c(i,1);
+                cc(2) = c(i,2);
+              }
+
+            Matrix lc = (do_edge ? (mecolor.isempty () ? cc : mecolor)
+                                 : Matrix ());
+            Matrix fc = (do_face ? (mfcolor.isempty () ? cc : mfcolor)
+                                 : Matrix ());
+
+            if (s.numel () > 1)
+              change_marker (props.get_marker (), std::sqrt (s(i)));
+
+            draw_marker (x(i), y(i), (has_z ? z(i) : 0.0), lc, fc, mea, mfa);
+          }
+
+        end_marker ();
+      }
+
+#else
+
+    octave_unused_parameter (props);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
+
+#endif
+  }
+
+  void
   opengl_renderer::draw_light (const light::properties& props)
   {
 #if defined (HAVE_OPENGL)
@@ -4275,6 +4401,27 @@
   }
 
   void
+  opengl_renderer::change_marker (const std::string& m, double size)
+  {
+#if defined (HAVE_OPENGL)
+
+    marker_id = make_marker_list (m, size, false);
+    filled_marker_id = make_marker_list (m, size, true);
+
+#else
+
+    octave_unused_parameter (m);
+    octave_unused_parameter (size);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
+
+#endif
+  }
+
+  void
   opengl_renderer::end_marker (void)
   {
 #if defined (HAVE_OPENGL)
@@ -4300,7 +4447,8 @@
 
   void
   opengl_renderer::draw_marker (double x, double y, double z,
-                                const Matrix& lc, const Matrix& fc)
+                                const Matrix& lc, const Matrix& fc,
+                                const double la, const double fa)
   {
 #if defined (HAVE_OPENGL)
 
@@ -4311,12 +4459,12 @@
 
     if (filled_marker_id > 0 && fc.numel () > 0)
       {
-        m_glfcns.glColor3dv (fc.data ());
+        m_glfcns.glColor4d (fc(0), fc(1), fc(2), fa);
         set_polygon_offset (true, -1.0);
         m_glfcns.glCallList (filled_marker_id);
         if (lc.numel () > 0)
           {
-            m_glfcns.glColor3dv (lc.data ());
+            m_glfcns.glColor4d (lc(0), lc(1), lc(2), la);
             m_glfcns.glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
             m_glfcns.glEdgeFlag (GL_TRUE);
             set_polygon_offset (true, -2.0);
@@ -4327,7 +4475,7 @@
       }
     else if (marker_id > 0 && lc.numel () > 0)
       {
-        m_glfcns.glColor3dv (lc.data ());
+        m_glfcns.glColor4d (lc(0), lc(1), lc(2), la);
         m_glfcns.glCallList (marker_id);
       }
 
@@ -4338,6 +4486,8 @@
     octave_unused_parameter (z);
     octave_unused_parameter (lc);
     octave_unused_parameter (fc);
+    octave_unused_parameter (la);
+    octave_unused_parameter (fa);
 
     // This shouldn't happen because construction of opengl_renderer
     // objects is supposed to be impossible if OpenGL is not available.
--- a/libinterp/corefcn/gl-render.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/gl-render.h	Thu Nov 19 13:08:00 2020 -0800
@@ -81,6 +81,7 @@
     virtual void draw_line (const line::properties& props);
     virtual void draw_surface (const surface::properties& props);
     virtual void draw_patch (const patch::properties& props);
+    virtual void draw_scatter (const scatter::properties& props);
     virtual void draw_light (const light::properties& props);
     virtual void draw_hggroup (const hggroup::properties& props);
     virtual void draw_text (const text::properties& props);
@@ -115,9 +116,11 @@
     }
 
     virtual void init_marker (const std::string& m, double size, float width);
+    virtual void change_marker (const std::string& m, double size);
     virtual void end_marker (void);
     virtual void draw_marker (double x, double y, double z,
-                              const Matrix& lc, const Matrix& fc);
+                              const Matrix& lc, const Matrix& fc,
+                              const double la = 1.0, const double fa = 1.0);
 
     virtual void text_to_pixels (const std::string& txt,
                                  uint8NDArray& pixels,
--- a/libinterp/corefcn/gl2ps-print.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/gl2ps-print.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -39,6 +39,7 @@
 
 #include <gl2ps.h>
 
+#include "file-ops.h"
 #include "lo-mappers.h"
 #include "oct-locbuf.h"
 #include "tmpfile-wrapper.h"
@@ -55,20 +56,6 @@
 
 namespace octave
 {
-  static void
-  safe_pclose (FILE *f)
-  {
-    if (f)
-      octave::pclose (f);
-  }
-
-  static void
-  safe_fclose (FILE *f)
-  {
-    if (f)
-      std::fclose (f);
-  }
-
   class
   OCTINTERP_API
   gl2ps_renderer : public opengl_renderer
@@ -128,6 +115,13 @@
               && fa.double_value () < 1)
             retval = true;
         }
+      else if (go.isa ("scatter"))
+        {
+          octave_value fa = go.get ("markerfacealpha");
+          if (fa.is_scalar_type () && fa.is_double_type ()
+              && fa.double_value () < 1)
+            retval = true;
+        }
 
       return retval;
     }
@@ -373,7 +367,7 @@
         if (! tmpf)
           error ("gl2ps_renderer::draw: couldn't open temporary file for printing");
 
-        frame.add_fcn (safe_fclose, tmpf);
+        frame.add ([=] () { std::fclose (tmpf); });
 
         // Reset buffsize, unless this is 2nd pass of a texstandalone print.
         if (term.find ("tex") == std::string::npos)
@@ -406,13 +400,17 @@
             else
               include_graph = old_print_cmd;
 
-            size_t n_begin = include_graph.find_first_not_of (" \"'");
+            size_t n_begin = include_graph.find_first_not_of (R"( "')");
 
             if (n_begin != std::string::npos)
               {
-                size_t n_end = include_graph.find_last_not_of (" \"'");
+                // Strip any quote characters characters around filename
+                size_t n_end = include_graph.find_last_not_of (R"( "')");
                 include_graph = include_graph.substr (n_begin,
                                                       n_end - n_begin + 1);
+                // Strip path from filename
+                n_begin = include_graph.find_last_of (sys::file_ops::dir_sep_chars ());
+                include_graph = include_graph.substr (n_begin + 1);
               }
             else
               include_graph = "foobar-inc";
@@ -807,7 +805,7 @@
     ColumnVector coord_pix = get_transform ().transform (x, y, z, false);
 
     std::ostringstream os;
-    os << "<text xml:space=\"preserve\" ";
+    os << R"(<text xml:space="preserve" )";
 
     // Rotation and translation are applied to the whole text element
     os << "transform=\""
@@ -834,7 +832,7 @@
         os << "<tspan ";
 
         if (name.compare (p->get_family ()))
-          os << "font-family=\""  << p->get_family () << "\" ";
+          os << "font-family=\"" << p->get_family () << "\" ";
 
         if (weight.compare (p->get_weight ()))
           os << "font-weight=\"" << p->get_weight () << "\" ";
@@ -853,12 +851,12 @@
 
         // provide an x coordinate for each character in the string
         os << "x=\"";
-        std::vector<double> xdata =  p->get_xdata ();
+        std::vector<double> xdata = p->get_xdata ();
         for (auto q = xdata.begin (); q != xdata.end (); q++)
           os << (*q) << " ";
-        os << "\"";
+        os << '"';
 
-        os << ">";
+        os << '>';
 
         // translate unicode and special xml characters
         if (p->get_code ())
@@ -1433,7 +1431,8 @@
         if (! fp)
           error (R"(print: failed to open pipe "%s")", stream.c_str ());
 
-        frame.add_fcn (safe_pclose, fp);
+        // Need octave:: qualifier here to avoid ambiguity.
+        frame.add ([=] () { octave::pclose (fp); });
       }
     else
       {
@@ -1444,7 +1443,7 @@
         if (! fp)
           error (R"(gl2ps_print: failed to create file "%s")", stream.c_str ());
 
-        frame.add_fcn (safe_fclose, fp);
+        frame.add ([=] () { std::fclose (fp); });
       }
 
     gl2ps_renderer rend (glfcns, fp, term);
--- a/libinterp/corefcn/graphics-toolkit.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/graphics-toolkit.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -36,8 +36,7 @@
   void
   base_graphics_toolkit::update (const graphics_handle& h, int id)
   {
-    gh_manager& gh_mgr
-      = octave::__get_gh_manager__ ("base_graphics_toolkit::update");
+    gh_manager& gh_mgr = __get_gh_manager__ ("base_graphics_toolkit::update");
 
     graphics_object go = gh_mgr.get_object (h);
 
@@ -48,7 +47,7 @@
   base_graphics_toolkit::initialize (const graphics_handle& h)
   {
     gh_manager& gh_mgr
-      = octave::__get_gh_manager__ ("base_graphics_toolkit::initialize");
+      = __get_gh_manager__ ("base_graphics_toolkit::initialize");
 
     graphics_object go = gh_mgr.get_object (h);
 
@@ -59,7 +58,7 @@
   base_graphics_toolkit::finalize (const graphics_handle& h)
   {
     gh_manager& gh_mgr
-      = octave::__get_gh_manager__ ("base_graphics_toolkit::finalize");
+      = __get_gh_manager__ ("base_graphics_toolkit::finalize");
 
     graphics_object go = gh_mgr.get_object (h);
 
--- a/libinterp/corefcn/graphics.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/graphics.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -1157,8 +1157,9 @@
                 {
                   pfx = name.substr (0, 7);
 
-                  if (pfx.compare ("surface") || pfx.compare ("hggroup")
-                      || pfx.compare ("uipanel") || pfx.compare ("uitable"))
+                  if (pfx.compare ("surface") || pfx.compare ("scatter")
+                      || pfx.compare ("hggroup") || pfx.compare ("uipanel")
+                      || pfx.compare ("uitable"))
                     offset = 7;
                   else if (len >= 9)
                     {
@@ -1226,6 +1227,8 @@
     go = new light (h, p);
   else if (type.compare ("patch"))
     go = new patch (h, p);
+  else if (type.compare ("scatter"))
+    go = new scatter (h, p);
   else if (type.compare ("surface"))
     go = new surface (h, p);
   else if (type.compare ("hggroup"))
@@ -1784,18 +1787,18 @@
 }
 
 /*
-## Test validation of uicontextmenu property
+## Test validation of contextmenu property
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
 %!   hax = axes ("parent", hf);
 %!   hpa = patch ("parent", hax);
 %!   try
-%!     set (hax, "uicontextmenu", hpa);
+%!     set (hax, "contextmenu", hpa);
 %!   catch
 %!     err = lasterr ();
 %!   end_try_catch
-%!   assert (err, 'set: invalid graphics object type for property "uicontextmenu"');
+%!   assert (err, 'set: invalid graphics object type for property "contextmenu"');
 %! unwind_protect_cleanup
 %!   delete (hf);
 %! end_unwind_protect
@@ -1940,12 +1943,11 @@
 void
 callback_property::execute (const octave_value& data) const
 {
-  octave::unwind_protect frame;
-
   // We are executing a callback function, so allow handles that have
   // their handlevisibility property set to "callback" to be visible.
 
-  frame.add_method (executing_callbacks, &callback_props::erase, this);
+  octave::unwind_action executing_callbacks_cleanup
+    ([=] () { executing_callbacks.erase (this); });
 
   if (! executing_callbacks.contains (this))
     {
@@ -2297,8 +2299,9 @@
                 {
                   pfx = name.substr (0, 7);
 
-                  if (pfx.compare ("surface") || pfx.compare ("hggroup")
-                      || pfx.compare ("uipanel") || pfx.compare ("uitable"))
+                  if (pfx.compare ("surface") || pfx.compare ("scatter")
+                      || pfx.compare ("hggroup")|| pfx.compare ("uipanel")
+                      || pfx.compare ("uitable"))
                     offset = 7;
                   else if (len > 9)
                     {
@@ -2357,6 +2360,8 @@
             has_property = image::properties::has_core_property (pname);
           else if (pfx == "patch")
             has_property = patch::properties::has_core_property (pname);
+          else if (pfx == "scatter")
+            has_property = scatter::properties::has_core_property (pname);
           else if (pfx == "surface")
             has_property = surface::properties::has_core_property (pname);
           else if (pfx == "hggroup")
@@ -2439,8 +2444,9 @@
                 {
                   pfx = name.substr (0, 7);
 
-                  if (pfx.compare ("surface") || pfx.compare ("hggroup")
-                      || pfx.compare ("uipanel") || pfx.compare ("uitable"))
+                  if (pfx.compare ("surface") || pfx.compare ("scatter")
+                      || pfx.compare ("hggroup") || pfx.compare ("uipanel")
+                      || pfx.compare ("uitable"))
                     offset = 7;
                   else if (len > 9)
                     {
@@ -2729,7 +2735,7 @@
 graphics_object::set_value_or_default (const caseless_str& pname,
                                        const octave_value& val)
 {
-  if (val.is_string ())
+  if (val.is_string () && val.rows () == 1)
     {
       std::string sval = val.string_value ();
 
@@ -3055,9 +3061,7 @@
 delete_graphics_objects (const NDArray vals, bool from_root = false)
 {
   // Prevent redraw of partially deleted objects.
-  octave::unwind_protect frame;
-  frame.protect_var (delete_executing);
-  delete_executing = true;
+  octave::unwind_protect_var<bool> restore_var (delete_executing, true);
 
   for (octave_idx_type i = 0; i < vals.numel (); i++)
     delete_graphics_object (vals.elem (i), from_root);
@@ -3122,7 +3126,7 @@
   hlist = figure_handle_list (true);
 
   if (hlist.numel () != 0)
-    warning ("gh_manager::close_all_figures: some graphics elements failed to close.");
+    warning ("gh_manager::close_all_figures: some graphics elements failed to close");
 
   // Clear all callback objects from our list.
 
@@ -3296,7 +3300,7 @@
 /*
 ## test defaults are set in the order they were stored
 %!test
-%! set(0, "defaultfigureunits", "normalized");
+%! set (0, "defaultfigureunits", "normalized");
 %! set(0, "defaultfigureposition", [0.7 0 0.3 0.3]);
 %! hf = figure ("visible", "off");
 %! tol = 20 * eps;
@@ -3304,8 +3308,8 @@
 %!   assert (get (hf, "position"), [0.7 0 0.3 0.3], tol);
 %! unwind_protect_cleanup
 %!   close (hf);
-%!   set(0, "defaultfigureunits", "remove");
-%!   set(0, "defaultfigureposition", "remove");
+%!   set (0, "defaultfigureunits", "remove");
+%!   set (0, "defaultfigureposition", "remove");
 %! end_unwind_protect
 */
 
@@ -3483,15 +3487,15 @@
 }
 
 void
-base_properties::update_uicontextmenu (void) const
-{
-  if (uicontextmenu.get ().isempty ())
+base_properties::update_contextmenu (void) const
+{
+  if (contextmenu.get ().isempty ())
     return;
 
   gh_manager& gh_mgr
-    = octave::__get_gh_manager__ ("base_properties::update_uicontextmenu");
-
-  graphics_object go = gh_mgr.get_object (uicontextmenu.get ());
+    = octave::__get_gh_manager__ ("base_properties::update_contextmenu");
+
+  graphics_object go = gh_mgr.get_object (contextmenu.get ());
 
   if (go && go.isa ("uicontextmenu"))
     {
@@ -3605,7 +3609,7 @@
 %! hf = figure ("handlevisibility", "off", "visible", "off");
 %! hax = axes ("parent", hf, "handlevisibility", "off");
 %! unwind_protect
-%!   fcn = @(h) setappdata (h, "testdata", gcbo ());
+%!   fcn = @(h, ~) setappdata (h, "testdata", gcbo ());
 %!   addlistener (hf, "color", fcn);
 %!   addlistener (hax, "color", fcn);
 %!   set (hf, "color", "b");
@@ -4185,7 +4189,7 @@
 figure::properties::set___graphics_toolkit__ (const octave_value& val)
 {
   if (! val.is_string ())
-    error ("set___graphics_toolkit__ must be a string");
+    error ("set___graphics_toolkit__: toolkit must be a string");
 
   std::string nm = val.string_value ();
 
@@ -5267,7 +5271,7 @@
 axes::properties::sync_positions (void)
 {
   // First part is equivalent to 'update_tightinset ()'
-  if (activepositionproperty.is ("position"))
+  if (positionconstraint.is ("innerposition"))
     update_position ();
   else
     update_outerposition ();
@@ -5284,7 +5288,7 @@
   tightinset = tinset;
   set_units (old_units);
   update_transform ();
-  if (activepositionproperty.is ("position"))
+  if (positionconstraint.is ("innerposition"))
     update_position ();
   else
     update_outerposition ();
@@ -5295,13 +5299,13 @@
 %! hf = figure ("visible", "off");
 %! graphics_toolkit (hf, "qt");
 %! unwind_protect
-%!   subplot(2,1,1); plot(rand(10,1)); subplot(2,1,2); plot(rand(10,1));
+%!   subplot (2,1,1); plot (rand (10,1)); subplot (2,1,2); plot (rand (10,1));
 %!   hax = findall (gcf (), "type", "axes");
 %!   positions = cell2mat (get (hax, "position"));
 %!   outerpositions = cell2mat (get (hax, "outerposition"));
 %!   looseinsets = cell2mat (get (hax, "looseinset"));
 %!   tightinsets = cell2mat (get (hax, "tightinset"));
-%!   subplot(2,1,1); plot(rand(10,1)); subplot(2,1,2); plot(rand(10,1));
+%!   subplot (2,1,1); plot (rand (10,1)); subplot (2,1,2); plot (rand (10,1));
 %!   hax = findall (gcf (), "type", "axes");
 %!   assert (cell2mat (get (hax, "position")), positions, 1e-4);
 %!   assert (cell2mat (get (hax, "outerposition")), outerpositions, 1e-4);
@@ -5335,7 +5339,7 @@
 %! hf = figure ("visible", "off");
 %! graphics_toolkit (hf, "qt");
 %! fpos = get (hf, "position");
-%! set (gca, "activepositionproperty", "position");
+%! set (gca, "positionconstraint", "innerposition");
 %! unwind_protect
 %!   plot (rand (3));
 %!   position = get (gca, "position");
@@ -6269,9 +6273,7 @@
   zPlaneN = (zPlane == z_min ? z_max : z_min);
   fz = (z_max - z_min) / sqrt (dir(0)*dir(0) + dir(1)*dir(1));
 
-  octave::unwind_protect frame;
-  frame.protect_var (updating_axes_layout);
-  updating_axes_layout = true;
+  octave::unwind_protect_var<bool> restore_var (updating_axes_layout, true);
 
   xySym = (xd*yd*(xPlane-xPlaneN)*(yPlane-yPlaneN) > 0);
   zSign = (zd*(zPlane-zPlaneN) <= 0);
@@ -6431,9 +6433,8 @@
 
   bool isempty = xlabel_props.get_string ().isempty ();
 
-  octave::unwind_protect frame;
-  frame.protect_var (updating_xlabel_position);
-  updating_xlabel_position = true;
+  octave::unwind_protect_var<bool>
+    restore_var (updating_xlabel_position, true);
 
   if (! isempty)
     {
@@ -6536,9 +6537,8 @@
 
   bool isempty = ylabel_props.get_string ().isempty ();
 
-  octave::unwind_protect frame;
-  frame.protect_var (updating_ylabel_position);
-  updating_ylabel_position = true;
+  octave::unwind_protect_var<bool>
+    restore_var (updating_ylabel_position, true);
 
   if (! isempty)
     {
@@ -6642,9 +6642,8 @@
   bool camAuto = cameraupvectormode_is ("auto");
   bool isempty = zlabel_props.get_string ().isempty ();
 
-  octave::unwind_protect frame;
-  frame.protect_var (updating_zlabel_position);
-  updating_zlabel_position = true;
+  octave::unwind_protect_var<bool>
+    restore_updating_zlabel_position (updating_zlabel_position, true);
 
   if (! isempty)
     {
@@ -6767,9 +6766,7 @@
   text::properties& title_props
     = reinterpret_cast<text::properties&> (go.get_properties ());
 
-  octave::unwind_protect frame;
-  frame.protect_var (updating_title_position);
-  updating_title_position = true;
+  octave::unwind_protect_var<bool> restore_var (updating_title_position, true);
 
   if (title_props.positionmode_is ("auto"))
     {
@@ -6920,8 +6917,8 @@
 
       if (modified_limits)
         {
-          octave::unwind_protect frame;
-          frame.protect_var (updating_aspectratios);
+          octave::unwind_protect_var<std::set<double>>
+            restore_var (updating_aspectratios);
 
           updating_aspectratios.insert (get___myhandle__ ().value ());
 
@@ -7503,7 +7500,7 @@
 void
 axes::properties::update_outerposition (void)
 {
-  set_activepositionproperty ("outerposition");
+  set_positionconstraint ("outerposition");
   caseless_str old_units = get_units ();
   set_units ("normalized");
 
@@ -7562,7 +7559,7 @@
 void
 axes::properties::update_position (void)
 {
-  set_activepositionproperty ("position");
+  set_positionconstraint ("innerposition");
   caseless_str old_units = get_units ();
   set_units ("normalized");
 
@@ -7621,7 +7618,7 @@
   double right_margin = std::max (linset(2), tinset(2));
   double top_margin = std::max (linset(3), tinset(3));
 
-  if (activepositionproperty.is ("position"))
+  if (positionconstraint.is ("innerposition"))
     {
       Matrix innerbox = position.get ().matrix_value ();
 
@@ -8595,8 +8592,8 @@
 
 #undef FIX_LIMITS
 
-  octave::unwind_protect frame;
-  frame.protect_var (updating_axis_limits);
+  octave::unwind_protect_var<std::set<double>>
+    restore_var (updating_axis_limits);
 
   updating_axis_limits.insert (get_handle ().value ());
   bool is_auto;
@@ -8721,6 +8718,11 @@
           xproperties.set_has3Dkids ((max_val - min_val) >
                                      std::numeric_limits<double>::epsilon ());
 
+          // FIXME: How to correctly handle (positive or negative) log scale?
+          if ((! octave::math::isfinite (min_val)
+               || ! octave::math::isfinite (max_val))
+              && ! xproperties.zscale_is ("log"))
+            min_val = max_val = 0.;
 
           limits = xproperties.get_axis_limits (min_val, max_val,
                                                 min_pos, max_neg,
@@ -8795,8 +8797,8 @@
 
     }
 
-  octave::unwind_protect frame;
-  frame.protect_var (updating_axis_limits);
+  octave::unwind_protect_var<std::set<double>>
+    restore_var (updating_axis_limits);
 
   updating_axis_limits.insert (get_handle ().value ());
   bool is_auto;
@@ -9700,9 +9702,7 @@
 
   // FIXME: shouldn't we update facevertexalphadata here ?
 
-  octave::unwind_protect frame;
-  frame.protect_var (updating_patch_data);
-  updating_patch_data = true;
+  octave::unwind_protect_var<bool> restore_var (updating_patch_data, true);
 
   faces.set (idx);
   vertices.set (vert);
@@ -9942,9 +9942,7 @@
   // Update normals
   update_normals (true);
 
-  octave::unwind_protect frame;
-  frame.protect_var (updating_patch_data);
-  updating_patch_data = true;
+  octave::unwind_protect_var<bool> restore_var (updating_patch_data, true);
 
   set_xdata (xd);
   set_ydata (yd);
@@ -10206,6 +10204,120 @@
 // ---------------------------------------------------------------------
 
 octave_value
+scatter::properties::get_color_data (void) const
+{
+  octave_value c = get_cdata ();
+  if (c.is_undefined () || c.isempty ())
+    return Matrix ();
+  else
+    return convert_cdata (*this, c, c.columns () == 1, 2);
+}
+
+void
+scatter::properties::update_data (void)
+{
+  Matrix xd = get_xdata ().matrix_value ();
+  Matrix yd = get_ydata ().matrix_value ();
+  Matrix zd = get_zdata ().matrix_value ();
+  Matrix cd = get_cdata ().matrix_value ();
+  Matrix sd = get_sizedata ().matrix_value ();
+
+  bad_data_msg = "";
+  if (xd.dims () != yd.dims ()
+      || (xd.dims () != zd.dims () && ! zd.isempty ()))
+    {
+      bad_data_msg = "x/y/zdata must have the same dimensions";
+      return;
+    }
+
+  octave_idx_type x_rows = xd.rows ();
+  octave_idx_type c_cols = cd.columns ();
+  octave_idx_type c_rows = cd.rows ();
+
+  if (! cd.isempty () && (c_rows != 1 || c_cols != 3)
+      && (c_rows != x_rows || (c_cols != 1 && c_cols != 3)))
+    {
+      bad_data_msg = "cdata must be an rgb triplet or have the same number of "
+                     "rows as X and one or three columns";
+      return;
+    }
+
+  octave_idx_type s_rows = sd.rows ();
+  if (s_rows != 1 && s_rows != x_rows)
+    {
+      bad_data_msg = "sizedata must be a scalar or a vector with the same "
+                     "dimensions as X";
+      return;
+    }
+}
+
+static bool updating_scatter_cdata = false;
+
+void
+scatter::properties::update_color (void)
+{
+  if (updating_scatter_cdata)
+    return;
+
+  Matrix series_idx = get_seriesindex ().matrix_value ();
+  if (series_idx.isempty ())
+    return;
+
+  gh_manager& gh_mgr
+    = octave::__get_gh_manager__ ("scatter::properties::update_color");
+
+  graphics_object go = gh_mgr.get_object (get___myhandle__ ());
+
+  axes::properties& parent_axes_prop
+    = dynamic_cast<axes::properties&>
+        (go.get_ancestor ("axes").get_properties ());
+
+  Matrix color_order = parent_axes_prop.get_colororder ().matrix_value ();
+  octave_idx_type s = (static_cast<octave_idx_type> (series_idx(0)) - 1)
+                      % color_order.rows ();
+
+  Matrix color = Matrix (1, 3, 0.);
+  color(0) = color_order(s,0);
+  color(1) = color_order(s,1);
+  color(2) = color_order(s,2);
+
+  octave::unwind_protect_var<bool> restore_var (updating_scatter_cdata, true);
+
+  set_cdata (color);
+  set_cdatamode ("auto");
+}
+
+void
+scatter::initialize (const graphics_object& go)
+{
+  base_graphics_object::initialize (go);
+
+  Matrix series_idx = xproperties.get_seriesindex ().matrix_value ();
+  if (series_idx.isempty ())
+    {
+      // Increment series index counter in parent axes
+      axes::properties& parent_axes_prop
+        = dynamic_cast<axes::properties&>
+            (go.get_ancestor ("axes").get_properties ());
+
+      if (! parent_axes_prop.nextplot_is ("add"))
+        parent_axes_prop.set_nextseriesindex (1);
+
+      series_idx.resize (1, 1);
+      series_idx(0) = parent_axes_prop.get_nextseriesindex ();
+      xproperties.set_seriesindex (series_idx);
+
+      parent_axes_prop.set_nextseriesindex
+        (parent_axes_prop.get_nextseriesindex () + 1);
+    }
+
+  if (xproperties.cdatamode_is ("auto"))
+    xproperties.update_color ();
+}
+
+// ---------------------------------------------------------------------
+
+octave_value
 surface::properties::get_color_data (void) const
 {
   return convert_cdata (*this, get_cdata (), cdatamapping_is ("scaled"), 3);
@@ -10649,10 +10761,7 @@
 
   get_children_limits (min_val, max_val, min_pos, max_neg, kids, update_type);
 
-  octave::unwind_protect frame;
-  frame.protect_var (updating_hggroup_limits);
-
-  updating_hggroup_limits = true;
+  octave::unwind_protect_var<bool> restore_var (updating_hggroup_limits, true);
 
   if (limits(0) != min_val || limits(1) != max_val
       || limits(2) != min_pos || limits(3) != max_neg)
@@ -10739,10 +10848,7 @@
       update_type = 'a';
     }
 
-  octave::unwind_protect frame;
-  frame.protect_var (updating_hggroup_limits);
-
-  updating_hggroup_limits = true;
+  octave::unwind_protect_var<bool> restore_var (updating_hggroup_limits, true);
 
   Matrix limits (1, 4);
 
@@ -10798,8 +10904,8 @@
           graphics_object go = gh_mgr.get_object (hobj);
 
           if (go.valid_object ()
-              && go.get ("uicontextmenu") == get___myhandle__ ())
-            go.set ("uicontextmenu", Matrix ());
+              && go.get ("contextmenu") == get___myhandle__ ())
+            go.set ("contextmenu", Matrix ());
         }
     }
 }
@@ -11470,7 +11576,7 @@
                 {
                   octave_value p = popup(j);
                   if (! p.is_string () || p.isempty ())
-                    error ("set: pop-up menu definitions must be non-empty strings.");
+                    error ("set: pop-up menu definitions must be non-empty strings");
                 }
             }
           else if (! (v.is_string () || v.isempty ()))
@@ -11492,7 +11598,7 @@
     }
   else
     {
-      error ("set: expecting cell of strings.");
+      error ("set: expecting cell of strings");
     }
 }
 
@@ -11528,7 +11634,7 @@
     error_exists = true;
 
   if (error_exists)
-    error ("set: expecting either 'auto' or a cell of pixel values or auto.");
+    error ("set: expecting either 'auto' or a cell of pixel values or auto");
   else
     {
       if (columnwidth.set (val, true))
@@ -12350,7 +12456,7 @@
 
 /*
 ## Test interruptible/busyaction properties
-%!function cb (h)
+%!function cb (h, ~)
 %! setappdata (gcbf (), "cb_exec", [getappdata(gcbf (), "cb_exec") h]);
 %! drawnow ();
 %! setappdata (gcbf (), "cb_exec", [getappdata(gcbf (), "cb_exec") h]);
@@ -12433,6 +12539,7 @@
   plist_map["text"] = text::properties::factory_defaults ();
   plist_map["image"] = image::properties::factory_defaults ();
   plist_map["patch"] = patch::properties::factory_defaults ();
+  plist_map["scatter"] = scatter::properties::factory_defaults ();
   plist_map["surface"] = surface::properties::factory_defaults ();
   plist_map["light"] = light::properties::factory_defaults ();
   plist_map["hggroup"] = hggroup::properties::factory_defaults ();
@@ -12477,8 +12584,8 @@
 %! unwind_protect
 %!   assert (ishghandle (hf));
 %!   assert (! ishghandle (-hf));
-%!   ax = gca;
-%!   l = line;
+%!   ax = gca ();
+%!   l = line ();
 %!   assert (ishghandle (ax));
 %!   assert (! ishghandle (-ax));
 %!   assert (ishghandle ([l, -1, ax, hf]), logical ([1, 0, 1, 1]));
@@ -13228,7 +13335,7 @@
 
   if (go.isa ("surface"))
     nd = 3;
-  else if ((go.isa ("line") || go.isa ("patch"))
+  else if ((go.isa ("line") || go.isa ("patch") || go.isa ("scatter"))
            && ! go.get ("zdata").isempty ())
     nd = 3;
   else
@@ -13331,6 +13438,15 @@
   GO_BODY (patch);
 }
 
+DEFMETHOD (__go_scatter__, interp, args, ,
+           doc: /* -*- texinfo -*-
+@deftypefn {} {} __go_scatter__ (@var{parent})
+Undocumented internal function.
+@end deftypefn */)
+{
+  GO_BODY (scatter);
+}
+
 DEFMETHOD (__go_light__, interp, args, ,
            doc: /* -*- texinfo -*-
 @deftypefn {} {} __go_light__ (@var{parent})
@@ -13700,9 +13816,7 @@
   if (args.length () > 3)
     print_usage ();
 
-  octave::unwind_protect frame;
-
-  frame.protect_var (Vdrawnow_requested, false);
+  octave::unwind_protect_var<bool> restore_var (Vdrawnow_requested, false);
 
   // Redraw unless we are in the middle of a deletion.
 
@@ -14528,6 +14642,42 @@
   return ovl (go.get_toolkit ().get_pixels (go));
 }
 
+DEFMETHOD (__get_position__, interp, args, ,
+           doc: /* -*- texinfo -*-
+@deftypefn {} {@var{pos} =} __get_position__ (@var{h}, @var{units})
+Internal function.
+
+Return the position of the graphics object @var{h} in the specified
+@var{units}.
+@end deftypefn */)
+{
+  if (args.length () != 2)
+    print_usage ();
+
+  double h
+    = args(0).xdouble_value ("__get_position__: H must be a graphics handle");
+
+  std::string units
+    = args(1).xstring_value ("__get_position__: UNITS must be a string");
+
+  gh_manager& gh_mgr = interp.get_gh_manager ();
+
+  graphics_object go = gh_mgr.get_object (h);
+
+  if (h == 0 || ! go)
+    error ("__get_position__: H must be a handle to a valid graphics object");
+
+  graphics_object parent_go = gh_mgr.get_object (go.get_parent ());
+  Matrix bbox = parent_go.get_properties ().get_boundingbox (true)
+                .extract_n (0, 2, 1, 2);
+
+  Matrix pos = convert_position (go.get ("position").matrix_value (),
+                                 go.get ("units").string_value (),
+                                 units, bbox);
+
+  return ovl (pos);
+}
+
 DEFUN (__get_system_fonts__, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn {} {@var{font_struct} =} __get_system_fonts__ ()
--- a/libinterp/corefcn/graphics.in.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/graphics.in.h	Thu Nov 19 13:08:00 2020 -0800
@@ -2312,6 +2312,18 @@
 
   void set___modified__ (const octave_value& val) { __modified__ = val; }
 
+  // Redirect calls to "uicontextmenu" to "contextmenu".
+
+  graphics_handle get_uicontextmenu (void) const
+  {
+    return get_contextmenu ();
+  }
+
+  void set_uicontextmenu (const octave_value& val)
+  {
+    set_contextmenu (val);
+  }
+
   void reparent (const graphics_handle& new_parent) { parent = new_parent; }
 
   // Update data limits for AXIS_TYPE (xdata, ydata, etc.) in the parent
@@ -2322,7 +2334,7 @@
   virtual void update_axis_limits (const std::string& axis_type,
                                    const graphics_handle& h) const;
 
-  virtual void update_uicontextmenu (void) const;
+  virtual void update_contextmenu (void) const;
 
   virtual void delete_children (bool clear = false, bool from_root = false)
   {
@@ -2382,6 +2394,7 @@
     callback_property buttondownfcn , Matrix ()
     children_property children gf , Matrix ()
     bool_property clipping , "on"
+    handle_property contextmenu u , graphics_handle ()
     callback_property createfcn , Matrix ()
     callback_property deletefcn , Matrix ()
     radio_property handlevisibility u , "{on}|callback|off"
@@ -2393,7 +2406,7 @@
     bool_property selectionhighlight , "on"
     string_property tag s , ""
     string_property type frs , ty
-    handle_property uicontextmenu u , graphics_handle ()
+    handle_property uicontextmenu gsh , graphics_handle ()
     any_property userdata , Matrix ()
     bool_property visible u , "on"
 
@@ -2431,7 +2444,7 @@
 
   virtual void init (void)
   {
-    uicontextmenu.add_constraint ("uicontextmenu");
+    contextmenu.add_constraint ("uicontextmenu");
   }
 };
 
@@ -3471,6 +3484,43 @@
 
     void sync_positions (void);
 
+    // Redirect calls to "activepositionproperty" to "positionconstraint".
+
+    std::string get_activepositionproperty (void) const
+    {
+      std::string cur_val;
+
+      if (positionconstraint.is ("innerposition"))
+        cur_val = "position";
+      else
+        cur_val = "outerposition";
+
+      return cur_val;
+    }
+
+    void set_activepositionproperty (const octave_value& val)
+    {
+      // call set method to validate the input
+      activepositionproperty.set (val);
+
+      if (val.char_matrix_value ().row_as_string (0) == "position")
+        set_positionconstraint ("innerposition");
+      else
+        set_positionconstraint (val);
+    }
+
+    // Redirect calls to "innerposition" to "position".
+
+    octave_value get_innerposition (void) const
+    {
+      return get_position ();
+    }
+
+    void set_innerposition (const octave_value& val)
+    {
+      set_position (val);
+    }
+
     void update_autopos (const std::string& elem_type);
     void update_xlabel_position (void);
     void update_ylabel_position (void);
@@ -3640,9 +3690,12 @@
     // Programming note: Keep property list sorted if new ones are added.
 
     BEGIN_PROPERTIES (axes)
-      radio_property activepositionproperty , "{outerposition}|position"
+      radio_property activepositionproperty gsh , "{outerposition}|position"
       row_vector_property alim m , default_lim ()
       radio_property alimmode , "{auto}|manual"
+      // FIXME: not yet implemented
+      array_property alphamap , Matrix ()
+      radio_property alphascale , "{linear}|log"
       color_property ambientlightcolor , color_values (1, 1, 1)
       bool_property box u , "off"
       radio_property boxstyle , "{back}|full"
@@ -3661,12 +3714,15 @@
       array_property colormap sg , Matrix ()
       array_property colororder , default_colororder ()
       double_property colororderindex , 1.0
+      radio_property colorscale , "{linear}|log"
       array_property currentpoint , Matrix (2, 3, 0.0)
       row_vector_property dataaspectratio mu , Matrix (1, 3, 1.0)
       radio_property dataaspectratiomode u , "{auto}|manual"
       radio_property fontangle u , "{normal}|italic"
       string_property fontname u , OCTAVE_DEFAULT_FONTNAME
-      double_property fontsize u , 10
+      double_property fontsize mu , 10
+      // FIXME: not yet implemented
+      radio_property fontsizemode , "{auto}|manual"
       bool_property fontsmoothing u , "on"
       radio_property fontunits SU , "{points}|inches|centimeters|normalized|pixels"
       radio_property fontweight u , "{normal}|bold"
@@ -3675,8 +3731,15 @@
       color_property gridcolor m , color_property (color_values (0.15, 0.15, 0.15), radio_values ("none"))
       radio_property gridcolormode , "{auto}|manual"
       radio_property gridlinestyle , "{-}|--|:|-.|none"
+      array_property innerposition sg , default_axes_position ()
+      // FIXME: Should be an array of "interaction objects". Make it read-only for now.
+      any_property interactions r , Matrix ()
       double_property labelfontsizemultiplier u , 1.1
       radio_property layer u , "{bottom}|top"
+      // FIXME: Should be a "layoutoptions" object. Make it read-only for now.
+      handle_property layout r , graphics_handle ()
+      // FIXME: Should be a "legend" object. Make it read-only for now.
+      handle_property legend r , graphics_handle ()
       // FIXME: should be kind of string array.
       any_property linestyleorder S , "-"
       double_property linestyleorderindex , 1.0
@@ -3687,10 +3750,12 @@
       radio_property minorgridcolormode , "{auto}|manual"
       radio_property minorgridlinestyle , "{:}|-|--|-.|none"
       radio_property nextplot , "{replace}|add|replacechildren"
+      double_property nextseriesindex r , 1.0
       array_property outerposition u , default_axes_outerposition ()
       row_vector_property plotboxaspectratio mu , Matrix (1, 3, 1.0)
       radio_property plotboxaspectratiomode u , "{auto}|manual"
       array_property position u , default_axes_position ()
+      radio_property positionconstraint , "{outerposition}|innerposition"
       radio_property projection , "{orthographic}|perspective"
       radio_property sortmethod , "{depth}|childorder"
       radio_property tickdir mu , "{in}|out"
@@ -3702,9 +3767,12 @@
       handle_property title SOf , make_graphics_handle ("text", __myhandle__, false, false, false)
       double_property titlefontsizemultiplier u , 1.1
       radio_property titlefontweight u , "{bold}|normal"
-      // FIXME: uicontextmenu should be moved here.
+      // FIXME: Should be a "axestoolbar" object. Make it read-only for now.
+      handle_property toolbar r , graphics_handle ()
       radio_property units SU , "{normalized}|inches|centimeters|points|pixels|characters"
       array_property view u , default_axes_view ()
+      // FIXME: Should be a "ruler" object. Make it read-only for now.
+      handle_property xaxis r , graphics_handle ()
       radio_property xaxislocation u , "{bottom}|top|origin"
       color_property xcolor mu , color_property (color_values (0.15, 0.15, 0.15), radio_values ("none"))
       radio_property xcolormode , "{auto}|manual"
@@ -3722,6 +3790,8 @@
       radio_property xticklabelmode u , "{auto}|manual"
       double_property xticklabelrotation , 0.0
       radio_property xtickmode u , "{auto}|manual"
+      // FIXME: Should be a "ruler" object. Make it read-only for now.
+      handle_property yaxis r , graphics_handle ()
       radio_property yaxislocation u , "{left}|right|origin"
       color_property ycolor mu , color_property (color_values (0.15, 0.15, 0.15), radio_values ("none"))
       radio_property ycolormode , "{auto}|manual"
@@ -3738,6 +3808,8 @@
       radio_property yticklabelmode u , "{auto}|manual"
       double_property yticklabelrotation , 0.0
       radio_property ytickmode u , "{auto}|manual"
+      // FIXME: Should be a "ruler" object. Make it read-only for now.
+      handle_property zaxis r , graphics_handle ()
       color_property zcolor mu , color_property (color_values (0.15, 0.15, 0.15), radio_values ("none"))
       radio_property zcolormode , "{auto}|manual"
       radio_property zdir u , "{normal}|reverse"
@@ -4382,8 +4454,7 @@
       color_property edgecolor , color_property (radio_values ("{none}"), color_values (0, 0, 0))
       bool_property editing , "off"
       array_property extent rG , Matrix (1, 4, 0.0)
-      // FIXME: DEPRECATED: Remove "oblique" in version 7.
-      radio_property fontangle u , "{normal}|italic|oblique"
+      radio_property fontangle u , "{normal}|italic"
       string_property fontname u , OCTAVE_DEFAULT_FONTNAME
       double_property fontsize u , 10
       bool_property fontsmoothing u , "on"
@@ -4490,11 +4561,6 @@
     {
       update_font ();
       update_text_extent ();
-      // FIXME: DEPRECATED: Remove warning for "oblique" in version 7.
-      if (fontangle.is ("oblique"))
-        warning_with_id ("Octave:deprecated-property",
-                         "Setting 'fontangle' to '%s' is deprecated, \
-use 'italic' or 'normal'.", fontangle.current_value ().c_str ());
     }
     void update_fontweight (void) { update_font (); update_text_extent (); }
 
@@ -5078,6 +5144,238 @@
 
 // ---------------------------------------------------------------------
 
+class OCTINTERP_API scatter : public base_graphics_object
+{
+public:
+  class OCTINTERP_API properties : public base_properties
+  {
+  public:
+    octave_value get_color_data (void) const;
+
+    // Matlab allows incoherent data to be stored in scatter properties.
+    // The scatter object should then be ignored by the renderer.
+    bool has_bad_data (std::string& msg) const
+    {
+      msg = bad_data_msg;
+      return ! msg.empty ();
+    }
+
+    bool is_aliminclude (void) const
+    { return aliminclude.is_on (); }
+    std::string get_aliminclude (void) const
+    { return aliminclude.current_value (); }
+
+    bool is_climinclude (void) const
+    { return climinclude.is_on (); }
+    std::string get_climinclude (void) const
+    { return climinclude.current_value (); }
+
+    // See the genprops.awk script for an explanation of the
+    // properties declarations.
+    // Programming note: Keep property list sorted if new ones are added.
+
+    BEGIN_PROPERTIES (scatter)
+      array_property annotation , Matrix ()
+      array_property cdata mu , Matrix ()
+      radio_property cdatamode u , "{auto}|manual"
+      string_property cdatasource , ""
+      array_property datatiptemplate , Matrix ()
+      string_property displayname , ""
+      array_property latitudedata , Matrix ()
+      string_property latitudedatasource , ""
+      double_property linewidth , 0.5
+      array_property longitudedata , Matrix ()
+      string_property longitudedatasource , ""
+      radio_property marker , "{o}|+|*|.|x|s|square|d|diamond|^|v|>|<|p|pentagram|h|hexagram|none"
+      double_property markeredgealpha , 1.0
+      color_property markeredgecolor , color_property (radio_values ("{flat}|none"), color_values (0, 0, 0))
+      double_property markerfacealpha , 1.0
+      color_property markerfacecolor , color_property (radio_values ("{none}|auto|flat"), color_values (0, 0, 0))
+      array_property rdata , Matrix ()
+      string_property rdatasource , ""
+      array_property seriesindex u , Matrix ()
+      array_property sizedata u , Matrix ()
+      string_property sizedatasource , ""
+      array_property thetadata , Matrix ()
+      string_property thetadatasource , ""
+      array_property xdata u , Matrix ()
+      string_property xdatasource , ""
+      array_property ydata u , Matrix ()
+      string_property ydatasource , ""
+      array_property zdata u , Matrix ()
+      string_property zdatasource , ""
+
+      // hidden properties for limit computation
+      row_vector_property alim hlr , Matrix ()
+      row_vector_property clim hlr , Matrix ()
+      row_vector_property xlim hlr , Matrix ()
+      row_vector_property ylim hlr , Matrix ()
+      row_vector_property zlim hlr , Matrix ()
+      bool_property aliminclude hlg , "on"
+      bool_property climinclude hlg , "on"
+      bool_property xliminclude hl , "on"
+      bool_property yliminclude hl , "on"
+      bool_property zliminclude hl , "on"
+    END_PROPERTIES
+
+  protected:
+    void init (void)
+    {
+      xdata.add_constraint (dim_vector (-1, 1));
+      xdata.add_constraint (dim_vector (1, -1));
+      xdata.add_constraint (dim_vector (-1, 0));
+      xdata.add_constraint (dim_vector (0, -1));
+      ydata.add_constraint (dim_vector (-1, 1));
+      ydata.add_constraint (dim_vector (1, -1));
+      ydata.add_constraint (dim_vector (-1, 0));
+      ydata.add_constraint (dim_vector (0, -1));
+      zdata.add_constraint (dim_vector (-1, 1));
+      zdata.add_constraint (dim_vector (1, -1));
+      zdata.add_constraint (dim_vector (-1, 0));
+      zdata.add_constraint (dim_vector (0, -1));
+      sizedata.add_constraint ("min", 0.0, false);
+      sizedata.add_constraint (dim_vector (-1, 1));
+      sizedata.add_constraint (dim_vector (1, -1));
+      sizedata.add_constraint (dim_vector (-1, 0));
+      sizedata.add_constraint (dim_vector (0, -1));
+      cdata.add_constraint ("double");
+      cdata.add_constraint ("single");
+      cdata.add_constraint ("logical");
+      cdata.add_constraint ("int8");
+      cdata.add_constraint ("int16");
+      cdata.add_constraint ("int32");
+      cdata.add_constraint ("int64");
+      cdata.add_constraint ("uint8");
+      cdata.add_constraint ("uint16");
+      cdata.add_constraint ("uint32");
+      cdata.add_constraint ("uint64");
+      cdata.add_constraint ("real");
+      cdata.add_constraint (dim_vector (-1, 1));
+      cdata.add_constraint (dim_vector (-1, 3));
+      cdata.add_constraint (dim_vector (-1, 0));
+      cdata.add_constraint (dim_vector (0, -1));
+
+      linewidth.add_constraint ("min", 0.0, false);
+      seriesindex.add_constraint (dim_vector (1, 1));
+      seriesindex.add_constraint (dim_vector (-1, 0));
+      seriesindex.add_constraint (dim_vector (0, -1));
+    }
+
+  public:
+    void update_color (void);
+
+  private:
+    std::string bad_data_msg;
+
+    void update_xdata (void)
+    {
+      if (get_xdata ().isempty ())
+        {
+          // For compatibility with Matlab behavior,
+          // if x/ydata are set empty, silently empty other *data properties.
+          set_ydata (Matrix ());
+          set_zdata (Matrix ());
+          bool cdatamode_auto = cdatamode.is ("auto");
+          set_cdata (Matrix ());
+          if (cdatamode_auto)
+            set_cdatamode ("auto");
+        }
+
+      set_xlim (xdata.get_limits ());
+
+      update_data ();
+    }
+
+    void update_ydata (void)
+    {
+      if (get_ydata ().isempty ())
+        {
+          set_xdata (Matrix ());
+          set_zdata (Matrix ());
+          bool cdatamode_auto = cdatamode.is ("auto");
+          set_cdata (Matrix ());
+          if (cdatamode_auto)
+            set_cdatamode ("auto");
+        }
+
+      set_ylim (ydata.get_limits ());
+
+      update_data ();
+    }
+
+    void update_zdata (void)
+    {
+      set_zlim (zdata.get_limits ());
+
+      update_data ();
+    }
+
+    void update_sizedata (void)
+    {
+      update_data ();
+    }
+
+    void update_cdata (void)
+    {
+      if (get_cdata ().matrix_value ().rows () == 1)
+        set_clim (cdata.get_limits ());
+      else
+        clim = cdata.get_limits ();
+
+      update_data ();
+    }
+
+    void update_cdatamode (void)
+    {
+      if (cdatamode.is ("auto"))
+        update_color ();
+    }
+
+    void update_seriesindex (void)
+    {
+      if (cdatamode.is ("auto"))
+        update_color ();
+    }
+
+    void update_data (void);
+
+  };
+
+private:
+  properties xproperties;
+  property_list default_properties;
+
+public:
+  scatter (const graphics_handle& mh, const graphics_handle& p)
+    : base_graphics_object (), xproperties (mh, p)
+  {
+    // FIXME: seriesindex should increment by one each time a new scatter
+    // object is added to the axes.
+  }
+
+  ~scatter (void) = default;
+
+  base_properties& get_properties (void) { return xproperties; }
+
+  const base_properties& get_properties (void) const { return xproperties; }
+
+  bool valid_object (void) const { return true; }
+
+  bool has_readonly_property (const caseless_str& pname) const
+  {
+    bool retval = xproperties.has_readonly_property (pname);
+    if (! retval)
+      retval = base_properties::has_readonly_property (pname);
+    return retval;
+  }
+
+protected:
+  void initialize (const graphics_object& go);
+
+};
+
+// ---------------------------------------------------------------------
+
 class OCTINTERP_API surface : public base_graphics_object
 {
 public:
@@ -5430,6 +5728,7 @@
 
 // ---------------------------------------------------------------------
 
+// FIXME: This class has been renamed to "contextmenu" in Matlab R2020a.
 class OCTINTERP_API uicontextmenu : public base_graphics_object
 {
 public:
@@ -5523,8 +5822,7 @@
       bool_property clipping , "on"
       radio_property enable , "{on}|inactive|off"
       array_property extent rG , Matrix (1, 4, 0.0)
-      // FIXME: DEPRECATED: Remove "oblique" in version 7.
-      radio_property fontangle u , "{normal}|italic|oblique"
+      radio_property fontangle u , "{normal}|italic"
       string_property fontname u , OCTAVE_DEFAULT_FONTNAME
       double_property fontsize u , 10
       radio_property fontunits S , "inches|centimeters|normalized|{points}|pixels"
@@ -5574,11 +5872,6 @@
     void update_fontangle (void)
     {
       update_text_extent ();
-      // FIXME: DEPRECATED: Remove warning for "oblique" in version 7.
-      if (fontangle.is ("oblique"))
-        warning_with_id ("Octave:deprecated-property",
-                         "Setting 'fontangle' to '%s' is deprecated, \
-use 'italic' or 'normal'.", fontangle.current_value ().c_str ());
     }
     void update_fontweight (void) { update_text_extent (); }
 
@@ -5639,8 +5932,7 @@
       radio_property bordertype , "none|{etchedin}|etchedout|beveledin|beveledout|line"
       double_property borderwidth , 1
       bool_property clipping , "on"
-      // FIXME: DEPRECATED: Remove "oblique" in version 7.
-      radio_property fontangle , "{normal}|italic|oblique"
+      radio_property fontangle , "{normal}|italic"
       string_property fontname , OCTAVE_DEFAULT_FONTNAME
       double_property fontsize , 10
       radio_property fontunits S , "inches|centimeters|normalized|{points}|pixels"
@@ -5731,8 +6023,7 @@
       color_property backgroundcolor , color_values (0.94, 0.94, 0.94)
       radio_property bordertype , "none|{etchedin}|etchedout|beveledin|beveledout|line"
       double_property borderwidth , 1
-      // FIXME: DEPRECATED: Remove "oblique" in version 7.
-      radio_property fontangle , "{normal}|italic|oblique"
+      radio_property fontangle , "{normal}|italic"
       string_property fontname , OCTAVE_DEFAULT_FONTNAME
       double_property fontsize , 10
       radio_property fontunits S , "inches|centimeters|normalized|{points}|pixels"
@@ -5825,8 +6116,7 @@
       any_property data u , Matrix ()
       bool_property enable , "on"
       array_property extent rG , Matrix (1, 4, 0.0)
-      // FIXME: DEPRECATED: Remove "oblique" in version 7.
-      radio_property fontangle u , "{normal}|italic|oblique"
+      radio_property fontangle u , "{normal}|italic"
       string_property fontname u , OCTAVE_DEFAULT_FONTNAME
       double_property fontsize u , 10
       radio_property fontunits S , "inches|centimeters|normalized|{points}|pixels"
@@ -5867,11 +6157,6 @@
     void update_fontangle (void)
     {
       update_table_extent ();
-      // FIXME: DEPRECATED: Remove warning for "oblique" in version 7.
-      if (fontangle.is ("oblique"))
-        warning_with_id ("Octave:deprecated-property",
-                         "Setting 'fontangle' to '%s' is deprecated, \
-use 'italic' or 'normal'.", fontangle.current_value ().c_str ());
     }
     void update_fontweight (void) { update_table_extent (); }
   };
--- a/libinterp/corefcn/gsvd.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/gsvd.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -319,7 +319,7 @@
 %! B = B0;
 %! A(:, 3) = 2*A(:, 1) - A(:, 2);
 %! [U, V, X, C, S, R] = gsvd (A, B);
-%! D1 = zeros(5, 3);  D1(1:3, 1:3) = C;
+%! D1 = zeros (5, 3);  D1(1:3, 1:3) = C;
 %! D2 = S;
 %! assert (norm (diag (C).^2 + diag (S).^2 - ones (3, 1)) <= 1e-6);
 %! assert (norm ((U'*A*X) - D1*R) <= 1e-6);
@@ -329,7 +329,7 @@
 %!test <48807>
 %! B(:, 3) = 2*B(:, 1) - B(:, 2);
 %! [U, V, X, C, S, R] = gsvd (A, B);
-%! D1 = zeros(5, 2);  D1(1:2, 1:2) = C;
+%! D1 = zeros (5, 2);  D1(1:2, 1:2) = C;
 %! D2 = [S; zeros(1, 2)];
 %! assert (norm (diag (C).^2 + diag (S).^2 - ones (2, 1)) <= 1e-6);
 %! assert (norm ((U'*A*X) - D1*[zeros(2, 1) R]) <= 1e-6);
@@ -351,8 +351,8 @@
 %!test <48807>
 %! B(2, 2) = 0;
 %! [U, V, X, C, S, R] = gsvd (A, B);
-%! D1 = zeros(3, 5); D1(1, 1) = 1; D1(2:3, 2:3) = C;
-%! D2 = zeros(5, 5); D2(1:2, 2:3) = S; D2(3:4, 4:5) = eye (2);
+%! D1 = zeros (3, 5); D1(1, 1) = 1; D1(2:3, 2:3) = C;
+%! D2 = zeros (5, 5); D2(1:2, 2:3) = S; D2(3:4, 4:5) = eye (2);
 %! assert (norm (diag (C).^2 + diag (S).^2 - ones (2, 1)) <= 1e-6);
 %! assert (norm ((U'*A*X) - D1*R) <= 1e-6);
 %! assert (norm ((V'*B*X) - D2*R) <= 1e-6);
@@ -374,7 +374,7 @@
 %! A(:, 3) = 2*A(:, 1) - A(:, 2);
 %! B(:, 3) = 2*B(:, 1) - B(:, 2);
 %! [U, V, X, C, S, R]=gsvd (A, B);
-%! D1 = zeros(3, 4); D1(1:3, 1:3) = C;
+%! D1 = zeros (3, 4); D1(1:3, 1:3) = C;
 %! D2 = eye (4); D2(1:3, 1:3) = S; D2(5,:) = 0;
 %! assert (norm (diag (C).^2 + diag (S).^2 - ones (3, 1)) <= 1e-6);
 %! assert (norm ((U'*A*X) - D1*[zeros(4, 1) R]) <= 1e-6);
@@ -387,7 +387,7 @@
 %! A = A0;
 %! B = B0;
 %! [U, V, X, C, S, R] = gsvd (A, B);
-%! D1 = zeros(5, 3);  D1(1:3, 1:3) = C;
+%! D1 = zeros (5, 3);  D1(1:3, 1:3) = C;
 %! D2 = S;
 %! assert (norm (diag (C).^2 + diag (S).^2 - ones (3, 1)) <= 1e-6);
 %! assert (norm ((U'*A*X) - D1*R) <= 1e-6);
@@ -397,7 +397,7 @@
 %!test <48807>
 %! B(2, 2) = 0;
 %! [U, V, X, C, S, R] = gsvd (A, B);
-%! D1 = zeros(5, 3);  D1(1, 1) = 1;  D1(2:3, 2:3) = C;
+%! D1 = zeros (5, 3);  D1(1, 1) = 1;  D1(2:3, 2:3) = C;
 %! D2 = [zeros(2, 1) S; zeros(1, 3)];
 %! assert (norm (diag (C).^2 + diag (S).^2 - ones (2, 1)) <= 1e-6);
 %! assert (norm ((U'*A*X) - D1*R) <= 1e-6);
@@ -408,7 +408,7 @@
 %! B = B0;
 %! A(:, 3) = 2*A(:, 1) - A(:, 2);
 %! [U, V, X, C, S, R] = gsvd (A, B);
-%! D1 = zeros(5, 3);  D1(1:3, 1:3) = C;
+%! D1 = zeros (5, 3);  D1(1:3, 1:3) = C;
 %! D2 = S;
 %! assert (norm (diag (C).^2 + diag (S).^2 - ones (3, 1)) <= 1e-6);
 %! assert (norm ((U'*A*X) - D1*R) <= 1e-6);
@@ -418,7 +418,7 @@
 %!test <48807>
 %! B(:, 3) = 2*B(:, 1) - B(:, 2);
 %! [U, V, X, C, S, R] = gsvd (A, B);
-%! D1 = zeros(5, 2);  D1(1:2, 1:2) = C;
+%! D1 = zeros (5, 2);  D1(1:2, 1:2) = C;
 %! D2 = [S; zeros(1, 2)];
 %! assert (norm (diag (C).^2 + diag (S).^2 - ones (2, 1)) <= 1e-6);
 %! assert (norm ((U'*A*X) - D1*[zeros(2, 1) R]) <= 1e-6);
@@ -441,8 +441,8 @@
 %!test <48807>
 %! B(2, 2) = 0;
 %! [U, V, X, C, S, R] = gsvd (A, B);
-%! D1 = zeros(3, 5);  D1(1, 1) = 1;  D1(2:3, 2:3) = C;
-%! D2 = zeros(5,5);  D2(1:2, 2:3) = S;  D2(3:4, 4:5) = eye (2);
+%! D1 = zeros (3, 5);  D1(1, 1) = 1;  D1(2:3, 2:3) = C;
+%! D2 = zeros (5,5);  D2(1:2, 2:3) = S;  D2(3:4, 4:5) = eye (2);
 %! assert (norm (diag (C).^2 + diag (S).^2 - ones (2, 1)) <= 1e-6);
 %! assert (norm ((U'*A*X) - D1*R) <= 1e-6);
 %! assert (norm ((V'*B*X) - D2*R) <= 1e-6);
@@ -452,8 +452,8 @@
 %! B = B0;
 %! A(3, :) = 2*A(1, :) - A(2, :);
 %! [U, V, X, C, S, R] = gsvd (A, B);
-%! D1 = zeros(3, 5);  D1(1:3, 1:3) = C;
-%! D2 = zeros(5,5);  D2(1:3, 1:3) = S;  D2(4:5, 4:5) = eye (2);
+%! D1 = zeros (3, 5);  D1(1:3, 1:3) = C;
+%! D2 = zeros (5,5);  D2(1:3, 1:3) = S;  D2(4:5, 4:5) = eye (2);
 %! assert (norm (diag (C).^2 + diag (S).^2 - ones (3, 1)) <= 1e-6);
 %! assert (norm ((U'*A*X) - D1*R) <= 1e-6);
 %! assert (norm ((V'*B*X) - D2*R) <= 1e-6);
@@ -465,7 +465,7 @@
 %! A(:, 3) = 2*A(:, 1) - A(:, 2);
 %! B(:, 3) = 2*B(:, 1) - B(:, 2);
 %! [U, V, X, C, S, R] = gsvd (A, B);
-%! D1 = zeros(3, 4);  D1(1:3, 1:3) = C;
+%! D1 = zeros (3, 4);  D1(1:3, 1:3) = C;
 %! D2 = eye (4);  D2(1:3, 1:3) = S;  D2(5,:) = 0;
 %! assert (norm (diag (C).^2 + diag (S).^2 - ones (3, 1)) <= 1e-6);
 %! assert (norm ((U'*A*X) - D1*[zeros(4, 1) R]) <= 1e-6);
--- a/libinterp/corefcn/input.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/input.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -525,7 +525,7 @@
                   error ("__mfile_encoding__: conversion from encoding '%s' "
                          "not supported", encoding.c_str ());
                 else
-                  error ("__mfile_encoding__: error %d opening encoding '%s'.",
+                  error ("__mfile_encoding__: error %d opening encoding '%s'",
                          errno, encoding.c_str ());
               }
             else
@@ -541,6 +541,92 @@
     return retval;
   }
 
+  // Get part of the directory that would be added to the load path
+  static std::string load_path_dir (const std::string& dir)
+  {
+    std::string lp_dir = dir;
+
+    // strip trailing filesep
+    size_t ipos = lp_dir.find_last_not_of (sys::file_ops::dir_sep_chars ());
+    if (ipos != std::string::npos)
+      lp_dir = lp_dir.erase (ipos+1);
+
+    // strip trailing private folder
+    ipos = lp_dir.find_last_of (sys::file_ops::dir_sep_chars ());
+    if (ipos != std::string::npos
+        && lp_dir.substr (ipos+1).compare ("private") == 0)
+      {
+        lp_dir = lp_dir.erase (ipos);
+        ipos = lp_dir.find_last_of (sys::file_ops::dir_sep_chars ());
+      }
+
+    // strip trailing @class folder
+    if (ipos != std::string::npos && lp_dir[ipos+1] == '@')
+      {
+        lp_dir = lp_dir.erase (ipos);
+        ipos = lp_dir.find_last_of (sys::file_ops::dir_sep_chars ());
+      }
+
+    // strip (nested) +namespace folders
+    while (ipos != std::string::npos && lp_dir[ipos+1] == '+')
+      {
+        lp_dir = lp_dir.erase (ipos);
+        ipos = lp_dir.find_last_of (sys::file_ops::dir_sep_chars ());
+      }
+
+    return lp_dir;
+  }
+
+  std::string input_system::dir_encoding (const std::string& dir)
+  {
+    std::string enc = m_mfile_encoding;
+
+    auto enc_it = m_dir_encoding.find (load_path_dir (dir));
+    if (enc_it != m_dir_encoding.end ())
+      enc = enc_it->second;
+
+    return enc;
+  }
+
+  void input_system::set_dir_encoding (const std::string& dir,
+                                       std::string& enc)
+  {
+    // use lower case
+    std::transform (enc.begin (), enc.end (), enc.begin (), ::tolower);
+
+    if (enc.compare ("delete") == 0)
+      {
+        // Remove path from map
+        m_dir_encoding.erase (load_path_dir (dir));
+        return;
+      }
+    else if (enc.compare ("utf-8"))
+      {
+        // Check for valid encoding name.
+        // FIXME: This will probably not happen very often and opening the
+        //        encoder doesn't take long.
+        //        Should we cache working encoding identifiers anyway?
+        void *codec
+          = octave_iconv_open_wrapper (enc.c_str (), "utf-8");
+
+        if (codec == reinterpret_cast<void *> (-1))
+          {
+            if (errno == EINVAL)
+              error ("dir_encoding: conversion from encoding '%s' "
+                     "not supported", enc.c_str ());
+            else
+              error ("dir_encoding: error %d opening encoding '%s'.",
+                     errno, enc.c_str ());
+          }
+        else
+          octave_iconv_close_wrapper (codec);
+      }
+
+    m_dir_encoding[load_path_dir (dir)] = enc;
+
+    return;
+   }
+ 
   octave_value
   input_system::auto_repeat_debug_command (const octave_value_list& args,
                                            int nargout)
@@ -816,7 +902,14 @@
   public:
 
     file_reader (interpreter& interp, FILE *f_arg)
-      : base_reader (interp), m_file (f_arg) { }
+      : base_reader (interp), m_file (f_arg)
+    {
+      octave::input_system& input_sys = interp.get_input_system ();
+      m_encoding = input_sys.mfile_encoding ();
+    }
+
+    file_reader (interpreter& interp, FILE *f_arg, const std::string& enc)
+      : base_reader (interp), m_file (f_arg), m_encoding (enc) { }
 
     std::string get_input (const std::string& prompt, bool& eof);
 
@@ -828,6 +921,8 @@
 
     FILE *m_file;
 
+    std::string m_encoding;
+
     static const std::string s_in_src;
   };
 
@@ -861,6 +956,10 @@
     : m_rep (new file_reader (interp, file))
   { }
 
+  input_reader::input_reader (interpreter& interp, FILE *file, const std::string& enc)
+    : m_rep (new file_reader (interp, file, enc))
+  { }
+
   input_reader::input_reader (interpreter& interp, const std::string& str)
     : m_rep (new eval_string_reader (interp, str))
   { }
@@ -890,9 +989,15 @@
 
     std::string src_str = octave_fgets (m_file, eof);
 
-    input_system& input_sys = m_interpreter.get_input_system ();
+    std::string mfile_encoding;
 
-    std::string mfile_encoding = input_sys.mfile_encoding ();
+    if (m_encoding.empty ())
+      {
+        input_system& input_sys = m_interpreter.get_input_system ();
+        mfile_encoding = input_sys.mfile_encoding ();
+      }
+    else
+      mfile_encoding = m_encoding;
 
     std::string encoding;
     if (mfile_encoding.compare ("system") == 0)
@@ -934,8 +1039,7 @@
                  "converting from codepage '%s' to UTF-8: %s",
                  encoding.c_str (), std::strerror (errno));
 
-        unwind_protect frame;
-        frame.add_fcn (::free, static_cast<void *> (utf8_str));
+        unwind_action free_utf8_str ([=] () { ::free (utf8_str); });
 
         src_str = std::string (reinterpret_cast<char *> (utf8_str), length);
       }
@@ -1412,6 +1516,73 @@
   return input_sys.mfile_encoding (args, nargout);
 }
 
+DEFMETHOD (dir_encoding, interp, args, nargout,
+           doc: /* -*- texinfo -*-
+@deftypefn {}  {@var{current_encoding} =} dir_encoding (@var{dir})
+@deftypefnx {} {@var{prev_encoding} =} dir_encoding (@var{dir}, @var{encoding})
+@deftypefnx {} {} dir_encoding (@dots{})
+Set and query the @var{encoding} that is used for reading m-files in @var{dir}.
+
+That encoding overrides the (globally set) m-file encoding.
+
+The string @var{DIR} must match the form how the directory would appear in the
+load path.
+
+The @var{encoding} must be a valid encoding identifier or @code{"delete"}.  In
+the latter case, the (globally set) m-file encoding will be used for the given
+@var{dir}.
+
+The currently or previously used encoding is returned in @var{current_encoding}
+or @var{prev_encoding}, respectively.  The output argument must be explicitly
+requested.
+
+The directory encoding is automatically read from the file @file{.oct-config}
+when a new path is added to the load path (for example with @code{addpath}).
+To set the encoding for all files in the same folder, that file must contain
+a line starting with @code{"encoding="} followed by the encoding identifier.
+
+For example to set the file encoding for all files in the same folder to
+ISO 8859-1 (Latin-1), create a file @file{.oct-config} with the following
+content:
+
+@example
+encoding=iso8859-1
+@end example
+
+If the file encoding is changed after the files have already been parsed, the
+files have to be parsed again for that change to take effect.  That can be done
+with the command @code{clear all}.
+
+@seealso{addpath, path}
+@end deftypefn */)
+{
+  int nargin = args.length ();
+
+  if (nargin < 1 || nargin > 2)
+    print_usage ();
+
+  std::string dir
+    = args(0).xstring_value ("dir_encoding: DIR must be a string");
+
+  octave_value retval;
+
+  octave::input_system& input_sys = interp.get_input_system ();
+
+  if (nargout > 0)
+    retval = input_sys.dir_encoding (dir);
+
+  if (nargin > 1)
+    {
+      std::string encoding
+        = args(1).xstring_value ("dir_encoding: ENCODING must be a string");
+
+      input_sys.set_dir_encoding (dir, encoding);
+    }
+
+  return ovl (retval);
+
+}
+
 DEFMETHOD (auto_repeat_debug_command, interp, args, nargout,
            doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{val} =} auto_repeat_debug_command ()
@@ -1430,40 +1601,3 @@
 
   return input_sys.auto_repeat_debug_command (args, nargout);
 }
-
-// Always define these functions.  The macro is intended to allow the
-// declarations to be hidden, not so that Octave will not provide the
-// functions if they are requested.
-
-// #if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-bool
-octave_yes_or_no (const std::string& prompt)
-{
-  octave::input_system& input_sys
-    = octave::__get_input_system__ ("set_default_prompts");
-
-  return input_sys.yes_or_no (prompt);
-}
-
-void
-remove_input_event_hook_functions (void)
-{
-  octave::input_system& input_sys
-    = octave::__get_input_system__ ("remove_input_event_hook_functions");
-
-  input_sys.clear_input_event_hooks ();
-}
-
-// Fix things up so that input can come from the standard input.  This
-// may need to become much more complicated, which is why it's in a
-// separate function.
-
-FILE *
-get_input_from_stdin (void)
-{
-  octave::command_editor::set_input_stream (stdin);
-  return octave::command_editor::get_input_stream ();
-}
-
-// #endif
--- a/libinterp/corefcn/input.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/input.h	Thu Nov 19 13:08:00 2020 -0800
@@ -34,6 +34,7 @@
 
 #include <memory>
 #include <string>
+#include <unordered_map>
 
 #include "hook-fcn.h"
 #include "oct-time.h"
@@ -147,6 +148,10 @@
 
     void set_mfile_encoding (const std::string& s) { m_mfile_encoding = s; }
 
+    std::string dir_encoding (const std::string& dir);
+
+    void set_dir_encoding (const std::string& dir, std::string& enc);
+
     octave_value
     auto_repeat_debug_command (const octave_value_list& args, int nargout);
 
@@ -199,6 +204,9 @@
     // Codepage which is used to read .m files
     std::string m_mfile_encoding;
 
+    // map of directories -> used mfile encoding
+    std::unordered_map<std::string, std::string> m_dir_encoding;
+
     // TRUE means repeat last debug command if the user just types RET.
     bool m_auto_repeat_debug_command;
 
@@ -259,6 +267,8 @@
 
     input_reader (interpreter& interp, FILE *file);
 
+    input_reader (interpreter& interp, FILE *file, const std::string& enc);
+
     input_reader (interpreter& interp, const std::string& str);
 
     input_reader (const input_reader& ir) = default;
@@ -298,17 +308,4 @@
   };
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (5, "use 'octave::input_system::yes_or_no' instead")
-extern bool octave_yes_or_no (const std::string& prompt);
-
-OCTAVE_DEPRECATED (5, "use 'octave::input_system::clear_input_event_hooks' instead")
-extern void remove_input_event_hook_functions (void);
-
-OCTAVE_DEPRECATED (5, "this function will be removed in a future version of Octave")
-extern OCTINTERP_API FILE * get_input_from_stdin (void);
-
 #endif
-
-#endif
--- a/libinterp/corefcn/interpreter.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/interpreter.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -295,6 +295,15 @@
   return retval;
 }
 
+DEFMETHOD (__traditional__, interp, , ,
+           doc: /* -*- texinfo -*-
+@deftypefn {} {} __traditional__ ()
+Undocumented internal function.
+@end deftypefn */)
+{
+  return ovl (interp.traditional ());
+}
+
 namespace octave
 {
   temporary_file_list::~temporary_file_list (void)
@@ -463,6 +472,7 @@
       m_read_site_files (true),
       m_read_init_files (m_app_context != nullptr),
       m_verbose (false),
+      m_traditional (false),
       m_inhibit_startup_message (false),
       m_load_path_initialized (false),
       m_history_initialized (false),
@@ -513,7 +523,6 @@
       m_display_info.initialize ();
 
     bool line_editing = false;
-    bool traditional = false;
 
     if (m_app_context)
       {
@@ -565,7 +574,7 @@
             && ! options.forced_line_editing ())
           line_editing = false;
 
-        traditional = options.traditional ();
+        m_traditional = options.traditional ();
 
         // FIXME: if possible, perform the following actions directly
         // instead of using the interpreter-level functions.
@@ -625,7 +634,7 @@
     // This should be done before initializing the load path because
     // some PKG_ADD files might need --traditional behavior.
 
-    if (traditional)
+    if (m_traditional)
       maximum_braindamage ();
 
     octave_interpreter_ready = true;
@@ -700,7 +709,7 @@
         frame.add_method (m_load_path, &load_path::set_add_hook,
                           m_load_path.get_add_hook ());
 
-        m_load_path.set_add_hook ([this] (const std::string& dir)
+        m_load_path.set_add_hook ([=] (const std::string& dir)
                                   { this->execute_pkg_add (dir); });
 
         m_load_path.initialize (set_initial_path);
@@ -1383,6 +1392,7 @@
     // FIXME: should these actions be handled as a list of functions
     // to call so users can add their own chdir handlers?
 
+    m_load_path.read_dir_config (".");
     m_load_path.update ();
 
     m_event_manager.directory_changed (sys::env::get_current_directory ());
--- a/libinterp/corefcn/interpreter.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/interpreter.h	Thu Nov 19 13:08:00 2020 -0800
@@ -180,6 +180,16 @@
       m_verbose = flag;
     }
 
+    void traditional (bool flag)
+    {
+      m_traditional = flag;
+    }
+
+    bool traditional (void) const
+    {
+      return m_traditional;
+    }
+
     void inhibit_startup_message (bool flag)
     {
       m_inhibit_startup_message = flag;
@@ -554,6 +564,8 @@
 
     bool m_verbose;
 
+    bool m_traditional;
+
     bool m_inhibit_startup_message;
 
     bool m_load_path_initialized;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/jsondecode.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,557 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include "defun.h"
+#include "error.h"
+#include "errwarn.h"
+#include "ovl.h"
+#include "parse.h"
+
+#if defined (HAVE_RAPIDJSON)
+#  include <rapidjson/document.h>
+#  include <rapidjson/error/en.h>
+#endif
+
+#if defined (HAVE_RAPIDJSON)
+
+octave_value
+decode (const rapidjson::Value& val, const octave_value_list& options);
+
+//! Decodes a numerical JSON value into a scalar number.
+//!
+//! @param val JSON value that is guaranteed to be a numerical value.
+//!
+//! @return @ref octave_value that contains the numerical value of @p val.
+//!
+//! @b Example:
+//!
+//! @code{.cc}
+//! rapidjson::Document d;
+//! d.Parse ("123");
+//! octave_value num = decode_number (d);
+//! @endcode
+
+octave_value
+decode_number (const rapidjson::Value& val)
+{
+  if (val.IsUint ())
+    return octave_value (val.GetUint ());
+  else if (val.IsInt ())
+    return octave_value (val.GetInt ());
+  else if (val.IsUint64 ())
+    return octave_value (val.GetUint64 ());
+  else if (val.IsInt64 ())
+    return octave_value (val.GetInt64 ());
+  else if (val.IsDouble ())
+    return octave_value (val.GetDouble ());
+  else
+    error ("jsondecode: unidentified type");
+}
+
+//! Decodes a JSON object into a scalar struct.
+//!
+//! @param val JSON value that is guaranteed to be a JSON object.
+//! @param options @c ReplacementStyle and @c Prefix options with their values.
+//!
+//! @return @ref octave_value that contains the equivalent scalar struct of @p val.
+//!
+//! @b Example:
+//!
+//! @code{.cc}
+//! rapidjson::Document d;
+//! d.Parse ("{\"a\": 1, \"b\": 2}");
+//! octave_value struct = decode_object (d, octave_value_list ());
+//! @endcode
+
+octave_value
+decode_object (const rapidjson::Value& val, const octave_value_list& options)
+{
+  octave_scalar_map retval;
+
+  // Validator function to guarantee legitimate variable name.
+  std::string fcn_name = "matlab.lang.makeValidName";
+
+  for (const auto& pair : val.GetObject ())
+    {
+      octave_value_list args = octave_value_list (pair.name.GetString ());
+      args.append (options);
+      std::string validName = octave::feval (fcn_name,args)(0).string_value ();
+      retval.assign (validName, decode (pair.value, options));
+    }
+
+  return retval;
+}
+
+//! Decodes a JSON array that contains only numerical or null values
+//! into an NDArray.
+//!
+//! @param val JSON value that is guaranteed to be a numeric array.
+//!
+//! @return @ref octave_value that contains the equivalent NDArray of @p val.
+//!
+//! @b Example:
+//!
+//! @code{.cc}
+//! rapidjson::Document d;
+//! d.Parse ("[1, 2, 3, 4]");
+//! octave_value numeric_array = decode_numeric_array (d);
+//! @endcode
+
+octave_value
+decode_numeric_array (const rapidjson::Value& val)
+{
+  NDArray retval (dim_vector (val.Size (), 1));
+  octave_idx_type index = 0;
+  for (const auto& elem : val.GetArray ())
+    retval(index++) = elem.IsNull () ? octave_NaN
+                                     : decode_number (elem).double_value ();
+  return retval;
+}
+
+//! Decodes a JSON array that contains only boolean values into a boolNDArray.
+//!
+//! @param val JSON value that is guaranteed to be a boolean array.
+//!
+//! @return @ref octave_value that contains the equivalent boolNDArray of @p val.
+//!
+//! @b Example:
+//!
+//! @code{.cc}
+//! rapidjson::Document d;
+//! d.Parse ("[true, false, true]");
+//! octave_value boolean_array = decode_boolean_array (d);
+//! @endcode
+
+octave_value
+decode_boolean_array (const rapidjson::Value& val)
+{
+  boolNDArray retval (dim_vector (val.Size (), 1));
+  octave_idx_type index = 0;
+  for (const auto& elem : val.GetArray ())
+    retval(index++) = elem.GetBool ();
+  return retval;
+}
+
+//! Decodes a JSON array that contains different types
+//! or string values only into a Cell.
+//!
+//! @param val JSON value that is guaranteed to be a mixed or string array.
+//! @param options @c ReplacementStyle and @c Prefix options with their values.
+//!
+//! @return @ref octave_value that contains the equivalent Cell of @p val.
+//!
+//! @b Example (decoding a string array):
+//!
+//! @code{.cc}
+//! rapidjson::Document d;
+//! d.Parse ("[\"foo\", \"bar\", \"baz\"]");
+//! octave_value cell = decode_string_and_mixed_array (d, octave_value_list ());
+//! @endcode
+//!
+//! @b Example (decoding a mixed array):
+//!
+//! @code{.cc}
+//! rapidjson::Document d;
+//! d.Parse ("[\"foo\", 123, true]");
+//! octave_value cell = decode_string_and_mixed_array (d, octave_value_list ());
+//! @endcode
+
+octave_value
+decode_string_and_mixed_array (const rapidjson::Value& val,
+                               const octave_value_list& options)
+{
+  Cell retval (dim_vector (val.Size (), 1));
+  octave_idx_type index = 0;
+  for (const auto& elem : val.GetArray ())
+    retval(index++) = decode (elem, options);
+  return retval;
+}
+
+//! Decodes a JSON array that contains only objects into a Cell or struct array
+//! depending on the similarity of the objects' keys.
+//!
+//! @param val JSON value that is guaranteed to be an object array.
+//! @param options @c ReplacementStyle and @c Prefix options with their values.
+//!
+//! @return @ref octave_value that contains the equivalent Cell
+//! or struct array of @p val.
+//!
+//! @b Example (returns a struct array):
+//!
+//! @code{.cc}
+//! rapidjson::Document d;
+//! d.Parse ("[{\"a\":1,\"b\":2},{\"a\":3,\"b\":4}]");
+//! octave_value object_array = decode_object_array (d, octave_value_list ());
+//! @endcode
+//!
+//! @b Example (returns a Cell):
+//!
+//! @code{.cc}
+//! rapidjson::Document d;
+//! d.Parse ("[{\"a\":1,\"b\":2},{\"b\":3,\"a\":4}]");
+//! octave_value object_array = decode_object_array (d, octave_value_list ());
+//! @endcode
+
+octave_value
+decode_object_array (const rapidjson::Value& val,
+                     const octave_value_list& options)
+{
+  Cell struct_cell = decode_string_and_mixed_array (val, options).cell_value ();
+  string_vector field_names = struct_cell(0).scalar_map_value ().fieldnames ();
+
+  bool same_field_names = true;
+  for (octave_idx_type i = 1; i < struct_cell.numel (); ++i)
+    if (field_names.std_list ()
+        != struct_cell(i).scalar_map_value ().fieldnames ().std_list ())
+      {
+        same_field_names = false;
+        break;
+      }
+
+  if (same_field_names)
+    {
+      octave_map struct_array;
+      Cell value (dim_vector (struct_cell.numel (), 1));
+      for (octave_idx_type i = 0; i < field_names.numel (); ++i)
+        {
+          for (octave_idx_type k = 0; k < struct_cell.numel (); ++k)
+            value(k) = struct_cell(k).scalar_map_value ().getfield (field_names(i));
+          struct_array.assign (field_names(i), value);
+        }
+      return struct_array;
+    }
+  else
+    return struct_cell;
+}
+
+//! Decodes a JSON array that contains only arrays into a Cell or an NDArray
+//! depending on the dimensions and element types of the sub-arrays.
+//!
+//! @param val JSON value that is guaranteed to be an array of arrays.
+//! @param options @c ReplacementStyle and @c Prefix options with their values.
+//!
+//! @return @ref octave_value that contains the equivalent Cell
+//! or NDArray of @p val.
+//!
+//! @b Example (returns an NDArray):
+//!
+//! @code{.cc}
+//! rapidjson::Document d;
+//! d.Parse ("[[1, 2], [3, 4]]");
+//! octave_value array = decode_array_of_arrays (d, octave_value_list ());
+//! @endcode
+//!
+//! @b Example (returns a Cell):
+//!
+//! @code{.cc}
+//! rapidjson::Document d;
+//! d.Parse ("[[1, 2], [3, 4, 5]]");
+//! octave_value cell = decode_array_of_arrays (d, octave_value_list ());
+//! @endcode
+
+octave_value
+decode_array_of_arrays (const rapidjson::Value& val,
+                        const octave_value_list& options)
+{
+  // Some arrays should be decoded as NDArrays and others as cell arrays
+  Cell cell = decode_string_and_mixed_array (val, options).cell_value ();
+
+  // Only arrays with sub-arrays of booleans and numericals will return NDArray
+  bool is_bool = cell(0).is_bool_matrix ();
+  dim_vector sub_array_dims = cell(0).dims ();
+  octave_idx_type sub_array_ndims = cell(0).ndims ();
+  octave_idx_type cell_numel = cell.numel ();
+  for (octave_idx_type i = 0; i < cell_numel; ++i)
+    {
+      // If one element is cell return the cell array as at least one of the
+      // sub-arrays area either an array of: strings, objects or mixed array
+      if (cell(i).iscell ())
+        return cell;
+      // If not the same dim of elements or dim = 0, return cell array
+      if (cell(i).dims () != sub_array_dims || sub_array_dims == dim_vector ())
+        return cell;
+      // If not numeric sub-arrays only or bool sub-arrays only,
+      // return cell array
+      if (cell(i).is_bool_matrix () != is_bool)
+        return cell;
+    }
+
+  // Calculate the dims of the output array
+  dim_vector array_dims;
+  array_dims.resize (sub_array_ndims + 1);
+  array_dims(0) = cell_numel;
+  for (auto i = 1; i < sub_array_ndims + 1; i++)
+    array_dims(i) = sub_array_dims(i-1);
+  NDArray array (array_dims);
+
+  // Populate the array with specific order to generate MATLAB-identical output
+  octave_idx_type array_index = 0;
+  for (octave_idx_type i = 0; i < array.numel () / cell_numel; ++i)
+    for (octave_idx_type k = 0; k < cell_numel; ++k)
+      array(array_index++) = cell(k).array_value ()(i);
+
+  if (is_bool)
+    return boolNDArray (array);
+  else
+    return array;
+}
+
+//! Decodes any type of JSON arrays.  This function only serves as an interface
+//! by choosing which function to call from the previous functions.
+//!
+//! @param val JSON value that is guaranteed to be an array.
+//! @param options @c ReplacementStyle and @c Prefix options with their values.
+//!
+//! @return @ref octave_value that contains the output of decoding @p val.
+//!
+//! @b Example:
+//!
+//! @code{.cc}
+//! rapidjson::Document d;
+//! d.Parse ("[[1, 2], [3, 4, 5]]");
+//! octave_value array = decode_array (d, octave_value_list ());
+//! @endcode
+
+octave_value
+decode_array (const rapidjson::Value& val, const octave_value_list& options)
+{
+  // Handle empty arrays
+  if (val.Empty ())
+    return NDArray ();
+
+  // Compare with other elements to know if the array has multiple types
+  rapidjson::Type array_type = val[0].GetType ();
+  // Check if the array is numeric and if it has multiple types
+  bool same_type = true;
+  bool is_numeric = true;
+  for (const auto& elem : val.GetArray ())
+    {
+      rapidjson::Type current_elem_type = elem.GetType ();
+      if (is_numeric && ! (current_elem_type == rapidjson::kNullType
+          || current_elem_type == rapidjson::kNumberType))
+        is_numeric = false;
+      if (same_type && (current_elem_type != array_type))
+        // RapidJSON doesn't have kBoolean Type it has kTrueType and kFalseType
+        if (! ((current_elem_type == rapidjson::kTrueType
+                && array_type == rapidjson::kFalseType)
+            || (current_elem_type == rapidjson::kFalseType
+                && array_type == rapidjson::kTrueType)))
+          same_type = false;
+    }
+
+  if (is_numeric)
+    return decode_numeric_array (val);
+
+  if (same_type && (array_type != rapidjson::kStringType))
+    {
+      if (array_type == rapidjson::kTrueType
+          || array_type == rapidjson::kFalseType)
+        return decode_boolean_array (val);
+      else if (array_type == rapidjson::kObjectType)
+        return decode_object_array (val, options);
+      else if (array_type == rapidjson::kArrayType)
+        return decode_array_of_arrays (val, options);
+      else
+        error ("jsondecode: unidentified type");
+    }
+  else
+    return decode_string_and_mixed_array (val, options);
+}
+
+//! Decodes any JSON value.  This function only serves as an interface
+//! by choosing which function to call from the previous functions.
+//!
+//! @param val JSON value.
+//! @param options @c ReplacementStyle and @c Prefix options with their values.
+//!
+//! @return @ref octave_value that contains the output of decoding @p val.
+//!
+//! @b Example:
+//!
+//! @code{.cc}
+//! rapidjson::Document d;
+//! d.Parse ("[{\"a\":1,\"b\":2},{\"b\":3,\"a\":4}]");
+//! octave_value value = decode (d, octave_value_list ());
+//! @endcode
+
+octave_value
+decode (const rapidjson::Value& val, const octave_value_list& options)
+{
+  if (val.IsBool ())
+    return val.GetBool ();
+  else if (val.IsNumber ())
+    return decode_number (val);
+  else if (val.IsString ())
+    return val.GetString ();
+  else if (val.IsObject ())
+    return decode_object (val, options);
+  else if (val.IsNull ())
+    return NDArray ();
+  else if (val.IsArray ())
+    return decode_array (val, options);
+  else
+    error ("jsondecode: unidentified type");
+}
+
+#endif
+
+DEFUN (jsondecode, args, ,
+       doc: /* -*- texinfo -*-
+@deftypefn  {} {@var{object} =} jsondecode (@var{JSON_txt})
+@deftypefnx {} {@var{object} =} jsondecode (@dots{}, "ReplacementStyle", @var{rs})
+@deftypefnx {} {@var{object} =} jsondecode (@dots{}, "Prefix", @var{pfx})
+
+Decode text that is formatted in JSON.
+
+The input @var{JSON_txt} is a string that contains JSON text.
+
+The output @var{object} is an Octave object that contains the result of
+decoding @var{JSON_txt}.
+
+For more information about the options @qcode{"ReplacementStyle"} and
+@qcode{"Prefix"}, see
+@ref{XREFmatlab_lang_makeValidName,,matlab.lang.makeValidName}.
+
+NOTE: Decoding and encoding JSON text is not guaranteed to reproduce the
+original text as some names may be changed by @code{matlab.lang.makeValidName}.
+
+This table shows the conversions from JSON data types to Octave data types:
+
+@multitable @columnfractions 0.50 0.50
+@headitem JSON data type @tab Octave data type
+@item Boolean @tab scalar logical
+@item Number @tab scalar double
+@item String @tab vector of characters
+@item Object @tab scalar struct (field names of the struct may be different from the keys of the JSON object due to @code{matlab_lang_makeValidName}
+@item null, inside a numeric array @tab @code{NaN}
+@item null, inside a non-numeric array @tab empty double array @code{[]}
+@item Array, of different data types @tab cell array
+@item Array, of Booleans @tab logical array
+@item Array, of Numbers @tab double array
+@item Array, of Strings @tab cell array of character vectors (@code{cellstr})
+@item Array of Objects, same field names @tab struct array
+@item Array of Objects, different field names @tab cell array of scalar structs
+@end multitable
+
+Examples:
+
+@example
+@group
+jsondecode ('[1, 2, null, 3]')
+    @result{} ans =
+
+      1
+      2
+    NaN
+      3
+@end group
+
+@group
+jsondecode ('["foo", "bar", ["foo", "bar"]]')
+    @result{} ans =
+       @{
+         [1,1] = foo
+         [2,1] = bar
+         [3,1] =
+         @{
+           [1,1] = foo
+           [2,1] = bar
+         @}
+
+       @}
+@end group
+
+@group
+jsondecode ('@{"nu#m#ber": 7, "s#tr#ing": "hi"@}', ...
+            'ReplacementStyle', 'delete')
+    @result{} scalar structure containing the fields:
+
+         number = 7
+         string = hi
+@end group
+
+@group
+jsondecode ('@{"1": "one", "2": "two"@}', 'Prefix', 'm_')
+    @result{} scalar structure containing the fields:
+
+         m_1 = one
+         m_2 = two
+@end group
+@end example
+
+@seealso{jsonencode, matlab.lang.makeValidName}
+@end deftypefn */)
+{
+#if defined (HAVE_RAPIDJSON)
+
+  int nargin = args.length ();
+
+  // makeValidName options are pairs, the number of arguments must be odd.
+  if (! (nargin % 2))
+    print_usage ();
+
+  if (! args(0).is_string ())
+    error ("jsondecode: JSON_TXT must be a character string");
+
+  std::string json = args(0).string_value ();
+  rapidjson::Document d;
+  // DOM is chosen instead of SAX as SAX publishes events to a handler that
+  // decides what to do depending on the event only.  This will cause a
+  // problem in decoding JSON arrays as the output may be an array or a cell
+  // and that doesn't only depend on the event (startArray) but also on the
+  // types of the elements inside the array.
+  d.Parse <rapidjson::kParseNanAndInfFlag> (json.c_str ());
+
+  if (d.HasParseError ())
+    error ("jsondecode: parse error at offset %u: %s\n",
+           static_cast<unsigned int> (d.GetErrorOffset ()) + 1,
+           rapidjson::GetParseError_En (d.GetParseError ()));
+
+  return decode (d, args.slice (1, nargin - 1));
+
+#else
+
+  octave_unused_parameter (args);
+
+  err_disabled_feature ("jsondecode", "JSON decoding through RapidJSON");
+
+#endif
+}
+
+/*
+Functional BIST tests are located in test/json/jsondecode_BIST.tst
+
+## Input validation tests
+%!testif HAVE_RAPIDJSON
+%! fail ("jsondecode ()");
+%! fail ("jsondecode ('1', 2)");
+%! fail ("jsondecode (1)", "JSON_TXT must be a character string");
+%! fail ("jsondecode ('12-')", "parse error at offset 3");
+
+*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/jsonencode.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,668 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include "builtin-defun-decls.h"
+#include "defun.h"
+#include "error.h"
+#include "errwarn.h"
+#include "oct-string.h"
+#include "ovl.h"
+
+#if defined (HAVE_RAPIDJSON)
+#  include <rapidjson/stringbuffer.h>
+#  include <rapidjson/writer.h>
+#  if defined (HAVE_RAPIDJSON_PRETTYWRITER)
+#    include <rapidjson/prettywriter.h>
+#  endif
+#endif
+
+#if defined (HAVE_RAPIDJSON)
+
+//! Encodes a scalar Octave value into a numerical JSON value.
+//!
+//! @param writer RapidJSON's writer that is responsible for generating JSON.
+//! @param obj scalar Octave value.
+//! @param ConvertInfAndNaN @c bool that converts @c Inf and @c NaN to @c null.
+//!
+//! @b Example:
+//!
+//! @code{.cc}
+//! octave_value obj (7);
+//! encode_numeric (writer, obj, true);
+//! @endcode
+
+template <typename T> void
+encode_numeric (T& writer, const octave_value& obj,
+                const bool& ConvertInfAndNaN)
+{
+  double value = obj.scalar_value ();
+
+  if (obj.is_bool_scalar ())
+    writer.Bool (obj.bool_value ());
+  // Any numeric input from the interpreter will be in double type so in order
+  // to detect ints, we will check if the floor of the input and the input are
+  // equal using fabs (A - B) < epsilon method as it is more accurate.
+  // If value > 999999, MATLAB will encode it in scientific notation (double)
+  else if (fabs (floor (value) - value) < std::numeric_limits<double>::epsilon ()
+           && value <= 999999 && value >= -999999)
+    writer.Int64 (value);
+  // Possibly write NULL for non-finite values (-Inf, Inf, NaN, NA)
+  else if (ConvertInfAndNaN && ! octave::math::isfinite (value))
+    writer.Null ();
+  else if (obj.is_double_type ())
+    writer.Double (value);
+  else
+    error ("jsonencode: unsupported type");
+}
+
+//! Encodes character vectors and arrays into JSON strings.
+//!
+//! @param writer RapidJSON's writer that is responsible for generating JSON.
+//! @param obj character vectors or character arrays.
+//! @param original_dims The original dimensions of the array being encoded.
+//! @param level The level of recursion for the function.
+//!
+//! @b Example:
+//!
+//! @code{.cc}
+//! octave_value obj ("foo");
+//! encode_string (writer, obj, true);
+//! @endcode
+
+template <typename T> void
+encode_string (T& writer, const octave_value& obj,
+               const dim_vector& original_dims, int level = 0)
+{
+  charNDArray array = obj.char_array_value ();
+
+  if (array.isempty ())
+    writer.String ("");
+  else if (array.isvector ())
+    {
+      // Handle the special case where the input is a vector with more than
+      // 2 dimensions (e.g. cat (8, ['a'], ['c'])).  In this case, we don't
+      // split the inner vectors of the input; we merge them into one.
+      if (level == 0)
+        {
+          std::string char_vector = "";
+          for (octave_idx_type i = 0; i < array.numel (); ++i)
+            char_vector += array(i);
+          writer.String (char_vector.c_str ());
+        }
+      else
+        for (octave_idx_type i = 0; i < array.numel () / original_dims(1); ++i)
+          {
+            std::string char_vector = "";
+            for (octave_idx_type k = 0; k < original_dims(1); ++k)
+              char_vector += array(i * original_dims(1) + k);
+            writer.String (char_vector.c_str ());
+          }
+    }
+  else
+    {
+      octave_idx_type idx;
+      octave_idx_type ndims = array.ndims ();
+      dim_vector dims = array.dims ();
+
+      // In this case, we already have a vector. So, we transform it to 2-D
+      // vector in order to be detected by "isvector" in the recursive call
+      if (dims.num_ones () == ndims - 1)
+      {
+        // Handle the special case when the input is a vector with more than
+        // 2 dimensions (e.g. cat (8, ['a'], ['c'])).  In this case, we don't
+        // add dimension brackets and treat it as if it is a vector
+        if (level != 0)
+          // Place an opening and a closing bracket (represents a dimension)
+          // for every dimension that equals 1 until we reach the 2-D vector
+          for (int i = level; i < ndims - 1; ++i)
+            writer.StartArray ();
+
+        encode_string (writer, array.as_row (), original_dims, level);
+
+        if (level != 0)
+          for (int i = level; i < ndims - 1; ++i)
+            writer.EndArray ();
+      }
+      else
+        {
+          // We place an opening and a closing bracket for each dimension
+          // that equals 1 to preserve the number of dimensions when decoding
+          // the array after encoding it.
+          if (original_dims(level) == 1 && level != 1)
+          {
+            writer.StartArray ();
+            encode_string (writer, array, original_dims, level + 1);
+            writer.EndArray ();
+          }
+          else
+            {
+              // The second dimension contains the number of the chars in
+              // the char vector. We want to treat them as a one object,
+              // so we replace it with 1
+              dims(1) = 1;
+
+              for (idx = 0; idx < ndims; ++idx)
+                if (dims(idx) != 1)
+                  break;
+              // Create the dimensions that will be used to call "num2cell"
+              // We called "num2cell" to divide the array to smaller sub-arrays
+              // in order to encode it recursively.
+              // The recursive encoding is necessary to support encoding of
+              // higher-dimensional arrays.
+              RowVector conversion_dims;
+              conversion_dims.resize (ndims - 1);
+              for (octave_idx_type i = 0; i < idx; ++i)
+                conversion_dims(i) = i + 1;
+              for (octave_idx_type i = idx ; i < ndims - 1; ++i)
+                conversion_dims(i) = i + 2;
+
+              octave_value_list args (obj);
+              args.append (conversion_dims);
+
+              Cell sub_arrays = Fnum2cell (args)(0).cell_value ();
+
+              writer.StartArray ();
+
+              for (octave_idx_type i = 0; i < sub_arrays.numel (); ++i)
+                encode_string (writer, sub_arrays(i), original_dims,
+                               level + 1);
+
+              writer.EndArray ();
+            }
+        }
+    }
+}
+
+//! Encodes a struct Octave value into a JSON object or a JSON array depending
+//! on the type of the struct (scalar struct or struct array.)
+//!
+//! @param writer RapidJSON's writer that is responsible for generating JSON.
+//! @param obj struct Octave value.
+//! @param ConvertInfAndNaN @c bool that converts @c Inf and @c NaN to @c null.
+//!
+//! @b Example:
+//!
+//! @code{.cc}
+//! octave_value obj (octave_map ());
+//! encode_struct (writer, obj,true);
+//! @endcode
+
+template <typename T> void
+encode_struct (T& writer, const octave_value& obj, const bool& ConvertInfAndNaN)
+{
+  octave_map struct_array = obj.map_value ();
+  octave_idx_type numel = struct_array.numel ();
+  bool is_array = (numel > 1);
+  string_vector keys = struct_array.keys ();
+
+  if (is_array)
+    writer.StartArray ();
+
+  for (octave_idx_type i = 0; i < numel; ++i)
+    {
+      writer.StartObject ();
+      for (octave_idx_type k = 0; k < keys.numel (); ++k)
+        {
+          writer.Key (keys(k).c_str ());
+          encode (writer, struct_array(i).getfield (keys(k)), ConvertInfAndNaN);
+        }
+      writer.EndObject ();
+    }
+
+  if (is_array)
+    writer.EndArray ();
+}
+
+//! Encodes a Cell Octave value into a JSON array
+//!
+//! @param writer RapidJSON's writer that is responsible for generating JSON.
+//! @param obj Cell Octave value.
+//! @param ConvertInfAndNaN @c bool that converts @c Inf and @c NaN to @c null.
+//!
+//! @b Example:
+//!
+//! @code{.cc}
+//! octave_value obj (cell ());
+//! encode_cell (writer, obj,true);
+//! @endcode
+
+template <typename T> void
+encode_cell (T& writer, const octave_value& obj, const bool& ConvertInfAndNaN)
+{
+  Cell cell = obj.cell_value ();
+
+  writer.StartArray ();
+
+  for (octave_idx_type i = 0; i < cell.numel (); ++i)
+    encode (writer, cell(i), ConvertInfAndNaN);
+
+  writer.EndArray ();
+}
+
+//! Encodes a numeric or logical Octave array into a JSON array
+//!
+//! @param writer RapidJSON's writer that is responsible for generating JSON.
+//! @param obj numeric or logical Octave array.
+//! @param ConvertInfAndNaN @c bool that converts @c Inf and @c NaN to @c null.
+//! @param original_dims The original dimensions of the array being encoded.
+//! @param level The level of recursion for the function.
+//! @param is_logical optional @c bool that indicates if the array is logical.
+//!
+//! @b Example:
+//!
+//! @code{.cc}
+//! octave_value obj (NDArray ());
+//! encode_array (writer, obj,true);
+//! @endcode
+
+template <typename T> void
+encode_array (T& writer, const octave_value& obj, const bool& ConvertInfAndNaN,
+              const dim_vector& original_dims, int level = 0,
+              bool is_logical = false)
+{
+  NDArray array = obj.array_value ();
+  // is_logical is assigned at level 0.  I think this is better than changing
+  // many places in the code, and it makes the function more modular.
+  if (level == 0)
+    is_logical = obj.islogical ();
+
+  if (array.isempty ())
+    {
+      writer.StartArray ();
+      writer.EndArray ();
+    }
+  else if (array.isvector ())
+    {
+      writer.StartArray ();
+      for (octave_idx_type i = 0; i < array.numel (); ++i)
+        {
+          if (is_logical)
+            encode_numeric (writer, bool (array(i)), ConvertInfAndNaN);
+          else
+            encode_numeric (writer, array(i), ConvertInfAndNaN);
+        }
+      writer.EndArray ();
+    }
+  else
+    {
+      octave_idx_type idx;
+      octave_idx_type ndims = array.ndims ();
+      dim_vector dims = array.dims ();
+
+      // In this case, we already have a vector. So,  we transform it to 2-D
+      // vector in order to be detected by "isvector" in the recursive call
+      if (dims.num_ones () == ndims - 1)
+        {
+          // Handle the special case when the input is a vector with more than
+          // 2 dimensions (e.g. ones ([1 1 1 1 1 6])). In this case, we don't
+          // add dimension brackets and treat it as if it is a vector
+          if (level != 0)
+            // Place an opening and a closing bracket (represents a dimension)
+            // for every dimension that equals 1 till we reach the 2-D vector
+            for (int i = level; i < ndims - 1; ++i)
+              writer.StartArray ();
+
+          encode_array (writer, array.as_row (), ConvertInfAndNaN,
+                        original_dims, level + 1, is_logical);
+
+          if (level != 0)
+            for (int i = level; i < ndims - 1; ++i)
+              writer.EndArray ();
+        }
+      else
+        {
+          // We place an opening and a closing bracket for each dimension
+          // that equals 1 to preserve the number of dimensions when decoding
+          // the array after encoding it.
+          if (original_dims (level) == 1)
+          {
+            writer.StartArray ();
+            encode_array (writer, array, ConvertInfAndNaN,
+                          original_dims, level + 1, is_logical);
+            writer.EndArray ();
+          }
+          else
+            {
+              for (idx = 0; idx < ndims; ++idx)
+                if (dims(idx) != 1)
+                  break;
+
+              // Create the dimensions that will be used to call "num2cell"
+              // We called "num2cell" to divide the array to smaller sub-arrays
+              // in order to encode it recursively.
+              // The recursive encoding is necessary to support encoding of
+              // higher-dimensional arrays.
+              RowVector conversion_dims;
+              conversion_dims.resize (ndims - 1);
+              for (octave_idx_type i = 0; i < idx; ++i)
+                conversion_dims(i) = i + 1;
+              for (octave_idx_type i = idx ; i < ndims - 1; ++i)
+                conversion_dims(i) = i + 2;
+
+              octave_value_list args (obj);
+              args.append (conversion_dims);
+
+              Cell sub_arrays = Fnum2cell (args)(0).cell_value ();
+
+              writer.StartArray ();
+
+              for (octave_idx_type i = 0; i < sub_arrays.numel (); ++i)
+                encode_array (writer, sub_arrays(i), ConvertInfAndNaN,
+                              original_dims, level + 1, is_logical);
+
+              writer.EndArray ();
+            }
+        }
+    }
+}
+
+//! Encodes any Octave object. This function only serves as an interface
+//! by choosing which function to call from the previous functions.
+//!
+//! @param writer RapidJSON's writer that is responsible for generating JSON.
+//! @param obj any @ref octave_value that is supported.
+//! @param ConvertInfAndNaN @c bool that converts @c Inf and @c NaN to @c null.
+//!
+//! @b Example:
+//!
+//! @code{.cc}
+//! octave_value obj (true);
+//! encode (writer, obj,true);
+//! @endcode
+
+template <typename T> void
+encode (T& writer, const octave_value& obj, const bool& ConvertInfAndNaN)
+{
+  if (obj.is_real_scalar ())
+    encode_numeric (writer, obj, ConvertInfAndNaN);
+  // As I checked for scalars, this will detect numeric & logical arrays
+  else if (obj.isnumeric () || obj.islogical ())
+    encode_array (writer, obj, ConvertInfAndNaN, obj.dims ());
+  else if (obj.is_string ())
+    encode_string (writer, obj, obj.dims ());
+  else if (obj.isstruct ())
+    encode_struct (writer, obj, ConvertInfAndNaN);
+  else if (obj.iscell ())
+    encode_cell (writer, obj, ConvertInfAndNaN);
+  else if (obj.class_name () == "containers.Map")
+    // To extract the data in containers.Map, convert it to a struct.
+    // The struct will have a "map" field whose value is a struct that
+    // contains the desired data.
+    // To avoid warnings due to that conversion, disable the
+    // "Octave:classdef-to-struct" warning and re-enable it.
+    {
+      octave::unwind_action restore_warning_state
+        ([] (const octave_value_list& old_warning_state)
+         {
+           set_warning_state (old_warning_state);
+         }, set_warning_state ("Octave:classdef-to-struct", "off"));
+
+      encode_struct (writer, obj.scalar_map_value ().getfield ("map"),
+                     ConvertInfAndNaN);
+    }
+  else if (obj.isobject ())
+    {
+      octave::unwind_action restore_warning_state
+        ([] (const octave_value_list& old_warning_state)
+         {
+           set_warning_state (old_warning_state);
+         }, set_warning_state ("Octave:classdef-to-struct", "off"));
+
+      encode_struct (writer, obj.scalar_map_value (), ConvertInfAndNaN);
+    }
+  else
+    error ("jsonencode: unsupported type");
+}
+
+#endif
+
+DEFUN (jsonencode, args, ,
+       doc: /* -*- texinfo -*-
+@deftypefn  {} {@var{JSON_txt} =} jsonencode (@var{object})
+@deftypefnx {} {@var{JSON_txt} =} jsonencode (@dots{}, "ConvertInfAndNaN", @var{TF})
+@deftypefnx {} {@var{JSON_txt} =} jsonencode (@dots{}, "PrettyWriter", @var{TF})
+
+Encode Octave data types into JSON text.
+
+The input @var{object} is an Octave variable to encode.
+
+The output @var{JSON_txt} is the JSON text that contains the result of encoding
+@var{object}.
+
+If the value of the option @qcode{"ConvertInfAndNaN"} is true then @code{NaN},
+@code{NA}, @code{-Inf}, and @code{Inf} values will be converted to
+@qcode{"null"} in the output.  If it is false then they will remain as their
+original values.  The default value for this option is true.
+
+If the value of the option @qcode{"PrettyWriter"} is true, the output text will
+have indentations and line feeds.  If it is false, the output will be condensed
+and written without whitespace.  The default value for this option is false.
+
+Programming Notes:
+
+@itemize @bullet
+@item
+Complex numbers are not supported.
+
+@item
+classdef objects are first converted to structs and then encoded.
+
+@item
+To preserve escape characters (e.g., @qcode{"\n"}), use single-quoted strings.
+
+@item
+Every character after the null character (@qcode{"\0"}) in a double-quoted
+string will be dropped during encoding.
+
+@item
+Encoding and decoding an array is not guaranteed to preserve the dimensions
+of the array.  In particular, row vectors will be reshaped to column vectors.
+
+@item
+Encoding and decoding is not guaranteed to preserve the Octave data type
+because JSON supports fewer data types than Octave.  For example, if you
+encode an @code{int8} and then decode it, you will get a @code{double}.
+@end itemize
+
+This table shows the conversions from Octave data types to JSON data types:
+
+@multitable @columnfractions 0.50 0.50
+@headitem Octave data type @tab JSON data type
+@item logical scalar @tab Boolean
+@item logical vector @tab Array of Boolean, reshaped to row vector
+@item logical array  @tab nested Array of Boolean
+@item numeric scalar @tab Number
+@item numeric vector @tab Array of Number, reshaped to row vector
+@item numeric array  @tab nested Array of Number
+@item @code{NaN}, @code{NA}, @code{Inf}, @code{-Inf}@*
+when @qcode{"ConvertInfAndNaN" = true} @tab @qcode{"null"}
+@item @code{NaN}, @code{NA}, @code{Inf}, @code{-Inf}@*
+when @qcode{"ConvertInfAndNaN" = false} @tab @qcode{"NaN"}, @qcode{"NaN"},
+@qcode{"Infinity"}, @qcode{"-Infinity"}
+@item empty array    @tab @qcode{"[]"}
+@item character vector @tab String
+@item character array @tab Array of String
+@item empty character array @tab @qcode{""}
+@item cell scalar @tab Array
+@item cell vector @tab Array, reshaped to row vector
+@item cell array @tab Array, flattened to row vector
+@item struct scalar @tab Object
+@item struct vector @tab Array of Object, reshaped to row vector
+@item struct array  @tab nested Array of Object
+@item classdef object @tab Object
+@end multitable
+
+Examples:
+
+@example
+@group
+jsonencode ([1, NaN; 3, 4])
+@result{} [[1,null],[3,4]]
+@end group
+
+@group
+jsonencode ([1, NaN; 3, 4], "ConvertInfAndNaN", false)
+@result{} [[1,NaN],[3,4]]
+@end group
+
+@group
+## Escape characters inside a single-quoted string
+jsonencode ('\0\a\b\t\n\v\f\r')
+@result{} "\\0\\a\\b\\t\\n\\v\\f\\r"
+@end group
+
+@group
+## Escape characters inside a double-quoted string
+jsonencode ("\a\b\t\n\v\f\r")
+@result{} "\u0007\b\t\n\u000B\f\r"
+@end group
+
+@group
+jsonencode ([true; false], "PrettyWriter", true)
+@result{} ans = [
+       true,
+       false
+   ]
+@end group
+
+@group
+jsonencode (['foo', 'bar'; 'foo', 'bar'])
+@result{} ["foobar","foobar"]
+@end group
+
+@group
+jsonencode (struct ('a', Inf, 'b', [], 'c', struct ()))
+@result{} @{"a":null,"b":[],"c":@{@}@}
+@end group
+
+@group
+jsonencode (struct ('structarray', struct ('a', @{1; 3@}, 'b', @{2; 4@})))
+@result{} @{"structarray":[@{"a":1,"b":2@},@{"a":3,"b":4@}]@}
+@end group
+
+@group
+jsonencode (@{'foo'; 'bar'; @{'foo'; 'bar'@}@})
+@result{} ["foo","bar",["foo","bar"]]
+@end group
+
+@group
+jsonencode (containers.Map(@{'foo'; 'bar'; 'baz'@}, [1, 2, 3]))
+@result{} @{"bar":2,"baz":3,"foo":1@}
+@end group
+@end example
+
+@seealso{jsondecode}
+@end deftypefn */)
+{
+#if defined (HAVE_RAPIDJSON)
+
+  int nargin = args.length ();
+  // jsonencode has two options 'ConvertInfAndNaN' and 'PrettyWriter'
+  if (nargin != 1 && nargin != 3 && nargin != 5)
+    print_usage ();
+
+  // Initialize options with their default values
+  bool ConvertInfAndNaN = true;
+  bool PrettyWriter = false;
+
+  for (octave_idx_type i = 1; i < nargin; ++i)
+    {
+      if (! args(i).is_string ())
+        error ("jsonencode: option must be a string");
+      if (! args(i+1).is_bool_scalar ())
+        error ("jsonencode: option value must be a logical scalar");
+
+      std::string option_name = args(i++).string_value ();
+      if (octave::string::strcmpi (option_name, "ConvertInfAndNaN"))
+        ConvertInfAndNaN = args(i).bool_value ();
+      else if (octave::string::strcmpi (option_name, "PrettyWriter"))
+        PrettyWriter = args(i).bool_value ();
+      else
+        error ("jsonencode: "
+               R"(Valid options are "ConvertInfAndNaN" and "PrettyWriter")");
+    }
+
+# if ! defined (HAVE_RAPIDJSON_PRETTYWRITER)
+  if (PrettyWriter)
+    {
+      warn_disabled_feature ("jsonencode",
+                             R"(the "PrettyWriter" option of RapidJSON)");
+      PrettyWriter = false;
+    }
+# endif
+
+  rapidjson::StringBuffer json;
+  if (PrettyWriter)
+    {
+# if defined (HAVE_RAPIDJSON_PRETTYWRITER)
+      rapidjson::PrettyWriter<rapidjson::StringBuffer, rapidjson::UTF8<>,
+                              rapidjson::UTF8<>, rapidjson::CrtAllocator,
+                              rapidjson::kWriteNanAndInfFlag> writer (json);
+      encode (writer, args(0), ConvertInfAndNaN);
+# endif
+    }
+  else
+    {
+      rapidjson::Writer<rapidjson::StringBuffer, rapidjson::UTF8<>,
+                        rapidjson::UTF8<>, rapidjson::CrtAllocator,
+                        rapidjson::kWriteNanAndInfFlag> writer (json);
+      encode (writer, args(0), ConvertInfAndNaN);
+    }
+
+  return octave_value (json.GetString ());
+
+#else
+
+  octave_unused_parameter (args);
+
+  err_disabled_feature ("jsonencode", "JSON encoding through RapidJSON");
+
+#endif
+}
+
+/*
+Functional BIST tests are located in test/json/jsonencode_BIST.tst
+
+## Input validation tests
+%!testif HAVE_RAPIDJSON
+%! fail ("jsonencode ()");
+%! fail ("jsonencode (1, 2)");
+%! fail ("jsonencode (1, 2, 3, 4)");
+%! fail ("jsonencode (1, 2, 3, 4, 5, 6)");
+%! fail ("jsonencode (1, 2, true)", "option must be a string");
+%! fail ("jsonencode (1, 'string', ones (2,2))", ...
+%!       "option value must be a logical scalar");
+%! fail ("jsonencode (1, 'foobar', true)", ...
+%!       'Valid options are "ConvertInfAndNaN"');
+
+%!testif HAVE_RAPIDJSON; ! __have_feature__ ("RAPIDJSON_PRETTYWRITER")
+%! fail ("jsonencode (1, 'PrettyWriter', true)", ...
+%!       "warning", 'the "PrettyWriter" option of RapidJSON was unavailable');
+
+*/
--- a/libinterp/corefcn/kron.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/kron.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -310,7 +310,7 @@
 %!assert (kron (single (1:4), ones (3, 1)), single (z))
 %!assert (kron (sparse (1:4), ones (3, 1)), sparse (z))
 %!assert (kron (complex (1:4), ones (3, 1)), z)
-%!assert (kron (complex (single(1:4)), ones (3, 1)), single(z))
+%!assert (kron (complex (single (1:4)), ones (3, 1)), single (z))
 %!assert (kron (x, y, z), kron (kron (x, y), z))
 %!assert (kron (x, y, z), kron (x, kron (y, z)))
 %!assert (kron (p1, p1), kron (p2, p2))
--- a/libinterp/corefcn/load-path.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/load-path.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -28,6 +28,7 @@
 #endif
 
 #include <algorithm>
+#include <cctype>
 
 #include "dir-ops.h"
 #include "file-ops.h"
@@ -56,9 +57,9 @@
   static std::string
   maybe_canonicalize (const std::string& dir_arg)
   {
-    bool is_absolute_path = octave::sys::env::absolute_pathname (dir_arg);
-
-    std::string canonical_dir = octave::sys::canonicalize_file_name (dir_arg);
+    bool is_absolute_path = sys::env::absolute_pathname (dir_arg);
+
+    std::string canonical_dir = sys::canonicalize_file_name (dir_arg);
     std::string dir;
     if (canonical_dir.empty ())
       dir = dir_arg;
@@ -70,7 +71,7 @@
           {
             // Remove current path from absolute path generated by
             // canonicalize_file_name.
-            std::string cwd = octave::sys::canonicalize_file_name (".");
+            std::string cwd = sys::canonicalize_file_name (".");
             if (dir.compare (0, cwd.length (), cwd) == 0)
               dir.erase (0, cwd.length ()+1);
             if (dir.empty ())
@@ -230,8 +231,8 @@
   load_path::load_path (interpreter& interp)
     : m_interpreter (interp), package_map (), top_level_package (),
       dir_info_list (), init_dirs (), m_command_line_path (),
-      add_hook ([this] (const std::string& dir) { this->execute_pkg_add (dir); }),
-      remove_hook ([this] (const std::string& dir) { this->execute_pkg_del (dir); })
+      add_hook ([=] (const std::string& dir) { this->execute_pkg_add (dir); }),
+      remove_hook ([=] (const std::string& dir) { this->execute_pkg_del (dir); })
   { }
 
   void
@@ -963,8 +964,6 @@
     if (! octave_interpreter_ready)
       return;
 
-    unwind_protect frame;
-
     std::string file = sys::file_ops::concat (dir, script_file);
 
     sys::file_stat fs (file);
@@ -1086,6 +1085,8 @@
           {
             if (fs.is_dir ())
               {
+                read_dir_config (dir);
+
                 dir_info di (dir);
 
                 if (at_end)
@@ -1136,6 +1137,78 @@
       }
   }
 
+  void
+  load_path::read_dir_config (const std::string& dir) const
+  {
+    // read file with directory configuration
+    std::string conf_file = dir + sys::file_ops::dir_sep_str ()
+                            + ".oct-config";
+
+    FILE* cfile = sys::fopen (conf_file, "rb");
+
+    if (! cfile)
+      {
+        // reset directory encoding
+        input_system& input_sys
+          = __get_input_system__ ("load_path::read_dir_config");
+
+        std::string enc_val = "delete";
+        input_sys.set_dir_encoding (dir, enc_val);
+        return;
+      }
+
+    unwind_action close_file ([cfile] (void) { fclose (cfile); });
+
+    // find line with character encoding and read it
+    bool eof = false;
+    const std::string enc_prop = "encoding";
+    while (! eof)
+      {
+        std::string conf_str = octave_fgets (cfile, eof);
+
+        // delete any preceeding whitespace
+        auto it = std::find_if_not (conf_str.begin (), conf_str.end (),
+                                    [] (unsigned char c)
+                                    { return std::isblank (c); });
+        conf_str.erase (conf_str.begin (), it);
+
+        // match identifier
+        if (conf_str.compare (0, enc_prop.size (), enc_prop) == 0)
+          {
+            // skip delimiter characters
+            size_t pos = conf_str.find_first_not_of (" \t=:",
+                                                     enc_prop.size ());
+            if (pos == std::string::npos)
+              continue;
+
+            std::string enc_val = conf_str.substr (pos);
+
+            // take alphanumeric and '-' characters
+            it = std::find_if_not (enc_val.begin (), enc_val.end (),
+                                   [] (unsigned char c)
+                                   { return std::isalnum (c) || c == '-'; });
+            enc_val.erase(it, enc_val.end ());
+
+            if (enc_val.empty ())
+              continue;
+
+            // set encoding for this directory in input system
+            input_system& input_sys
+              = __get_input_system__ ("load_path::read_dir_config");
+            input_sys.set_dir_encoding (dir, enc_val);
+            return;
+          }
+      }
+
+    // reset directory encoding
+    input_system& input_sys
+      = __get_input_system__ ("load_path::read_dir_config");
+
+    std::string enc_val = "delete";
+    input_sys.set_dir_encoding (dir, enc_val);
+
+  }
+
   bool
   load_path::is_package (const std::string& name) const
   {
--- a/libinterp/corefcn/load-path.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/load-path.h	Thu Nov 19 13:08:00 2020 -0800
@@ -191,6 +191,8 @@
       remove_hook = f;
     }
 
+    void read_dir_config (const std::string& dir) const;
+
     void execute_pkg_add (const std::string& dir);
     void execute_pkg_del (const std::string& dir);
 
--- a/libinterp/corefcn/load-save.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/load-save.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -645,6 +645,10 @@
           warning (R"(save: "-tabs" option only has an effect with "-ascii")");
       }
 
+    if (append && use_zlib
+        && (fmt.type () != TEXT && fmt.type () != MAT_ASCII))
+      error ("save: -append and -zip options can only be used together with a text format (-text or -ascii)");
+
     return retval;
   }
 
@@ -1812,6 +1816,53 @@
   return load_save_sys.save (args, nargout);
 }
 
+/*
+## Save and load strings with "-v6"
+%!test
+%! A = A2 = ["foo"; "bar"];
+%! B = B2 = "foobar";
+%! C = C2 = {"foo", "bar"};
+%! D = D2 = {"Saint Barthélemy", "Saint Kitts and Nevis"};
+%! mat_file = [tempname(), ".mat"];
+%! unwind_protect
+%!   save (mat_file, "A", "B", "C", "D", "-v6");
+%!   clear ("A", "B", "C", "D");
+%!   load (mat_file);
+%! unwind_protect_cleanup
+%!   unlink (mat_file);
+%! end_unwind_protect
+%! assert (A, A2);
+%! assert (B, B2);
+%! assert (C, C2);
+%! assert (D, D2);
+
+## Save and load strings with "-v7"
+%!testif HAVE_ZLIB
+%! A = A2 = ["foo"; "bar"];
+%! B = B2 = "foobar";
+%! C = C2 = {"foo", "bar"};
+%! D = D2 = {"Saint Barthélemy", "Saint Kitts and Nevis"};
+%! mat_file = [tempname(), ".mat"];
+%! unwind_protect
+%!   save (mat_file, "A", "B", "C", "D", "-v7");
+%!   clear ("A", "B", "C", "D");
+%!   load (mat_file);
+%! unwind_protect_cleanup
+%!   unlink (mat_file);
+%! end_unwind_protect
+%! assert (A, A2);
+%! assert (B, B2);
+%! assert (C, C2);
+%! assert (D, D2);
+
+## Test input validation
+%!testif HAVE_ZLIB <*59225>
+%! fname = tempname ();
+%! x = 1;
+%! fail ('save ("-append", "-zip", "-binary", fname, "x")',
+%!       "-append and -zip options .* with a text format");
+*/
+
 DEFMETHOD (crash_dumps_octave_core, interp, args, nargout,
            doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{val} =} crash_dumps_octave_core ()
--- a/libinterp/corefcn/ls-mat-ascii.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/ls-mat-ascii.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -154,7 +154,7 @@
                 {
                   std::istringstream tmp_stream (buf.substr (beg, end-beg));
 
-                  octave_read_double (tmp_stream);
+                  octave::read_value<double> (tmp_stream);
 
                   if (tmp_stream.fail ())
                     {
@@ -285,7 +285,7 @@
         {
           octave_quit ();
 
-          d = octave_read_value<double> (tmp_stream);
+          d = octave::read_value<double> (tmp_stream);
 
           if (! tmp_stream && ! tmp_stream.eof ())
             error ("load: failed to read matrix from file '%s'",
@@ -381,7 +381,7 @@
                 {
                   // Omit leading tabs.
                   if (j != 0) os << '\t';
-                  octave_write_double (os, m(i, j));
+                  octave::write_value<double> (os, m(i, j));
                 }
               os << "\n";
             }
--- a/libinterp/corefcn/ls-mat4.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/ls-mat4.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -465,9 +465,9 @@
     }
   else if (tc.is_range ())
     {
-      Range r = tc.range_value ();
+      octave::range<double> r = tc.range_value ();
       double base = r.base ();
-      double inc = r.inc ();
+      double inc = r.increment ();
       octave_idx_type nel = r.numel ();
       for (octave_idx_type i = 0; i < nel; i++)
         {
--- a/libinterp/corefcn/ls-mat5.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/ls-mat5.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -50,6 +50,7 @@
 #include "oct-time.h"
 #include "quit.h"
 #include "str-vec.h"
+#include "unistr-wrappers.h"
 
 #include "Cell.h"
 #include "defaults.h"
@@ -1417,58 +1418,84 @@
 
             tc = ctmp;
           }
-        else
+        else if (arrayclass == MAT_FILE_CHAR_CLASS)
           {
-            if (arrayclass == MAT_FILE_CHAR_CLASS)
+            bool converted = false;
+            if (re.isvector () && (type == miUTF16 || type == miUINT16))
               {
-                if (type == miUTF16 || type == miUTF32)
-                  {
-                    bool found_big_char = false;
-                    for (octave_idx_type i = 0; i < n; i++)
-                      {
-                        if (re(i) > 127)
-                          {
-                            re(i) = '?';
-                            found_big_char = true;
-                          }
-                      }
-
-                    if (found_big_char)
-                      warning_with_id ("Octave:load:unsupported-utf-char",
-                               "load: can not read non-ASCII portions of UTF characters; replacing unreadable characters with '?'");
-                  }
-                else if (type == miUTF8)
+                uint16NDArray u16 = re;
+                const uint16_t *u16_str
+                  = reinterpret_cast<const uint16_t *> (u16.data ());
+
+                // Convert to UTF-8.
+                size_t n8;
+                uint8_t *u8_str = octave_u16_to_u8_wrapper (u16_str,
+                                                            u16.numel (),
+                                                            nullptr, &n8);
+                if (u8_str)
                   {
-                    // Search for multi-byte encoded UTF8 characters and
-                    // replace with 0x3F for '?'...  Give the user a warning
-
-                    bool utf8_multi_byte = false;
-                    for (octave_idx_type i = 0; i < n; i++)
+                    // FIXME: Is there a better way to construct a charMatrix
+                    // from a non zero terminated buffer?
+                    tc = charMatrix (std::string (reinterpret_cast<char *> (u8_str), n8));
+                    free (u8_str);
+                    converted = true;
+                  }
+              }
+            else if (re.isvector () && (type == miUTF32 || type == miUINT32))
+              {
+                uint32NDArray u32 = re;
+                const uint32_t *u32_str
+                  = reinterpret_cast<const uint32_t *> (u32.data ());
+
+                // Convert to UTF-8.
+                size_t n8;
+                uint8_t *u8_str = octave_u32_to_u8_wrapper (u32_str,
+                                                            u32.numel (),
+                                                            nullptr, &n8);
+                if (u8_str)
+                  {
+                    // FIXME: Is there a better way to construct a charMatrix
+                    // from a non zero terminated buffer?
+                    tc = charMatrix (std::string (reinterpret_cast<char *> (u8_str), n8));
+                    free (u8_str);
+                    converted = true;
+                  }
+              }
+            else if (type == miUTF8 || type == miUINT8)
+              {
+                // Octave's internal encoding is UTF-8.  So we should be
+                // able to use this natively.
+                tc = re;
+                tc = tc.convert_to_str (false, true, '\'');
+                converted = true;
+              }
+
+            if (! converted)
+              {
+                // Fall back to manually replacing non-ASCII
+                // characters by "?".
+                bool found_big_char = false;
+                for (octave_idx_type i = 0; i < n; i++)
+                  {
+                    if (re(i) > 127)
                       {
-                        unsigned char a = static_cast<unsigned char> (re(i));
-                        if (a > 0x7f)
-                          utf8_multi_byte = true;
-                      }
-
-                    if (utf8_multi_byte)
-                      {
-                        warning_with_id ("Octave:load:unsupported-utf-char",
-                                         "load: can not read multi-byte encoded UTF8 characters; replacing unreadable characters with '?'");
-                        for (octave_idx_type i = 0; i < n; i++)
-                          {
-                            unsigned char a
-                              = static_cast<unsigned char> (re(i));
-                            if (a > 0x7f)
-                              re(i) = '?';
-                          }
+                        re(i) = '?';
+                        found_big_char = true;
                       }
                   }
+
+                if (found_big_char)
+                  warning_with_id ("Octave:load:unsupported-utf-char",
+                    "load: failed to convert from input to UTF-8; "
+                    "replacing non-ASCII characters with '?'");
+
                 tc = re;
                 tc = tc.convert_to_str (false, true, '\'');
               }
-            else
-              tc = re;
+
           }
+        else
+          tc = re;
       }
     }
 
@@ -2070,6 +2097,24 @@
   return ret;
 }
 
+static uint16_t *
+maybe_convert_to_u16 (const charNDArray& chm, size_t& n16_str)
+{
+  uint16_t *u16_str;
+  dim_vector dv = chm.dims ();
+
+  if (chm.ndims () == 2 && dv(0) == 1)
+    {
+      const uint8_t *u8_str = reinterpret_cast<const uint8_t *> (chm.data ());
+      u16_str = octave_u8_to_u16_wrapper (u8_str, chm.numel (),
+                                          nullptr, &n16_str);
+    }
+  else
+    u16_str = nullptr;
+
+  return u16_str;
+}
+
 int
 save_mat5_element_length (const octave_value& tc, const std::string& name,
                           bool save_as_floats, bool mat7_format)
@@ -2087,9 +2132,23 @@
   if (tc.is_string ())
     {
       charNDArray chm = tc.char_array_value ();
+      // convert to UTF-16
+      size_t n16_str;
+      uint16_t *u16_str = maybe_convert_to_u16 (chm, n16_str);
       ret += 8;
-      if (chm.numel () > 2)
-        ret += PAD (2 * chm.numel ());
+
+      octave_idx_type str_len;
+      if (u16_str)
+        {
+          // Count number of elements in converted string
+          str_len = 2 * n16_str;
+          free (u16_str);
+        }
+      else
+        str_len = chm.numel ();
+
+      if (str_len > 2)
+        ret += PAD (str_len);
     }
   else if (tc.issparse ())
     {
@@ -2414,15 +2473,36 @@
 
   write_mat5_tag (os, miINT32, dim_len);
 
-  for (int i = 0; i < nd; i++)
+  // Strings need to be converted here (or dim-vector will be off).
+  charNDArray chm;
+  uint16_t *u16_str;
+  size_t n16_str;
+  bool conv_u16 = false;
+  if (tc.is_string ())
     {
-      int32_t n = dv(i);
+      chm = tc.char_array_value ();
+      u16_str = maybe_convert_to_u16 (chm, n16_str);
+
+      if (u16_str)
+        conv_u16 = true;
+    }
+
+  if (conv_u16)
+    {
+      int32_t n = 1;
       os.write (reinterpret_cast<char *> (&n), 4);
+      os.write (reinterpret_cast<char *> (&n16_str), 4);
     }
+  else
+    for (int i = 0; i < nd; i++)
+      {
+        int32_t n = dv(i);
+        os.write (reinterpret_cast<char *> (&n), 4);
+      }
 
   if (PAD (dim_len) > dim_len)
     {
-      static char buf[9]="\x00\x00\x00\x00\x00\x00\x00\x00";
+      static char buf[9] = "\x00\x00\x00\x00\x00\x00\x00\x00";
       os.write (buf, PAD (dim_len) - dim_len);
     }
 
@@ -2445,24 +2525,35 @@
   // data element
   if (tc.is_string ())
     {
-      charNDArray chm = tc.char_array_value ();
-      octave_idx_type nel = chm.numel ();
-      octave_idx_type len = nel*2;
-      octave_idx_type paddedlength = PAD (len);
-
-      OCTAVE_LOCAL_BUFFER (int16_t, buf, nel+3);
-      write_mat5_tag (os, miUINT16, len);
-
-      const char *s = chm.data ();
-
-      for (octave_idx_type i = 0; i < nel; i++)
-        buf[i] = *s++ & 0x00FF;
-
-      os.write (reinterpret_cast<char *> (buf), len);
+      octave_idx_type len;
+      octave_idx_type paddedlength;
+
+      if (conv_u16)
+        {
+          // converted UTF-16
+          len = n16_str*2;
+          paddedlength = PAD (len);
+
+          write_mat5_tag (os, miUTF16, len);
+
+          os.write (reinterpret_cast<char *> (u16_str), len);
+
+          free (u16_str);
+        }
+      else
+        {
+          // write as UTF-8
+          len = chm.numel ();
+          paddedlength = PAD (len);
+
+          write_mat5_tag (os, miUTF8, len);
+
+          os.write (chm.data (), len);
+        }
 
       if (paddedlength > len)
         {
-          static char padbuf[9]="\x00\x00\x00\x00\x00\x00\x00\x00";
+          static char padbuf[9] = "\x00\x00\x00\x00\x00\x00\x00\x00";
           os.write (padbuf, paddedlength - len);
         }
     }
--- a/libinterp/corefcn/lsode.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/lsode.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -269,9 +269,7 @@
   warned_fcn_imaginary = false;
   warned_jac_imaginary = false;
 
-  octave::unwind_protect frame;
-
-  frame.protect_var (call_depth);
+  octave::unwind_protect_var<int> restore_var (call_depth);
   call_depth++;
 
   if (call_depth > 1)
--- a/libinterp/corefcn/lu.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/lu.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -801,15 +801,15 @@
 %! [L,U,P] = lu (A);
 %! [~,ordcols] = max (P,[],1);
 %! [~,ordrows] = max (P,[],2);
-%! P1 = eye (size(P))(:,ordcols);
-%! P2 = eye (size(P))(ordrows,:);
-%! assert(P1 == P);
-%! assert(P2 == P);
+%! P1 = eye (size (P))(:,ordcols);
+%! P2 = eye (size (P))(ordrows,:);
+%! assert (P1 == P);
+%! assert (P2 == P);
 %! [L,U,P] = luupdate (L,U,P,u,v);
 %! [L,U,P1] = luupdate (L,U,P1,u,v);
 %! [L,U,P2] = luupdate (L,U,P2,u,v);
-%! assert(P1 == P);
-%! assert(P2 == P);
+%! assert (P1 == P);
+%! assert (P2 == P);
 %!
 %!testif HAVE_QRUPDATE_LUU
 %! [L,U,P] = lu (Ac);
--- a/libinterp/corefcn/mappers.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/mappers.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -223,7 +223,7 @@
 DEFUN (angle, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn {} {} angle (@var{z})
-See @code{arg}.
+@xref{XREFarg,,@code{arg}}.
 @seealso{arg}
 @end deftypefn */)
 {
@@ -841,7 +841,7 @@
 
 %!test
 %! x = [1+2i,-1+2i,1e-6+2e-6i,0+2i];
-%! assert (erfcx (x), exp (x.^2) .* erfc(x), -1.e-10);
+%! assert (erfcx (x), exp (x.^2) .* erfc (x), -1.e-10);
 
 %!test
 %! x = [100, 100+20i];
@@ -883,7 +883,7 @@
 
 %!test
 %! x = [-0.1, 0.1, 1, 1+2i,-1+2i,1e-6+2e-6i,0+2i];
-%! assert (erfi (x), -i * erf(i*x), -1.e-10);
+%! assert (erfi (x), -i * erf (i*x), -1.e-10);
 
 %!error erfi ()
 %!error erfi (1, 2)
@@ -1216,7 +1216,7 @@
 %! result(double ("0":"9") + 1) = true;
 %! result(double ("a":"z") + 1) = true;
 %! assert (isalnum (charset), result);
-%!assert (isalnum(["Ä8Aa?"; "(Uß ;"]), logical ([1 1 1 1 1 0; 0 1 1 1 0 0]));
+%!assert (isalnum(["Ä8Aa?"; "(Uß ;"]), logical ([1 1 1 1 1 0; 0 1 1 1 0 0]))
 
 %!error isalnum ()
 %!error isalnum (1, 2)
@@ -1245,7 +1245,7 @@
 %! result(double ("A":"Z") + 1) = true;
 %! result(double ("a":"z") + 1) = true;
 %! assert (isalpha (charset), result);
-%!assert (isalpha("Ä8Aa(Uß ;"), logical ([1 1 0 1 1 0 1 1 1 0 0]));
+%!assert (isalpha("Ä8Aa(Uß ;"), logical ([1 1 0 1 1 0 1 1 1 0 0]))
 
 %!error isalpha ()
 %!error isalpha (1, 2)
@@ -1321,7 +1321,7 @@
 %! result = false (1, 128);
 %! result(double ("0":"9") + 1) = true;
 %! assert (isdigit (charset), result);
-%!assert (isdigit("Ä8Aa(Uß ;"), logical ([0 0 1 0 0 0 0 0 0 0 0]));
+%!assert (isdigit("Ä8Aa(Uß ;"), logical ([0 0 1 0 0 0 0 0 0 0 0]))
 
 %!error isdigit ()
 %!error isdigit (1, 2)
@@ -1388,7 +1388,7 @@
 %! result = false (1, 128);
 %! result(34:127) = true;
 %! assert (isgraph (charset), result);
-%!assert (isgraph("Ä8Aa(Uß ;"), logical ([1 1 1 1 1 1 1 1 1 0 1]));
+%!assert (isgraph("Ä8Aa(Uß ;"), logical ([1 1 1 1 1 1 1 1 1 0 1]))
 
 %!error isgraph ()
 %!error isgraph (1, 2)
@@ -1414,7 +1414,7 @@
 %! result = false (1, 128);
 %! result(double ("a":"z") + 1) = true;
 %! assert (islower (charset), result);
-%!assert (islower("Ä8Aa(Uß ;"), logical ([0 0 0 0 1 0 0 1 1 0 0]));
+%!assert (islower("Ä8Aa(Uß ;"), logical ([0 0 0 0 1 0 0 1 1 0 0]))
 
 %!error islower ()
 %!error islower (1, 2)
@@ -1521,7 +1521,7 @@
 %! result = false (1, 128);
 %! result(33:127) = true;
 %! assert (isprint (charset), result);
-%!assert (isprint("Ä8Aa(Uß ;"), logical ([1 1 1 1 1 1 1 1 1 1 1]));
+%!assert (isprint("Ä8Aa(Uß ;"), logical ([1 1 1 1 1 1 1 1 1 1 1]))
 
 %!error isprint ()
 %!error isprint (1, 2)
@@ -1550,7 +1550,7 @@
 %! result(92:97) = true;
 %! result(124:127) = true;
 %! assert (ispunct (charset), result);
-%!assert (ispunct("Ä8Aa(Uß ;"), logical ([0 0 0 0 0 1 0 0 0 0 1]));
+%!assert (ispunct("Ä8Aa(Uß ;"), logical ([0 0 0 0 0 1 0 0 0 0 1]))
 
 %!error ispunct ()
 %!error ispunct (1, 2)
@@ -1577,7 +1577,7 @@
 %! result = false (1, 128);
 %! result(double (" \f\n\r\t\v") + 1) = true;
 %! assert (isspace (charset), result);
-%!assert (isspace("Ä8Aa(Uß ;"), logical ([0 0 0 0 0 0 0 0 0 1 0]));
+%!assert (isspace("Ä8Aa(Uß ;"), logical ([0 0 0 0 0 0 0 0 0 1 0]))
 
 %!error isspace ()
 %!error isspace (1, 2)
@@ -1603,7 +1603,7 @@
 %! result = false (1, 128);
 %! result(double ("A":"Z") + 1) = true;
 %! assert (isupper (charset), result);
-%!assert (isupper("Ä8Aa(Uß ;"), logical ([1 1 0 1 0 0 1 0 0 0 0]));
+%!assert (isupper("Ä8Aa(Uß ;"), logical ([1 1 0 1 0 0 1 0 0 0 0]))
 
 %!error isupper ()
 %!error isupper (1, 2)
@@ -1631,7 +1631,7 @@
 %! result(double ("0":"9") + 1) = true;
 %! result(double ("a":"f") + 1) = true;
 %! assert (isxdigit (charset), result);
-%!assert (isxdigit("Ä8Aa(Uß ;"), logical ([0 0 1 1 1 0 0 0 0 0 0]));
+%!assert (isxdigit("Ä8Aa(Uß ;"), logical ([0 0 1 1 1 0 0 0 0 0 0]))
 
 %!error isxdigit ()
 %!error isxdigit (1, 2)
--- a/libinterp/corefcn/matrix_type.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/matrix_type.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -540,10 +540,10 @@
 %! a = matrix_type (spdiags (randn (10,3),[-1,0,1],10,10), "Singular");
 %! assert (matrix_type (a), "Singular");
 
-%!assert (matrix_type (triu (ones(10,10))), "Upper")
-%!assert (matrix_type (triu (ones(10,10),-1)), "Full")
-%!assert (matrix_type (tril (ones(10,10))), "Lower")
-%!assert (matrix_type (tril (ones(10,10),1)), "Full")
+%!assert (matrix_type (triu (ones (10,10))), "Upper")
+%!assert (matrix_type (triu (ones (10,10),-1)), "Full")
+%!assert (matrix_type (tril (ones (10,10))), "Lower")
+%!assert (matrix_type (tril (ones (10,10),1)), "Full")
 %!assert (matrix_type (10*eye (10,10) + ones (10,10)), "Positive Definite")
 %!assert (matrix_type (ones (11,10)), "Rectangular")
 %!test
--- a/libinterp/corefcn/max.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/max.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -269,7 +269,7 @@
           {
             if (arg.is_range () && (dim == -1 || dim == 1))
               {
-                Range range = arg.range_value ();
+                octave::range<double> range = arg.range_value ();
                 if (range.numel () < 1)
                   {
                     retval(0) = arg;
@@ -281,14 +281,14 @@
                     retval(0) = range.min ();
                     if (nargout > 1)
                       retval(1) = static_cast<double>
-                                  (range.inc () < 0 ? range.numel () : 1);
+                                  (range.increment () < 0 ? range.numel () : 1);
                   }
                 else
                   {
                     retval(0) = range.max ();
                     if (nargout > 1)
                       retval(1) = static_cast<double>
-                                  (range.inc () >= 0 ? range.numel () : 1);
+                                  (range.increment () >= 0 ? range.numel () : 1);
                   }
               }
             else if (arg.issparse ())
--- a/libinterp/corefcn/mex.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/mex.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -62,6 +62,197 @@
 #include "variables.h"
 #include "graphics.h"
 
+// These must be declared extern "C" but may be omitted from the set of
+// symbols declared in mexproto.h, so we declare them here as well.
+
+extern "C"
+{
+  extern OCTINTERP_API const mxArray *
+  mexGet_interleaved (double handle, const char *property);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateCellArray (mwSize ndims, const mwSize *dims);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateCellMatrix (mwSize m, mwSize n);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateCharArray (mwSize ndims, const mwSize *dims);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateCharMatrixFromStrings (mwSize m, const char **str);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateDoubleMatrix (mwSize nr, mwSize nc, mxComplexity flag);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateDoubleScalar (double val);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateLogicalArray (mwSize ndims, const mwSize *dims);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateLogicalMatrix (mwSize m, mwSize n);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateLogicalScalar (mxLogical val);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateNumericArray (mwSize ndims, const mwSize *dims, mxClassID class_id,
+                        mxComplexity flag);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateNumericMatrix (mwSize m, mwSize n, mxClassID class_id,
+                         mxComplexity flag);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateUninitNumericArray (mwSize ndims, const mwSize *dims,
+                              mxClassID class_id, mxComplexity flag);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateUninitNumericMatrix (mwSize m, mwSize n, mxClassID class_id,
+                               mxComplexity flag);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateSparse (mwSize m, mwSize n, mwSize nzmax, mxComplexity flag);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateSparseLogicalMatrix (mwSize m, mwSize n, mwSize nzmax);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateString (const char *str);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateStructArray (mwSize ndims, const mwSize *dims, int num_keys,
+                       const char **keys);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateStructMatrix (mwSize rows, mwSize cols, int num_keys,
+                        const char **keys);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateCellArray_interleaved (mwSize ndims, const mwSize *dims);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateCellMatrix_interleaved (mwSize m, mwSize n);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateCharArray_interleaved (mwSize ndims, const mwSize *dims);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateCharMatrixFromStrings_interleaved (mwSize m, const char **str);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateDoubleMatrix_interleaved (mwSize nr, mwSize nc, mxComplexity flag);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateDoubleScalar_interleaved (double val);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateLogicalArray_interleaved (mwSize ndims, const mwSize *dims);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateLogicalMatrix_interleaved (mwSize m, mwSize n);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateLogicalScalar_interleaved (mxLogical val);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateNumericArray_interleaved (mwSize ndims, const mwSize *dims,
+                                    mxClassID class_id, mxComplexity flag);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateNumericMatrix_interleaved (mwSize m, mwSize n, mxClassID class_id,
+                                     mxComplexity flag);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateUninitNumericArray_interleaved (mwSize ndims, const mwSize *dims,
+                                          mxClassID class_id,
+                                          mxComplexity flag);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateUninitNumericMatrix_interleaved (mwSize m, mwSize n,
+                                           mxClassID class_id,
+                                           mxComplexity flag);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateSparse_interleaved (mwSize m, mwSize n, mwSize nzmax,
+                              mxComplexity flag);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateSparseLogicalMatrix_interleaved (mwSize m, mwSize n, mwSize nzmax);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateString_interleaved (const char *str);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateStructArray_interleaved (mwSize ndims, const mwSize *dims,
+                                   int num_keys, const char **keys);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateStructMatrix_interleaved (mwSize rows, mwSize cols, int num_keys,
+                                    const char **keys);
+
+  extern OCTINTERP_API int mxMakeArrayReal (mxArray *ptr);
+  extern OCTINTERP_API int mxMakeArrayComplex (mxArray *ptr);
+
+  extern OCTINTERP_API mxDouble * mxGetDoubles (const mxArray *p);
+  extern OCTINTERP_API mxSingle * mxGetSingles (const mxArray *p);
+  extern OCTINTERP_API mxInt8 * mxGetInt8s (const mxArray *p);
+  extern OCTINTERP_API mxInt16 * mxGetInt16s (const mxArray *p);
+  extern OCTINTERP_API mxInt32 * mxGetInt32s (const mxArray *p);
+  extern OCTINTERP_API mxInt64 * mxGetInt64s (const mxArray *p);
+  extern OCTINTERP_API mxUint8 * mxGetUint8s (const mxArray *p);
+  extern OCTINTERP_API mxUint16 * mxGetUint16s (const mxArray *p);
+  extern OCTINTERP_API mxUint32 * mxGetUint32s (const mxArray *p);
+  extern OCTINTERP_API mxUint64 * mxGetUint64s (const mxArray *p);
+
+  extern OCTINTERP_API mxComplexDouble * mxGetComplexDoubles (const mxArray *p);
+  extern OCTINTERP_API mxComplexSingle * mxGetComplexSingles (const mxArray *p);
+#if 0
+  /* We don't have these yet. */
+  extern OCTINTERP_API mxComplexInt8 * mxGetComplexInt8s (const mxArray *p);
+  extern OCTINTERP_API mxComplexInt16 * mxGetComplexInt16s (const mxArray *p);
+  extern OCTINTERP_API mxComplexInt32 * mxGetComplexInt32s (const mxArray *p);
+  extern OCTINTERP_API mxComplexInt64 * mxGetComplexInt64s (const mxArray *p);
+  extern OCTINTERP_API mxComplexUint8 * mxGetComplexUint8s (const mxArray *p);
+  extern OCTINTERP_API mxComplexUint16 * mxGetComplexUint16s (const mxArray *p);
+  extern OCTINTERP_API mxComplexUint32 * mxGetComplexUint32s (const mxArray *p);
+  extern OCTINTERP_API mxComplexUint64 * mxGetComplexUint64s (const mxArray *p);
+#endif
+
+  extern OCTINTERP_API double * mxGetPi (const mxArray *ptr);
+  extern OCTINTERP_API void * mxGetImagData (const mxArray *ptr);
+
+  extern OCTINTERP_API int mxSetDoubles (mxArray *p, mxDouble *d);
+  extern OCTINTERP_API int mxSetSingles (mxArray *p, mxSingle *d);
+  extern OCTINTERP_API int mxSetInt8s (mxArray *p, mxInt8 *d);
+  extern OCTINTERP_API int mxSetInt16s (mxArray *p, mxInt16 *d);
+  extern OCTINTERP_API int mxSetInt32s (mxArray *p, mxInt32 *d);
+  extern OCTINTERP_API int mxSetInt64s (mxArray *p, mxInt64 *d);
+  extern OCTINTERP_API int mxSetUint8s (mxArray *p, mxUint8 *d);
+  extern OCTINTERP_API int mxSetUint16s (mxArray *p, mxUint16 *d);
+  extern OCTINTERP_API int mxSetUint32s (mxArray *p, mxUint32 *d);
+  extern OCTINTERP_API int mxSetUint64s (mxArray *p, mxUint64 *d);
+
+  extern OCTINTERP_API int mxSetComplexDoubles (mxArray *p, mxComplexDouble *d);
+  extern OCTINTERP_API int mxSetComplexSingles (mxArray *p, mxComplexSingle *d);
+#if 0
+  /* We don't have these yet. */
+  extern OCTINTERP_API int mxSetComplexInt8s (mxArray *p, mxComplexInt8 *d);
+  extern OCTINTERP_API int mxSetComplexInt16s (mxArray *p, mxComplexInt16 *d);
+  extern OCTINTERP_API int mxSetComplexInt32s (mxArray *p, mxComplexInt32 *d);
+  extern OCTINTERP_API int mxSetComplexInt64s (mxArray *p, mxComplexInt64 *d);
+  extern OCTINTERP_API int mxSetComplexUint8s (mxArray *p, mxComplexUint8 *d);
+  extern OCTINTERP_API int mxSetComplexUint16s (mxArray *p, mxComplexUint16 *d);
+  extern OCTINTERP_API int mxSetComplexUint32s (mxArray *p, mxComplexUint32 *d);
+  extern OCTINTERP_API int mxSetComplexUint64s (mxArray *p, mxComplexUint64 *d);
+#endif
+
+  extern OCTINTERP_API void mxSetPi (mxArray *ptr, double *pi);
+  extern OCTINTERP_API void mxSetImagData (mxArray *ptr, void *pi);
+}
+
 // #define DEBUG 1
 
 static void
@@ -112,6 +303,10 @@
 
 // ------------------------------------------------------------------
 
+mxArray_base::mxArray_base (bool interleaved)
+  : m_interleaved (interleaved)
+{ }
+
 static mwIndex
 calc_single_subscript_internal (mwSize ndims, const mwSize *dims,
                                 mwSize nsubs, const mwIndex *subs)
@@ -157,13 +352,26 @@
 
 static inline void * maybe_mark_foreign (void *ptr);
 
+#define VOID_MUTATION_METHOD(FCN_NAME, ARG_LIST)        \
+  void FCN_NAME ARG_LIST { request_mutation (); }
+
+#define CONST_VOID_MUTATION_METHOD(FCN_NAME, ARG_LIST)  \
+  void FCN_NAME ARG_LIST const { request_mutation (); }
+
+#define MUTATION_METHOD(RET_TYPE, FCN_NAME, ARG_LIST, RET_VAL)          \
+  RET_TYPE FCN_NAME ARG_LIST { request_mutation (); return RET_VAL; }
+
+#define CONST_MUTATION_METHOD(RET_TYPE, FCN_NAME, ARG_LIST, RET_VAL)    \
+  RET_TYPE FCN_NAME ARG_LIST const { request_mutation (); return RET_VAL; }
+
 class mxArray_octave_value : public mxArray_base
 {
 public:
 
-  mxArray_octave_value (const octave_value& ov)
-    : mxArray_base (), val (ov), mutate_flag (false),
-      id (mxUNKNOWN_CLASS), class_name (nullptr), ndims (-1), dims (nullptr) { }
+  mxArray_octave_value (bool interleaved, const octave_value& ov)
+    : mxArray_base (interleaved), val (ov), mutate_flag (false),
+      id (mxUNKNOWN_CLASS), class_name (nullptr), ndims (-1), dims (nullptr)
+  { }
 
   // No assignment!  FIXME: should this be implemented?  Note that we
   // do have a copy constructor.
@@ -174,7 +382,7 @@
 
   mxArray * as_mxArray (void) const
   {
-    mxArray *retval = val.as_mxArray ();
+    mxArray *retval = val.as_mxArray (m_interleaved);
 
     // RETVAL is assumed to be an mxArray_matlab object.  Should we
     // assert that condition here?
@@ -303,16 +511,10 @@
     return ndims;
   }
 
-  void set_m (mwSize /*m*/) { request_mutation (); }
-
-  void set_n (mwSize /*n*/) { request_mutation (); }
-
-  int set_dimensions (mwSize * /*dims_arg*/, mwSize /*ndims_arg*/)
-  {
-    request_mutation ();
-
-    return 0;
-  }
+  VOID_MUTATION_METHOD (set_m, (mwSize))
+  VOID_MUTATION_METHOD (set_n, (mwSize))
+
+  MUTATION_METHOD (int, set_dimensions, (mwSize *, mwSize), 0)
 
   mwSize get_number_of_elements (void) const { return val.numel (); }
 
@@ -378,7 +580,7 @@
   }
 
   // Not allowed.
-  void set_class_name (const char * /*name_arg*/) { request_mutation (); }
+  VOID_MUTATION_METHOD (set_class_name, (const char *))
 
   mxArray * get_property (mwIndex idx, const char *pname) const
   {
@@ -393,7 +595,7 @@
             octave_value pval = ov_cdef->get_property (idx, pname);
 
             if (pval.is_defined())
-              retval = new mxArray (pval);
+              retval = new mxArray (m_interleaved, pval);
           }
       }
 
@@ -410,17 +612,13 @@
           ov_cdef->set_property (idx, pname, pval->as_octave_value ());
       }
     else
-      err_invalid_type ();
+      err_invalid_type ("set_property");
   }
 
-  mxArray * get_cell (mwIndex /*idx*/) const
-  {
-    request_mutation ();
-    return nullptr;
-  }
+  CONST_MUTATION_METHOD (mxArray *, get_cell, (mwIndex), nullptr)
 
   // Not allowed.
-  void set_cell (mwIndex /*idx*/, mxArray * /*val*/) { request_mutation (); }
+  VOID_MUTATION_METHOD (set_cell, (mwIndex, mxArray *))
 
   double get_scalar (void) const
   {
@@ -454,6 +652,61 @@
     return retval;
   }
 
+  template <typename T>
+  T * get_data (mxClassID class_id, mxComplexity complexity) const
+  {
+    T *retval = static_cast<T *> (val.mex_get_data (class_id, complexity));
+
+    if (retval)
+      maybe_mark_foreign (retval);
+    else
+      request_mutation ();
+
+    return retval;
+  }
+
+  CONST_MUTATION_METHOD (mxDouble *, get_doubles, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxSingle *, get_singles, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxInt8 *, get_int8s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxInt16 *, get_int16s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxInt32 *, get_int32s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxInt64 *, get_int64s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxUint8 *, get_uint8s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxUint16 *, get_uint16s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxUint32 *, get_uint32s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxUint64 *, get_uint64s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxComplexDouble *, get_complex_doubles, (void), nullptr);
+  CONST_MUTATION_METHOD (mxComplexSingle *, get_complex_singles, (void), nullptr);
+
+#if 0
+  /* We don't have these yet. */
+  CONST_MUTATION_METHOD (mxComplexInt8 *, get_complex_int8s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxComplexInt16 *, get_complex_int16s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxComplexInt32 *, get_complex_int32s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxComplexInt64 *, get_complex_int64s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxComplexUint8 *, get_complex_uint8s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxComplexUint16 *, get_complex_uint16s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxComplexUint32 *, get_complex_uint32s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxComplexUint64 *, get_complex_uint64s, (void), nullptr);
+#endif
+
   void * get_imag_data (void) const
   {
     void *retval = nullptr;
@@ -467,10 +720,35 @@
   }
 
   // Not allowed.
-  void set_data (void * /*pr*/) { request_mutation (); }
+  VOID_MUTATION_METHOD (set_data, (void *))
+
+  MUTATION_METHOD (int, set_doubles, (mxDouble *), 0)
+  MUTATION_METHOD (int, set_singles, (mxSingle *), 0)
+  MUTATION_METHOD (int, set_int8s, (mxInt8 *), 0)
+  MUTATION_METHOD (int, set_int16s, (mxInt16 *), 0)
+  MUTATION_METHOD (int, set_int32s, (mxInt32 *), 0)
+  MUTATION_METHOD (int, set_int64s, (mxInt64 *), 0)
+  MUTATION_METHOD (int, set_uint8s, (mxUint8 *), 0)
+  MUTATION_METHOD (int, set_uint16s, (mxUint16 *), 0)
+  MUTATION_METHOD (int, set_uint32s, (mxUint32 *), 0)
+  MUTATION_METHOD (int, set_uint64s, (mxUint64 *), 0)
+
+  MUTATION_METHOD (int, set_complex_doubles, (mxComplexDouble *), 0)
+  MUTATION_METHOD (int, set_complex_singles, (mxComplexSingle *), 0)
+#if 0
+  /* We don't have these yet. */
+  MUTATION_METHOD (int, set_complex_int8s, (mxComplexInt8 *), 0)
+  MUTATION_METHOD (int, set_complex_int16s, (mxComplexInt16 *), 0)
+  MUTATION_METHOD (int, set_complex_int32s, (mxComplexInt32 *), 0)
+  MUTATION_METHOD (int, set_complex_int64s, (mxComplexInt64 *), 0)
+  MUTATION_METHOD (int, set_complex_uint8s, (mxComplexUint8 *), 0)
+  MUTATION_METHOD (int, set_complex_uint16s, (mxComplexUint16 *), 0)
+  MUTATION_METHOD (int, set_complex_uint32s, (mxComplexUint32 *), 0)
+  MUTATION_METHOD (int, set_complex_uint64s, (mxComplexUint64 *), 0)
+#endif
 
   // Not allowed.
-  void set_imag_data (void * /*pi*/) { request_mutation (); }
+  VOID_MUTATION_METHOD (set_imag_data, (void *))
 
   mwIndex * get_ir (void) const
   {
@@ -485,50 +763,30 @@
   mwSize get_nzmax (void) const { return val.nzmax (); }
 
   // Not allowed.
-  void set_ir (mwIndex * /*ir*/) { request_mutation (); }
-
-  // Not allowed.
-  void set_jc (mwIndex * /*jc*/) { request_mutation (); }
+  VOID_MUTATION_METHOD (set_ir, (mwIndex *))
 
   // Not allowed.
-  void set_nzmax (mwSize /*nzmax*/) { request_mutation (); }
+  VOID_MUTATION_METHOD (set_jc, (mwIndex *))
 
   // Not allowed.
-  int add_field (const char * /*key*/)
-  {
-    request_mutation ();
-    return 0;
-  }
+  VOID_MUTATION_METHOD (set_nzmax, (mwSize))
+
+  // Not allowed.
+  MUTATION_METHOD (int, add_field, (const char *), 0)
 
   // Not allowed.
-  void remove_field (int /*key_num*/) { request_mutation (); }
-
-  mxArray * get_field_by_number (mwIndex /*index*/, int /*key_num*/) const
-  {
-    request_mutation ();
-    return nullptr;
-  }
+  VOID_MUTATION_METHOD (remove_field, (int))
+
+  CONST_MUTATION_METHOD (mxArray *, get_field_by_number, (mwIndex, int), nullptr)
 
   // Not allowed.
-  void set_field_by_number (mwIndex /*index*/, int /*key_num*/,
-                            mxArray * /*val*/)
-  {
-    request_mutation ();
-  }
+  VOID_MUTATION_METHOD (set_field_by_number, (mwIndex, int, mxArray *))
 
   int get_number_of_fields (void) const { return val.nfields (); }
 
-  const char * get_field_name_by_number (int /*key_num*/) const
-  {
-    request_mutation ();
-    return nullptr;
-  }
-
-  int get_field_number (const char * /*key*/) const
-  {
-    request_mutation ();
-    return 0;
-  }
+  CONST_MUTATION_METHOD (const char *, get_field_name_by_number, (int), nullptr)
+
+  CONST_MUTATION_METHOD (int, get_field_number, (const char *), 0)
 
   int get_string (char *buf, mwSize buflen) const
   {
@@ -596,21 +854,21 @@
 
     switch (id)
       {
-      case mxDOUBLE_CLASS: return sizeof (double);
-      case mxSINGLE_CLASS: return sizeof (float);
-      case mxCHAR_CLASS: return sizeof (mxChar);
-      case mxLOGICAL_CLASS: return sizeof (mxLogical);
       case mxCELL_CLASS: return sizeof (mxArray *);
       case mxSTRUCT_CLASS: return sizeof (mxArray *);
+      case mxLOGICAL_CLASS: return sizeof (mxLogical);
+      case mxCHAR_CLASS: return sizeof (mxChar);
+      case mxDOUBLE_CLASS: return get_numeric_element_size (sizeof (mxDouble));
+      case mxSINGLE_CLASS: return get_numeric_element_size (sizeof (mxSingle));
+      case mxINT8_CLASS: return get_numeric_element_size (sizeof (mxInt8));
+      case mxUINT8_CLASS: return get_numeric_element_size (sizeof (mxUint8));
+      case mxINT16_CLASS: return get_numeric_element_size (sizeof (mxInt16));
+      case mxUINT16_CLASS: return get_numeric_element_size (sizeof (mxUint16));
+      case mxINT32_CLASS: return get_numeric_element_size (sizeof (mxInt32));
+      case mxUINT32_CLASS: return get_numeric_element_size (sizeof (mxUint32));
+      case mxINT64_CLASS: return get_numeric_element_size (sizeof (mxInt64));
+      case mxUINT64_CLASS: return get_numeric_element_size (sizeof (mxUint64));
       case mxFUNCTION_CLASS: return 0;
-      case mxINT8_CLASS: return 1;
-      case mxUINT8_CLASS: return 1;
-      case mxINT16_CLASS: return 2;
-      case mxUINT16_CLASS: return 2;
-      case mxINT32_CLASS: return 4;
-      case mxUINT32_CLASS: return 4;
-      case mxINT64_CLASS: return 8;
-      case mxUINT64_CLASS: return 8;
       // FIXME: user-defined objects need their own class ID.
       //        What should they return, size of pointer?
       default: return 0;
@@ -637,9 +895,9 @@
     : mxArray_base (arg), val (arg.val), mutate_flag (arg.mutate_flag),
       id (arg.id), class_name (mxArray::strsave (arg.class_name)),
       ndims (arg.ndims),
-      dims (ndims > 0 ? static_cast<mwSize *>
-                         (mxArray::malloc (ndims * sizeof (mwSize)))
-                      : nullptr)
+      dims (ndims > 0
+            ? static_cast<mwSize *> (mxArray::malloc (ndims * sizeof (mwSize)))
+            : nullptr)
   {
     if (dims)
       {
@@ -671,13 +929,14 @@
 {
 protected:
 
-  mxArray_matlab (mxClassID id_arg = mxUNKNOWN_CLASS)
-    : mxArray_base (), class_name (nullptr), id (id_arg), ndims (0),
+  mxArray_matlab (bool interleaved, mxClassID id_arg = mxUNKNOWN_CLASS)
+    : mxArray_base (interleaved), class_name (nullptr), id (id_arg), ndims (0),
       dims (nullptr)
   { }
 
-  mxArray_matlab (mxClassID id_arg, mwSize ndims_arg, const mwSize *dims_arg)
-    : mxArray_base (), class_name (nullptr), id (id_arg),
+  mxArray_matlab (bool interleaved, mxClassID id_arg, mwSize ndims_arg,
+                  const mwSize *dims_arg)
+    : mxArray_base (interleaved), class_name (nullptr), id (id_arg),
       ndims (ndims_arg < 2 ? 2 : ndims_arg),
       dims (static_cast<mwSize *> (mxArray::malloc (ndims * sizeof (mwSize))))
   {
@@ -704,8 +963,8 @@
       }
   }
 
-  mxArray_matlab (mxClassID id_arg, const dim_vector& dv)
-    : mxArray_base (), class_name (nullptr), id (id_arg),
+  mxArray_matlab (bool interleaved, mxClassID id_arg, const dim_vector& dv)
+    : mxArray_base (interleaved), class_name (nullptr), id (id_arg),
       ndims (dv.ndims ()),
       dims (static_cast<mwSize *> (mxArray::malloc (ndims * sizeof (mwSize))))
   {
@@ -721,8 +980,8 @@
       }
   }
 
-  mxArray_matlab (mxClassID id_arg, mwSize m, mwSize n)
-    : mxArray_base (), class_name (nullptr), id (id_arg), ndims (2),
+  mxArray_matlab (bool interleaved, mxClassID id_arg, mwSize m, mwSize n)
+    : mxArray_base (interleaved), class_name (nullptr), id (id_arg), ndims (2),
       dims (static_cast<mwSize *> (mxArray::malloc (ndims * sizeof (mwSize))))
   {
     dims[0] = m;
@@ -900,98 +1159,304 @@
 
   mxArray * get_cell (mwIndex /*idx*/) const
   {
-    err_invalid_type ();
+    err_invalid_type ("get_cell");
   }
 
   void set_cell (mwIndex /*idx*/, mxArray * /*val*/)
   {
-    err_invalid_type ();
+    err_invalid_type ("set_cell");
   }
 
   double get_scalar (void) const
   {
-    err_invalid_type ();
+    err_invalid_type ("get_scalar");
   }
 
   void * get_data (void) const
   {
-    err_invalid_type ();
+    err_invalid_type ("get_data");
+  }
+
+  mxDouble * get_doubles (void) const
+  {
+    err_invalid_type ("get_doubles");
+  }
+
+  mxSingle * get_singles (void) const
+  {
+    err_invalid_type ("get_singles");
+  }
+
+  mxInt8 * get_int8s (void) const
+  {
+    err_invalid_type ("get_int8s");
+  }
+
+  mxInt16 * get_int16s (void) const
+  {
+    err_invalid_type ("get_int16s");
+  }
+
+  mxInt32 * get_int32s (void) const
+  {
+    err_invalid_type ("get_int32s");
+  }
+
+  mxInt64 * get_int64s (void) const
+  {
+    err_invalid_type ("get_int64s");
+  }
+
+  mxUint8 * get_uint8s (void) const
+  {
+    err_invalid_type ("get_uint8s");
+  }
+
+  mxUint16 * get_uint16s (void) const
+  {
+    err_invalid_type ("get_uint16s");
+  }
+
+  mxUint32 * get_uint32s (void) const
+  {
+    err_invalid_type ("get_uint32s");
+  }
+
+  mxUint64 * get_uint64s (void) const
+  {
+    err_invalid_type ("get_uint64s");
   }
 
+  mxComplexDouble * get_complex_doubles (void) const
+  {
+    err_invalid_type ("get_complex_doubles");
+  }
+
+  mxComplexSingle * get_complex_singles (void) const
+  {
+    err_invalid_type ("get_complex_singles");
+  }
+
+#if 0
+  /* We don't have these yet. */
+  mxComplexInt8 * get_complex_int8s (void) const
+  {
+    err_invalid_type ("get_complex_int8s");
+  }
+
+  mxComplexInt16 * get_complex_int16s (void) const
+  {
+    err_invalid_type ("get_complex_int16s");
+  }
+
+  mxComplexInt32 * get_complex_int32s (void) const
+  {
+    err_invalid_type ("get_complex_int32s");
+  }
+
+  mxComplexInt64 * get_complex_int64s (void) const
+  {
+    err_invalid_type ("get_complex_int64s");
+  }
+
+  mxComplexUint8 * get_complex_uint8s (void) const
+  {
+    err_invalid_type ("get_complex_uint8s");
+  }
+
+  mxComplexUint16 * get_complex_uint16s (void) const
+  {
+    err_invalid_type ("get_complex_uint16s");
+  }
+
+  mxComplexUint32 * get_complex_uint32s (void) const
+  {
+    err_invalid_type ("get_complex_uint32s");
+  }
+
+  mxComplexUint64 * get_complex_uint64s (void) const
+  {
+    err_invalid_type ("get_complex_uint64s");
+  }
+#endif
+
   void * get_imag_data (void) const
   {
-    err_invalid_type ();
+    err_invalid_type ("get_imag_data");
   }
 
   void set_data (void * /*pr*/)
   {
-    err_invalid_type ();
+    err_invalid_type ("set_data");
+  }
+
+  int set_doubles (mxDouble *)
+  {
+    err_invalid_type ("set_doubles");
+  }
+
+  int set_singles (mxSingle *)
+  {
+    err_invalid_type ("set_singles");
+  }
+
+  int set_int8s (mxInt8 *)
+  {
+    err_invalid_type ("set_int8s");
+  }
+
+  int set_int16s (mxInt16 *)
+  {
+    err_invalid_type ("set_int16s");
+  }
+
+  int set_int32s (mxInt32 *)
+  {
+    err_invalid_type ("set_int32s");
+  }
+
+  int set_int64s (mxInt64 *)
+  {
+    err_invalid_type ("set_int64s");
+  }
+
+  int set_uint8s (mxUint8 *)
+  {
+    err_invalid_type ("set_uint8s");
+  }
+
+  int set_uint16s (mxUint16 *)
+  {
+    err_invalid_type ("set_uint16s");
+  }
+
+  int set_uint32s (mxUint32 *)
+  {
+    err_invalid_type ("set_uint32s");
+  }
+
+  int set_uint64s (mxUint64 *)
+  {
+    err_invalid_type ("set_uint64s");
   }
 
+  int set_complex_doubles (mxComplexDouble *)
+  {
+    err_invalid_type ("set_complex_doubles");
+  }
+
+  int set_complex_singles (mxComplexSingle *)
+  {
+    err_invalid_type ("set_complex_singles");
+  }
+
+#if 0
+  /* We don't have these yet. */
+  int set_complex_int8s (mxComplexInt8 *)
+  {
+    err_invalid_type ("set_complex_int8s");
+  }
+
+  int set_complex_int16s (mxComplexInt16 *)
+  {
+    err_invalid_type ("set_complex_int16s");
+  }
+
+  int set_complex_int32s (mxComplexInt32 *)
+  {
+    err_invalid_type ("set_complex_int32s");
+  }
+
+  int set_complex_int64s (mxComplexInt64 *)
+  {
+    err_invalid_type ("set_complex_int64s");
+  }
+
+  int set_complex_uint8s (mxComplexUint8 *)
+  {
+    err_invalid_type ("set_complex_uint8s");
+  }
+
+  int set_complex_uint16s (mxComplexUint16 *)
+  {
+    err_invalid_type ("set_complex_uint16s");
+  }
+
+  int set_complex_uint32s (mxComplexUint32 *)
+  {
+    err_invalid_type ("set_complex_uint32s");
+  }
+
+  int set_complex_uint64s (mxComplexUint64 *)
+  {
+    err_invalid_type ("set_complex_uint64s");
+  }
+#endif
+
   void set_imag_data (void * /*pi*/)
   {
-    err_invalid_type ();
+    err_invalid_type ("set_imag_data");
   }
 
   mwIndex * get_ir (void) const
   {
-    err_invalid_type ();
+    err_invalid_type ("get_ir");
   }
 
   mwIndex * get_jc (void) const
   {
-    err_invalid_type ();
+    err_invalid_type ("get_jc");
   }
 
   mwSize get_nzmax (void) const
   {
-    err_invalid_type ();
+    err_invalid_type ("get_nzmax");
   }
 
   void set_ir (mwIndex * /*ir*/)
   {
-    err_invalid_type ();
+    err_invalid_type ("set_ir");
   }
 
   void set_jc (mwIndex * /*jc*/)
   {
-    err_invalid_type ();
+    err_invalid_type ("set_jc");
   }
 
   void set_nzmax (mwSize /*nzmax*/)
   {
-    err_invalid_type ();
+    err_invalid_type ("set_nzmax");
   }
 
   int add_field (const char * /*key*/)
   {
-    err_invalid_type ();
+    err_invalid_type ("add_field");
   }
 
   void remove_field (int /*key_num*/)
   {
-    err_invalid_type ();
+    err_invalid_type ("remove_field");
   }
 
   mxArray * get_field_by_number (mwIndex /*index*/, int /*key_num*/) const
   {
-    err_invalid_type ();
+    err_invalid_type ("get_field_by_number");
   }
 
   void set_field_by_number (mwIndex /*index*/, int /*key_num*/,
                             mxArray * /*val*/)
   {
-    err_invalid_type ();
+    err_invalid_type ("set_field_by_number");
   }
 
   int get_number_of_fields (void) const
   {
-    err_invalid_type ();
+    err_invalid_type ("get_number_of_fields");
   }
 
   const char * get_field_name_by_number (int /*key_num*/) const
   {
-    err_invalid_type ();
+    err_invalid_type ("get_field_name_by_number");
   }
 
   int get_field_number (const char * /*key*/) const
@@ -1001,12 +1466,12 @@
 
   int get_string (char * /*buf*/, mwSize /*buflen*/) const
   {
-    err_invalid_type ();
+    err_invalid_type ("get_string");
   }
 
   char * array_to_string (void) const
   {
-    err_invalid_type ();
+    err_invalid_type ("array_to_string");
   }
 
   mwIndex calc_single_subscript (mwSize nsubs, mwIndex *subs) const
@@ -1022,16 +1487,16 @@
       case mxSTRUCT_CLASS: return sizeof (mxArray *);
       case mxLOGICAL_CLASS: return sizeof (mxLogical);
       case mxCHAR_CLASS: return sizeof (mxChar);
-      case mxDOUBLE_CLASS: return sizeof (double);
-      case mxSINGLE_CLASS: return sizeof (float);
-      case mxINT8_CLASS: return 1;
-      case mxUINT8_CLASS: return 1;
-      case mxINT16_CLASS: return 2;
-      case mxUINT16_CLASS: return 2;
-      case mxINT32_CLASS: return 4;
-      case mxUINT32_CLASS: return 4;
-      case mxINT64_CLASS: return 8;
-      case mxUINT64_CLASS: return 8;
+      case mxDOUBLE_CLASS: return get_numeric_element_size (sizeof (mxDouble));
+      case mxSINGLE_CLASS: return get_numeric_element_size (sizeof (mxSingle));
+      case mxINT8_CLASS: return get_numeric_element_size (sizeof (mxInt8));
+      case mxUINT8_CLASS: return get_numeric_element_size (sizeof (mxUint8));
+      case mxINT16_CLASS: return get_numeric_element_size (sizeof (mxInt16));
+      case mxUINT16_CLASS: return get_numeric_element_size (sizeof (mxUint16));
+      case mxINT32_CLASS: return get_numeric_element_size (sizeof (mxInt32));
+      case mxUINT32_CLASS: return get_numeric_element_size (sizeof (mxUint32));
+      case mxINT64_CLASS: return get_numeric_element_size (sizeof (mxInt64));
+      case mxUINT64_CLASS: return get_numeric_element_size (sizeof (mxUint64));
       case mxFUNCTION_CLASS: return 0;
       // FIXME: user-defined objects need their own class ID.
       //        What should they return, size of pointer?
@@ -1065,59 +1530,79 @@
 
   mwSize ndims;
   mwSize *dims;
-
-  OCTAVE_NORETURN void err_invalid_type (void) const
-  {
-    error ("invalid type for operation");
-  }
 };
 
+
 // Matlab-style numeric, character, and logical data.
 
+#define TYPED_GET_METHOD(TYPE, FCN_NAME)        \
+  TYPE FCN_NAME (void) const                    \
+  {                                             \
+    if (! m_interleaved)                        \
+      panic_impossible ();                      \
+                                                \
+    return static_cast<TYPE> (pr);              \
+  }
+
+#define TYPED_SET_METHOD(TYPE, FCN_NAME)        \
+  int FCN_NAME (TYPE d)                         \
+  {                                             \
+    if (! m_interleaved)                        \
+      panic_impossible ();                      \
+                                                \
+    pr = d;                                     \
+    return 0;                                   \
+  }
+
 class mxArray_number : public mxArray_matlab
 {
 public:
 
-  mxArray_number (mxClassID id_arg, mwSize ndims_arg, const mwSize *dims_arg,
-                  mxComplexity flag = mxREAL, bool init = true)
-    : mxArray_matlab (id_arg, ndims_arg, dims_arg),
-      pr (init ? mxArray::calloc (get_number_of_elements (),
-                                  get_element_size ())
-               : mxArray::malloc (get_number_of_elements ()
-                                  * get_element_size ())),
-      pi (flag == mxCOMPLEX
-            ? (init ? mxArray::calloc (get_number_of_elements (),
-                                       get_element_size ())
-                    : mxArray::malloc (get_number_of_elements ()
-                                       * get_element_size ()))
-            : nullptr) { }
-
-  mxArray_number (mxClassID id_arg, const dim_vector& dv,
+  mxArray_number (bool interleaved, mxClassID id_arg, mwSize ndims_arg,
+                  const mwSize *dims_arg, mxComplexity flag = mxREAL,
+                  bool init = true)
+    : mxArray_matlab (interleaved, id_arg, ndims_arg, dims_arg),
+      m_complex (flag == mxCOMPLEX),
+      pr (init
+          ? mxArray::calloc (get_number_of_elements (), get_element_size ())
+          : mxArray::malloc (get_number_of_elements () * get_element_size ())),
+      pi (m_interleaved
+          ? nullptr
+          : (m_complex
+             ? (init
+                ? mxArray::calloc (get_number_of_elements (), get_element_size ())
+                : mxArray::malloc (get_number_of_elements () * get_element_size ()))
+             : nullptr))
+  { }
+
+  mxArray_number (bool interleaved, mxClassID id_arg, const dim_vector& dv,
                   mxComplexity flag = mxREAL)
-    : mxArray_matlab (id_arg, dv),
+    : mxArray_matlab (interleaved, id_arg, dv), m_complex (flag == mxCOMPLEX),
       pr (mxArray::calloc (get_number_of_elements (), get_element_size ())),
-      pi (flag == mxCOMPLEX ? mxArray::calloc (get_number_of_elements (),
-                                               get_element_size ())
-                            : nullptr)
+      pi (m_interleaved
+          ? nullptr
+          : (m_complex
+             ? mxArray::calloc (get_number_of_elements (), get_element_size ())
+             : nullptr))
   { }
 
-  mxArray_number (mxClassID id_arg, mwSize m, mwSize n,
+  mxArray_number (bool interleaved, mxClassID id_arg, mwSize m, mwSize n,
                   mxComplexity flag = mxREAL, bool init = true)
-    : mxArray_matlab (id_arg, m, n),
-      pr (init ? mxArray::calloc (get_number_of_elements (),
-                                  get_element_size ())
-               : mxArray::malloc (get_number_of_elements ()
-                                  * get_element_size ())),
-      pi (flag == mxCOMPLEX
-            ? (init ? mxArray::calloc (get_number_of_elements (),
-                                       get_element_size ())
-                    : mxArray::malloc (get_number_of_elements ()
-                                       * get_element_size ()))
-            : nullptr)
+    : mxArray_matlab (interleaved, id_arg, m, n), m_complex (flag == mxCOMPLEX),
+      pr (init
+          ? mxArray::calloc (get_number_of_elements (), get_element_size ())
+          : mxArray::malloc (get_number_of_elements () * get_element_size ())),
+      pi (m_interleaved
+          ? nullptr
+          : (m_complex
+             ? (init
+                ? mxArray::calloc (get_number_of_elements (), get_element_size ())
+                : mxArray::malloc (get_number_of_elements () * get_element_size ()))
+             : nullptr))
   { }
 
-  mxArray_number (mxClassID id_arg, double val)
-    : mxArray_matlab (id_arg, 1, 1),
+  mxArray_number (bool interleaved, mxClassID id_arg, double val)
+    : mxArray_matlab (interleaved, id_arg, 1, 1), m_complex (false),
       pr (mxArray::calloc (get_number_of_elements (), get_element_size ())),
       pi (nullptr)
   {
@@ -1125,8 +1610,8 @@
     dpr[0] = val;
   }
 
-  mxArray_number (mxClassID id_arg, mxLogical val)
-    : mxArray_matlab (id_arg, 1, 1),
+  mxArray_number (bool interleaved, mxClassID id_arg, mxLogical val)
+    : mxArray_matlab (interleaved, id_arg, 1, 1), m_complex (false),
       pr (mxArray::calloc (get_number_of_elements (), get_element_size ())),
       pi (nullptr)
   {
@@ -1134,10 +1619,11 @@
     lpr[0] = val;
   }
 
-  mxArray_number (const char *str)
-    : mxArray_matlab (mxCHAR_CLASS,
+  mxArray_number (bool interleaved, const char *str)
+    : mxArray_matlab (interleaved, mxCHAR_CLASS,
                       str ? (strlen (str) ? 1 : 0) : 0,
                       str ? strlen (str) : 0),
+      m_complex (false),
       pr (mxArray::calloc (get_number_of_elements (), get_element_size ())),
       pi (nullptr)
   {
@@ -1148,8 +1634,9 @@
   }
 
   // FIXME: ???
-  mxArray_number (mwSize m, const char **str)
-    : mxArray_matlab (mxCHAR_CLASS, m, max_str_len (m, str)),
+  mxArray_number (bool interleaved, mwSize m, const char **str)
+    : mxArray_matlab (interleaved, mxCHAR_CLASS, m, max_str_len (m, str)),
+      m_complex (false),
       pr (mxArray::calloc (get_number_of_elements (), get_element_size ())),
       pi (nullptr)
   {
@@ -1176,11 +1663,13 @@
 protected:
 
   mxArray_number (const mxArray_number& val)
-    : mxArray_matlab (val),
+    : mxArray_matlab (val), m_complex (val.m_complex),
       pr (mxArray::malloc (get_number_of_elements () * get_element_size ())),
-      pi (val.pi ? mxArray::malloc (get_number_of_elements ()
-                                    * get_element_size ())
-                 : nullptr)
+      pi (m_interleaved
+          ? nullptr
+          : (val.pi
+             ? mxArray::malloc (get_number_of_elements () * get_element_size ())
+             : nullptr))
   {
     size_t nbytes = get_number_of_elements () * get_element_size ();
 
@@ -1198,7 +1687,10 @@
 
   mxArray_number& operator = (const mxArray_number&);
 
-  mxArray_base * dup (void) const { return new mxArray_number (*this); }
+  mxArray_base * dup (void) const
+  {
+    return new mxArray_number (*this);
+  }
 
   ~mxArray_number (void)
   {
@@ -1206,10 +1698,15 @@
     mxFree (pi);
   }
 
-  int is_complex (void) const { return pi != nullptr; }
+  int is_complex (void) const
+  {
+    return m_interleaved ? m_complex : (pi != nullptr);
+  }
 
   double get_scalar (void) const
   {
+    // FIXME: how does this work for interleaved complex arrays?
+
     double retval = 0;
 
     switch (get_class_id ())
@@ -1271,11 +1768,73 @@
 
   void * get_data (void) const { return pr; }
 
-  void * get_imag_data (void) const { return pi; }
+  void * get_imag_data (void) const
+  {
+    if (m_interleaved)
+      panic_impossible ();
+
+    return pi;
+  }
 
   void set_data (void *pr_arg) { pr = pr_arg; }
 
-  void set_imag_data (void *pi_arg) { pi = pi_arg; }
+  void set_imag_data (void *pi_arg)
+  {
+    if (m_interleaved)
+      panic_impossible ();
+
+    pi = pi_arg;
+  }
+
+  TYPED_GET_METHOD (mxDouble *, get_doubles)
+  TYPED_GET_METHOD (mxSingle *, get_singles)
+  TYPED_GET_METHOD (mxInt8 *, get_int8s)
+  TYPED_GET_METHOD (mxInt16 *, get_int16s)
+  TYPED_GET_METHOD (mxInt32 *, get_int32s)
+  TYPED_GET_METHOD (mxInt64 *, get_int64s)
+  TYPED_GET_METHOD (mxUint8 *, get_uint8s)
+  TYPED_GET_METHOD (mxUint16 *, get_uint16s)
+  TYPED_GET_METHOD (mxUint32 *, get_uint32s)
+  TYPED_GET_METHOD (mxUint64 *, get_uint64s)
+
+  TYPED_GET_METHOD (mxComplexDouble *, get_complex_doubles)
+  TYPED_GET_METHOD (mxComplexSingle *, get_complex_singles)
+#if 0
+  /* We don't have these yet. */
+  TYPED_GET_METHOD (mxComplexInt8 *, get_complex_int8s)
+  TYPED_GET_METHOD (mxComplexInt16 *, get_complex_int16s)
+  TYPED_GET_METHOD (mxComplexInt32 *, get_complex_int32s)
+  TYPED_GET_METHOD (mxComplexInt64 *, get_complex_int64s)
+  TYPED_GET_METHOD (mxComplexUint8 *, get_complex_uint8s)
+  TYPED_GET_METHOD (mxComplexUint16 *, get_complex_uint16s)
+  TYPED_GET_METHOD (mxComplexUint32 *, get_complex_uint32s)
+  TYPED_GET_METHOD (mxComplexUint64 *, get_complex_uint64s)
+#endif
+
+  TYPED_SET_METHOD (mxDouble *, set_doubles)
+  TYPED_SET_METHOD (mxSingle *, set_singles)
+  TYPED_SET_METHOD (mxInt8 *, set_int8s)
+  TYPED_SET_METHOD (mxInt16 *, set_int16s)
+  TYPED_SET_METHOD (mxInt32 *, set_int32s)
+  TYPED_SET_METHOD (mxInt64 *, set_int64s)
+  TYPED_SET_METHOD (mxUint8 *, set_uint8s)
+  TYPED_SET_METHOD (mxUint16 *, set_uint16s)
+  TYPED_SET_METHOD (mxUint32 *, set_uint32s)
+  TYPED_SET_METHOD (mxUint64 *, set_uint64s)
+
+  TYPED_SET_METHOD (mxComplexDouble *, set_complex_doubles)
+  TYPED_SET_METHOD (mxComplexSingle *, set_complex_singles)
+#if 0
+  /* We don't have these yet. */
+  TYPED_SET_METHOD (mxComplexInt8 *, set_complex_int8s)
+  TYPED_SET_METHOD (mxComplexInt16 *, set_complex_int16s)
+  TYPED_SET_METHOD (mxComplexInt32 *, set_complex_int32s)
+  TYPED_SET_METHOD (mxComplexInt64 *, set_complex_int64s)
+  TYPED_SET_METHOD (mxComplexUint8 *, set_complex_uint8s)
+  TYPED_SET_METHOD (mxComplexUint16 *, set_complex_uint16s)
+  TYPED_SET_METHOD (mxComplexUint32 *, set_complex_uint32s)
+  TYPED_SET_METHOD (mxComplexUint64 *, set_complex_uint64s)
+#endif
 
   int get_string (char *buf, mwSize buflen) const
   {
@@ -1336,23 +1895,40 @@
         {
           mwSize nel = get_number_of_elements ();
 
-          double *ppr = static_cast<double *> (pr);
-
-          if (pi)
+          if (is_complex ())
             {
-              ComplexNDArray val (dv);
-
-              Complex *ptr = val.fortran_vec ();
-
-              double *ppi = static_cast<double *> (pi);
-
-              for (mwIndex i = 0; i < nel; i++)
-                ptr[i] = Complex (ppr[i], ppi[i]);
-
-              retval = val;
+              if (m_interleaved)
+                {
+                  Complex *ppr = static_cast<Complex *> (pr);
+
+                  ComplexNDArray val (dv);
+                  Complex *ptr = val.fortran_vec ();
+
+                  for (mwIndex i = 0; i < nel; i++)
+                    ptr[i] = ppr[i];
+
+                  retval = val;
+                }
+              else
+                {
+                  double *ppr = static_cast<double *> (pr);
+
+                  ComplexNDArray val (dv);
+
+                  Complex *ptr = val.fortran_vec ();
+
+                  double *ppi = static_cast<double *> (pi);
+
+                  for (mwIndex i = 0; i < nel; i++)
+                    ptr[i] = Complex (ppr[i], ppi[i]);
+
+                  retval = val;
+                }
             }
           else
             {
+              double *ppr = static_cast<double *> (pr);
+
               NDArray val (dv);
 
               double *ptr = val.fortran_vec ();
@@ -1369,23 +1945,40 @@
         {
           mwSize nel = get_number_of_elements ();
 
-          float *ppr = static_cast<float *> (pr);
-
-          if (pi)
+          if (is_complex ())
             {
-              FloatComplexNDArray val (dv);
-
-              FloatComplex *ptr = val.fortran_vec ();
-
-              float *ppi = static_cast<float *> (pi);
-
-              for (mwIndex i = 0; i < nel; i++)
-                ptr[i] = FloatComplex (ppr[i], ppi[i]);
-
-              retval = val;
+              if (m_interleaved)
+                {
+                  FloatComplex *ppr = static_cast<FloatComplex *> (pr);
+
+                  FloatComplexNDArray val (dv);
+                  FloatComplex *ptr = val.fortran_vec ();
+
+                  for (mwIndex i = 0; i < nel; i++)
+                    ptr[i] = ppr[i];
+
+                  retval = val;
+                }
+              else
+                {
+                  float *ppr = static_cast<float *> (pr);
+
+                  FloatComplexNDArray val (dv);
+
+                  FloatComplex *ptr = val.fortran_vec ();
+
+                  float *ppi = static_cast<float *> (pi);
+
+                  for (mwIndex i = 0; i < nel; i++)
+                    ptr[i] = FloatComplex (ppr[i], ppi[i]);
+
+                  retval = val;
+                }
             }
           else
             {
+              float *ppr = static_cast<float *> (pr);
+
               FloatNDArray val (dv);
 
               float *ptr = val.fortran_vec ();
@@ -1464,7 +2057,7 @@
   octave_value
   int_to_ov (const dim_vector& dv) const
   {
-    if (pi)
+    if (is_complex ())
       error ("complex integer types are not supported");
 
     mwSize nel = get_number_of_elements ();
@@ -1483,7 +2076,17 @@
 
 private:
 
+  // Flag to identify complex object if using interleaved data and PI is
+  // always nullptr.
+  bool m_complex;
+
+  // If using interleaved complex storage, this is the pointer to data
+  // (real, complex, or logical).  Otherwise, it is the pointer to the
+  // real part of the data.
   void *pr;
+
+  // If using non-interleaved complex storage, this is the pointer to
+  // the imaginary part of the data.  Othrwise is is always nullptr.
   void *pi;
 };
 
@@ -1493,24 +2096,31 @@
 {
 public:
 
-  mxArray_sparse (mxClassID id_arg, mwSize m, mwSize n, mwSize nzmax_arg,
-                  mxComplexity flag = mxREAL)
-    : mxArray_matlab (id_arg, m, n)
-  {
-    nzmax = (nzmax_arg > 0 ? nzmax_arg : 1);
-    pr = mxArray::calloc (nzmax, get_element_size ());
-    pi = (flag == mxCOMPLEX ? mxArray::calloc (nzmax, get_element_size ())
-                            : nullptr);
-    ir = (static_cast<mwIndex *> (mxArray::calloc (nzmax, sizeof (mwIndex))));
-    jc = (static_cast<mwIndex *> (mxArray::calloc (n + 1, sizeof (mwIndex))));
-  }
+  mxArray_sparse (bool interleaved, mxClassID id_arg, mwSize m, mwSize n,
+                  mwSize nzmax_arg, mxComplexity flag = mxREAL)
+    : mxArray_matlab (interleaved, id_arg, m, n), m_complex (flag == mxCOMPLEX),
+
+      nzmax (nzmax_arg > 0 ? nzmax_arg : 1),
+      pr (mxArray::calloc (nzmax, get_element_size ())),
+      pi (m_interleaved
+          ? nullptr
+          : (m_complex
+             ? mxArray::calloc (nzmax, get_element_size ())
+             : nullptr)),
+      ir (static_cast<mwIndex *> (mxArray::calloc (nzmax, sizeof (mwIndex)))),
+      jc (static_cast<mwIndex *> (mxArray::calloc (n + 1, sizeof (mwIndex))))
+  { }
 
 private:
 
   mxArray_sparse (const mxArray_sparse& val)
     : mxArray_matlab (val), nzmax (val.nzmax),
       pr (mxArray::malloc (nzmax * get_element_size ())),
-      pi (val.pi ? mxArray::malloc (nzmax * get_element_size ()) : nullptr),
+      pi (m_interleaved
+          ? nullptr
+          : (val.pi
+             ? mxArray::malloc (nzmax * get_element_size ())
+             : nullptr)),
       ir (static_cast<mwIndex *> (mxArray::malloc (nzmax * sizeof (mwIndex)))),
       jc (static_cast<mwIndex *> (mxArray::malloc (nzmax * sizeof (mwIndex))))
   {
@@ -1536,7 +2146,10 @@
 
   mxArray_sparse& operator = (const mxArray_sparse&);
 
-  mxArray_base * dup (void) const { return new mxArray_sparse (*this); }
+  mxArray_base * dup (void) const
+  {
+    return new mxArray_sparse (*this);
+  }
 
   ~mxArray_sparse (void)
   {
@@ -1546,17 +2159,38 @@
     mxFree (jc);
   }
 
-  int is_complex (void) const { return pi != nullptr; }
+  int is_complex (void) const
+  {
+    return m_interleaved ? m_complex : (pi != nullptr);
+  }
 
   int is_sparse (void) const { return 1; }
 
   void * get_data (void) const { return pr; }
 
-  void * get_imag_data (void) const { return pi; }
+  void * get_imag_data (void) const
+  {
+    if (m_interleaved)
+      panic_impossible ();
+
+    return pi;
+  }
 
   void set_data (void *pr_arg) { pr = pr_arg; }
 
-  void set_imag_data (void *pi_arg) { pi = pi_arg; }
+  void set_imag_data (void *pi_arg)
+  {
+    if (m_interleaved)
+      panic_impossible ();
+
+    pi = pi_arg;
+  }
+
+  TYPED_GET_METHOD (mxDouble *, get_doubles)
+  TYPED_GET_METHOD (mxComplexDouble *, get_complex_doubles)
+
+  TYPED_SET_METHOD (mxDouble *, set_doubles)
+  TYPED_SET_METHOD (mxComplexDouble *, set_complex_doubles)
 
   mwIndex * get_ir (void) const { return ir; }
 
@@ -1584,24 +2218,45 @@
       {
       case mxDOUBLE_CLASS:
         {
-          if (pi)
+          if (is_complex ())
             {
-              double *ppr = static_cast<double *> (pr);
-              double *ppi = static_cast<double *> (pi);
-
-              SparseComplexMatrix val (get_m (), get_n (),
-                                       static_cast<octave_idx_type> (nzmax));
-
-              for (mwIndex i = 0; i < nzmax; i++)
+              if (m_interleaved)
                 {
-                  val.xdata (i) = Complex (ppr[i], ppi[i]);
-                  val.xridx (i) = ir[i];
+                  Complex *ppr = static_cast<Complex *> (pr);
+
+                  SparseComplexMatrix val (get_m (), get_n (),
+                                           static_cast<octave_idx_type> (nzmax));
+
+                  for (mwIndex i = 0; i < nzmax; i++)
+                    {
+                      val.xdata (i) = ppr[i];
+                      val.xridx (i) = ir[i];
+                    }
+
+                  for (mwIndex i = 0; i < get_n () + 1; i++)
+                    val.xcidx (i) = jc[i];
+
+                  retval = val;
                 }
-
-              for (mwIndex i = 0; i < get_n () + 1; i++)
-                val.xcidx (i) = jc[i];
-
-              retval = val;
+              else
+                {
+                  double *ppr = static_cast<double *> (pr);
+                  double *ppi = static_cast<double *> (pi);
+
+                  SparseComplexMatrix val (get_m (), get_n (),
+                                           static_cast<octave_idx_type> (nzmax));
+
+                  for (mwIndex i = 0; i < nzmax; i++)
+                    {
+                      val.xdata (i) = Complex (ppr[i], ppi[i]);
+                      val.xridx (i) = ir[i];
+                    }
+
+                  for (mwIndex i = 0; i < get_n () + 1; i++)
+                    val.xcidx (i) = jc[i];
+
+                  retval = val;
+                }
             }
           else
             {
@@ -1646,7 +2301,6 @@
 
       case mxSINGLE_CLASS:
         error ("single precision sparse data type not supported");
-        break;
 
       default:
         panic_impossible ();
@@ -1657,10 +2311,23 @@
 
 private:
 
+  // Flag to identify complex object if using interleaved data and PI is
+  // always nullptr.
+  bool m_complex;
+
+  // Maximun number of nonzero elements.
   mwSize nzmax;
 
+  // If using interleaved complex storage, this is the pointer to data
+  // (real, complex, or logical).  Otherwise, it is the pointer to the
+  // real part of the data.
   void *pr;
+
+  // If using non-interleaved complex storage, this is the pointer to
+  // the imaginary part of the data.  Othrwise is is always nullptr.
   void *pi;
+
+  // Sparse storage indexing arrays.
   mwIndex *ir;
   mwIndex *jc;
 };
@@ -1671,9 +2338,9 @@
 {
 public:
 
-  mxArray_struct (mwSize ndims_arg, const mwSize *dims_arg, int num_keys_arg,
-                  const char **keys)
-    : mxArray_matlab (mxSTRUCT_CLASS, ndims_arg, dims_arg),
+  mxArray_struct (bool interleaved, mwSize ndims_arg, const mwSize *dims_arg,
+                  int num_keys_arg, const char **keys)
+    : mxArray_matlab (interleaved, mxSTRUCT_CLASS, ndims_arg, dims_arg),
       nfields (num_keys_arg),
       fields (static_cast<char **> (mxArray::calloc (nfields,
                                                      sizeof (char *)))),
@@ -1684,8 +2351,9 @@
     init (keys);
   }
 
-  mxArray_struct (const dim_vector& dv, int num_keys_arg, const char **keys)
-    : mxArray_matlab (mxSTRUCT_CLASS, dv), nfields (num_keys_arg),
+  mxArray_struct (bool interleaved, const dim_vector& dv, int num_keys_arg,
+                  const char **keys)
+    : mxArray_matlab (interleaved, mxSTRUCT_CLASS, dv), nfields (num_keys_arg),
       fields (static_cast<char **> (mxArray::calloc (nfields,
                                                      sizeof (char *)))),
       data (static_cast<mxArray **> (mxArray::calloc (nfields *
@@ -1695,8 +2363,10 @@
     init (keys);
   }
 
-  mxArray_struct (mwSize m, mwSize n, int num_keys_arg, const char **keys)
-    : mxArray_matlab (mxSTRUCT_CLASS, m, n), nfields (num_keys_arg),
+  mxArray_struct (bool interleaved, mwSize m, mwSize n, int num_keys_arg,
+                  const char **keys)
+    : mxArray_matlab (interleaved, mxSTRUCT_CLASS, m, n),
+      nfields (num_keys_arg),
       fields (static_cast<char **> (mxArray::calloc (nfields,
                                                      sizeof (char *)))),
       data (static_cast<mxArray **> (mxArray::calloc (nfields *
@@ -1937,18 +2607,18 @@
 {
 public:
 
-  mxArray_cell (mwSize ndims_arg, const mwSize *dims_arg)
-    : mxArray_matlab (mxCELL_CLASS, ndims_arg, dims_arg),
+  mxArray_cell (bool interleaved, mwSize ndims_arg, const mwSize *dims_arg)
+    : mxArray_matlab (interleaved, mxCELL_CLASS, ndims_arg, dims_arg),
       data (static_cast<mxArray **> (mxArray::calloc (get_number_of_elements (),
                                      sizeof (mxArray *)))) { }
 
-  mxArray_cell (const dim_vector& dv)
-    : mxArray_matlab (mxCELL_CLASS, dv),
+  mxArray_cell (bool interleaved, const dim_vector& dv)
+    : mxArray_matlab (interleaved, mxCELL_CLASS, dv),
       data (static_cast<mxArray **> (mxArray::calloc (get_number_of_elements (),
                                      sizeof (mxArray *)))) { }
 
-  mxArray_cell (mwSize m, mwSize n)
-    : mxArray_matlab (mxCELL_CLASS, m, n),
+  mxArray_cell (bool interleaved, mwSize m, mwSize n)
+    : mxArray_matlab (interleaved, mxCELL_CLASS, m, n),
       data (static_cast<mxArray **> (mxArray::calloc (get_number_of_elements (),
                                      sizeof (mxArray *)))) { }
 
@@ -2021,54 +2691,76 @@
 
 // ------------------------------------------------------------------
 
-mxArray::mxArray (const octave_value& ov)
-  : rep (new mxArray_octave_value (ov)), name (nullptr) { }
-
-mxArray::mxArray (mxClassID id, mwSize ndims, const mwSize *dims,
-                  mxComplexity flag, bool init)
-  : rep (new mxArray_number (id, ndims, dims, flag, init)), name (nullptr) { }
-
-mxArray::mxArray (mxClassID id, const dim_vector& dv, mxComplexity flag)
-  : rep (new mxArray_number (id, dv, flag)), name (nullptr) { }
-
-mxArray::mxArray (mxClassID id, mwSize m, mwSize n,
+mxArray::mxArray (bool interleaved, const octave_value& ov)
+  : rep (create_rep (interleaved, ov)), name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, mxClassID id, mwSize ndims,
+                  const mwSize *dims, mxComplexity flag, bool init)
+  : rep (create_rep (interleaved, id, ndims, dims, flag, init)),
+    name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, mxClassID id, const dim_vector& dv,
+                  mxComplexity flag)
+  : rep (create_rep (interleaved, id, dv, flag)), name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, mxClassID id, mwSize m, mwSize n,
                   mxComplexity flag, bool init)
-  : rep (new mxArray_number (id, m, n, flag, init)), name (nullptr) { }
-
-mxArray::mxArray (mxClassID id, double val)
-  : rep (new mxArray_number (id, val)), name (nullptr) { }
-
-mxArray::mxArray (mxClassID id, mxLogical val)
-  : rep (new mxArray_number (id, val)), name (nullptr) { }
-
-mxArray::mxArray (const char *str)
-  : rep (new mxArray_number (str)), name (nullptr) { }
-
-mxArray::mxArray (mwSize m, const char **str)
-  : rep (new mxArray_number (m, str)), name (nullptr) { }
-
-mxArray::mxArray (mxClassID id, mwSize m, mwSize n, mwSize nzmax,
-                  mxComplexity flag)
-  : rep (new mxArray_sparse (id, m, n, nzmax, flag)), name (nullptr) { }
-
-mxArray::mxArray (mwSize ndims, const mwSize *dims, int num_keys,
+  : rep (create_rep (interleaved, id, m, n, flag, init)), name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, mxClassID id, double val)
+  : rep (create_rep (interleaved, id, val)), name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, mxClassID id, mxLogical val)
+  : rep (create_rep (interleaved, id, val)), name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, const char *str)
+  : rep (create_rep (interleaved, str)), name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, mwSize m, const char **str)
+  : rep (create_rep (interleaved, m, str)), name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, mxClassID id, mwSize m, mwSize n,
+                  mwSize nzmax, mxComplexity flag)
+  : rep (create_rep (interleaved, id, m, n, nzmax, flag)), name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, mwSize ndims, const mwSize *dims,
+                  int num_keys,
                   const char **keys)
-  : rep (new mxArray_struct (ndims, dims, num_keys, keys)), name (nullptr) { }
-
-mxArray::mxArray (const dim_vector& dv, int num_keys, const char **keys)
-  : rep (new mxArray_struct (dv, num_keys, keys)), name (nullptr) { }
-
-mxArray::mxArray (mwSize m, mwSize n, int num_keys, const char **keys)
-  : rep (new mxArray_struct (m, n, num_keys, keys)), name (nullptr) { }
-
-mxArray::mxArray (mwSize ndims, const mwSize *dims)
-  : rep (new mxArray_cell (ndims, dims)), name (nullptr) { }
-
-mxArray::mxArray (const dim_vector& dv)
-  : rep (new mxArray_cell (dv)), name (nullptr) { }
-
-mxArray::mxArray (mwSize m, mwSize n)
-  : rep (new mxArray_cell (m, n)), name (nullptr) { }
+  : rep (new mxArray_struct (interleaved, ndims, dims, num_keys, keys)),
+    name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, const dim_vector& dv, int num_keys,
+                  const char **keys)
+  : rep (new mxArray_struct (interleaved, dv, num_keys, keys)), name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, mwSize m, mwSize n, int num_keys,
+                  const char **keys)
+  : rep (new mxArray_struct (interleaved, m, n, num_keys, keys)),
+    name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, mwSize ndims, const mwSize *dims)
+  : rep (new mxArray_cell (interleaved, ndims, dims)), name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, const dim_vector& dv)
+  : rep (new mxArray_cell (interleaved, dv)), name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, mwSize m, mwSize n)
+  : rep (new mxArray_cell (interleaved, m, n)), name (nullptr)
+{ }
 
 mxArray::~mxArray (void)
 {
@@ -2100,6 +2792,64 @@
   return rep->as_octave_value ();
 }
 
+mxArray_base *
+mxArray::create_rep (bool interleaved, const octave_value& ov)
+{
+  return new mxArray_octave_value (interleaved, ov);
+}
+
+mxArray_base *
+mxArray::create_rep (bool interleaved, mxClassID id, mwSize ndims,
+                     const mwSize *dims, mxComplexity flag, bool init)
+{
+  return new mxArray_number (interleaved, id, ndims, dims, flag, init);
+}
+
+mxArray_base *
+mxArray::create_rep (bool interleaved, mxClassID id, const dim_vector& dv,
+                     mxComplexity flag)
+{
+  return new mxArray_number (interleaved, id, dv, flag);
+}
+
+mxArray_base *
+mxArray::create_rep (bool interleaved, mxClassID id, mwSize m, mwSize n,
+                     mxComplexity flag, bool init)
+{
+  return new mxArray_number (interleaved, id, m, n, flag, init);
+}
+
+mxArray_base *
+mxArray::create_rep (bool interleaved, mxClassID id, double val)
+{
+  return new mxArray_number (interleaved, id, val);
+}
+
+mxArray_base *
+mxArray::create_rep (bool interleaved, mxClassID id, mxLogical val)
+{
+  return new mxArray_number (interleaved, id, val);
+}
+
+mxArray_base *
+mxArray::create_rep (bool interleaved, const char *str)
+{
+  return new mxArray_number (interleaved, str);
+}
+
+mxArray_base *
+mxArray::create_rep (bool interleaved, mwSize m, const char **str)
+{
+  return new mxArray_number (interleaved, m, str);
+}
+
+mxArray_base *
+mxArray::create_rep (bool interleaved, mxClassID id, mwSize m, mwSize n,
+                     mwSize nzmax, mxComplexity flag)
+{
+  return new mxArray_sparse (interleaved, id, m, n, nzmax, flag);
+}
+
 void
 mxArray::maybe_mutate (void) const
 {
@@ -2130,7 +2880,7 @@
 {
 public:
 
-  mex (octave_mex_function *f)
+  mex (octave_mex_function& f)
     : curr_mex_fcn (f), memlist (), arraylist (), fname (nullptr) { }
 
   // No copying!
@@ -2363,7 +3113,9 @@
   // freed on exit unless marked as persistent.
   mxArray * make_value (const octave_value& ov)
   {
-    return mark_array (new mxArray (ov));
+    bool interleaved = curr_mex_fcn.use_interleaved_complex ();
+
+    return mark_array (new mxArray (interleaved, ov));
   }
 
   // Free an array and its contents.
@@ -2387,7 +3139,7 @@
     return inlist;
   }
 
-  octave_mex_function * current_mex_function (void) const
+  octave_mex_function& current_mex_function (void) const
   {
     return curr_mex_fcn;
   }
@@ -2398,7 +3150,7 @@
 private:
 
   // Pointer to the mex function that corresponds to this mex context.
-  octave_mex_function *curr_mex_fcn;
+  octave_mex_function& curr_mex_fcn;
 
   // List of memory resources that need to be freed upon exit.
   std::set<void *> memlist;
@@ -2438,7 +3190,6 @@
     else
       warning ("%s: value not marked", function_name ());
 #endif
-
   }
 };
 
@@ -2478,8 +3229,9 @@
   return ptr;
 }
 
-static inline void *
-maybe_unmark (void *ptr)
+template <typename T>
+static inline T *
+maybe_unmark (T *ptr)
 {
   if (mex_context)
     mex_context->unmark (ptr);
@@ -2580,116 +3332,235 @@
 
 // Constructors.
 mxArray *
+mxCreateCellArray_interleaved (mwSize ndims, const mwSize *dims)
+{
+  return maybe_mark_array (new mxArray (true, ndims, dims));
+}
+
+mxArray *
 mxCreateCellArray (mwSize ndims, const mwSize *dims)
 {
-  return maybe_mark_array (new mxArray (ndims, dims));
+  return maybe_mark_array (new mxArray (false, ndims, dims));
+}
+
+mxArray *
+mxCreateCellMatrix_interleaved (mwSize m, mwSize n)
+{
+  return maybe_mark_array (new mxArray (true, m, n));
 }
 
 mxArray *
 mxCreateCellMatrix (mwSize m, mwSize n)
 {
-  return maybe_mark_array (new mxArray (m, n));
+  return maybe_mark_array (new mxArray (false, m, n));
+}
+
+mxArray *
+mxCreateCharArray_interleaved (mwSize ndims, const mwSize *dims)
+{
+  return maybe_mark_array (new mxArray (true, mxCHAR_CLASS, ndims, dims));
 }
 
 mxArray *
 mxCreateCharArray (mwSize ndims, const mwSize *dims)
 {
-  return maybe_mark_array (new mxArray (mxCHAR_CLASS, ndims, dims));
+  return maybe_mark_array (new mxArray (false, mxCHAR_CLASS, ndims, dims));
+}
+
+mxArray *
+mxCreateCharMatrixFromStrings_interleaved (mwSize m, const char **str)
+{
+  return maybe_mark_array (new mxArray (true, m, str));
 }
 
 mxArray *
 mxCreateCharMatrixFromStrings (mwSize m, const char **str)
 {
-  return maybe_mark_array (new mxArray (m, str));
+  return maybe_mark_array (new mxArray (false, m, str));
+}
+
+mxArray *
+mxCreateDoubleMatrix_interleaved (mwSize m, mwSize n, mxComplexity flag)
+{
+  return maybe_mark_array (new mxArray (true, mxDOUBLE_CLASS, m, n, flag));
 }
 
 mxArray *
 mxCreateDoubleMatrix (mwSize m, mwSize n, mxComplexity flag)
 {
-  return maybe_mark_array (new mxArray (mxDOUBLE_CLASS, m, n, flag));
+  return maybe_mark_array (new mxArray (false, mxDOUBLE_CLASS, m, n, flag));
+}
+
+mxArray *
+mxCreateDoubleScalar_interleaved (double val)
+{
+  return maybe_mark_array (new mxArray (true, mxDOUBLE_CLASS, val));
 }
 
 mxArray *
 mxCreateDoubleScalar (double val)
 {
-  return maybe_mark_array (new mxArray (mxDOUBLE_CLASS, val));
+  return maybe_mark_array (new mxArray (false, mxDOUBLE_CLASS, val));
+}
+
+mxArray *
+mxCreateLogicalArray_interleaved (mwSize ndims, const mwSize *dims)
+{
+  return maybe_mark_array (new mxArray (true, mxLOGICAL_CLASS, ndims, dims));
 }
 
 mxArray *
 mxCreateLogicalArray (mwSize ndims, const mwSize *dims)
 {
-  return maybe_mark_array (new mxArray (mxLOGICAL_CLASS, ndims, dims));
+  return maybe_mark_array (new mxArray (false, mxLOGICAL_CLASS, ndims, dims));
+}
+
+mxArray *
+mxCreateLogicalMatrix_interleaved (mwSize m, mwSize n)
+{
+  return maybe_mark_array (new mxArray (true, mxLOGICAL_CLASS, m, n));
 }
 
 mxArray *
 mxCreateLogicalMatrix (mwSize m, mwSize n)
 {
-  return maybe_mark_array (new mxArray (mxLOGICAL_CLASS, m, n));
+  return maybe_mark_array (new mxArray (false, mxLOGICAL_CLASS, m, n));
+}
+
+mxArray *
+mxCreateLogicalScalar_interleaved (mxLogical val)
+{
+  return maybe_mark_array (new mxArray (true, mxLOGICAL_CLASS, val));
 }
 
 mxArray *
 mxCreateLogicalScalar (mxLogical val)
 {
-  return maybe_mark_array (new mxArray (mxLOGICAL_CLASS, val));
+  return maybe_mark_array (new mxArray (false, mxLOGICAL_CLASS, val));
+}
+
+mxArray *
+mxCreateNumericArray_interleaved (mwSize ndims, const mwSize *dims,
+                                  mxClassID class_id, mxComplexity flag)
+{
+  return maybe_mark_array (new mxArray (true, class_id, ndims, dims, flag));
 }
 
 mxArray *
-mxCreateNumericArray (mwSize ndims, const mwSize *dims, mxClassID class_id,
-                      mxComplexity flag)
-{
-  return maybe_mark_array (new mxArray (class_id, ndims, dims, flag));
+mxCreateNumericArray (mwSize ndims, const mwSize *dims,
+                               mxClassID class_id, mxComplexity flag)
+{
+  return maybe_mark_array (new mxArray (false, class_id, ndims, dims, flag));
+}
+
+mxArray *
+mxCreateNumericMatrix_interleaved (mwSize m, mwSize n, mxClassID class_id,
+                                   mxComplexity flag)
+{
+  return maybe_mark_array (new mxArray (true, class_id, m, n, flag));
 }
 
 mxArray *
 mxCreateNumericMatrix (mwSize m, mwSize n, mxClassID class_id,
-                       mxComplexity flag)
-{
-  return maybe_mark_array (new mxArray (class_id, m, n, flag));
+                                mxComplexity flag)
+{
+  return maybe_mark_array (new mxArray (false, class_id, m, n, flag));
+}
+
+mxArray *
+mxCreateUninitNumericArray_interleaved (mwSize ndims, const mwSize *dims,
+                                        mxClassID class_id, mxComplexity flag)
+{
+  return maybe_mark_array (new mxArray (true, class_id, ndims, dims, flag,
+                                        false));
 }
 
 mxArray *
 mxCreateUninitNumericArray (mwSize ndims, const mwSize *dims,
-                            mxClassID class_id, mxComplexity flag)
-{
-  return maybe_mark_array (new mxArray (class_id, ndims, dims, flag, false));
+                                     mxClassID class_id, mxComplexity flag)
+{
+  return maybe_mark_array (new mxArray (false, class_id, ndims, dims, flag,
+                                        false));
+}
+
+mxArray *
+mxCreateUninitNumericMatrix_interleaved (mwSize m, mwSize n,
+                                         mxClassID class_id, mxComplexity flag)
+{
+  return maybe_mark_array (new mxArray (true, class_id, m, n, flag, false));
 }
 
 mxArray *
 mxCreateUninitNumericMatrix (mwSize m, mwSize n, mxClassID class_id,
-                             mxComplexity flag)
-{
-  return maybe_mark_array (new mxArray (class_id, m, n, flag, false));
+                                      mxComplexity flag)
+{
+  return maybe_mark_array (new mxArray (false, class_id, m, n, flag, false));
+}
+
+mxArray *
+mxCreateSparse_interleaved (mwSize m, mwSize n, mwSize nzmax, mxComplexity flag)
+{
+  return maybe_mark_array (new mxArray (true, mxDOUBLE_CLASS, m, n, nzmax,
+                                        flag));
 }
 
 mxArray *
 mxCreateSparse (mwSize m, mwSize n, mwSize nzmax, mxComplexity flag)
 {
-  return maybe_mark_array (new mxArray (mxDOUBLE_CLASS, m, n, nzmax, flag));
+  return maybe_mark_array (new mxArray (false, mxDOUBLE_CLASS, m, n, nzmax,
+                                        flag));
+}
+
+mxArray *
+mxCreateSparseLogicalMatrix_interleaved (mwSize m, mwSize n, mwSize nzmax)
+{
+  return maybe_mark_array (new mxArray (true, mxLOGICAL_CLASS, m, n, nzmax));
 }
 
 mxArray *
 mxCreateSparseLogicalMatrix (mwSize m, mwSize n, mwSize nzmax)
 {
-  return maybe_mark_array (new mxArray (mxLOGICAL_CLASS, m, n, nzmax));
+  return maybe_mark_array (new mxArray (false, mxLOGICAL_CLASS, m, n, nzmax));
+}
+
+mxArray *
+mxCreateString_interleaved (const char *str)
+{
+  return maybe_mark_array (new mxArray (true, str));
 }
 
 mxArray *
 mxCreateString (const char *str)
 {
-  return maybe_mark_array (new mxArray (str));
+  return maybe_mark_array (new mxArray (false, str));
+}
+
+mxArray *
+mxCreateStructArray_interleaved (mwSize ndims, const mwSize *dims,
+                                 int num_keys, const char **keys)
+{
+  return maybe_mark_array (new mxArray (true, ndims, dims, num_keys, keys));
 }
 
 mxArray *
 mxCreateStructArray (mwSize ndims, const mwSize *dims, int num_keys,
-                     const char **keys)
-{
-  return maybe_mark_array (new mxArray (ndims, dims, num_keys, keys));
+                              const char **keys)
+{
+  return maybe_mark_array (new mxArray (false, ndims, dims, num_keys, keys));
 }
 
 mxArray *
-mxCreateStructMatrix (mwSize m, mwSize n, int num_keys, const char **keys)
-{
-  return maybe_mark_array (new mxArray (m, n, num_keys, keys));
+mxCreateStructMatrix_interleaved (mwSize m, mwSize n, int num_keys,
+                                  const char **keys)
+{
+  return maybe_mark_array (new mxArray (true, m, n, num_keys, keys));
+}
+
+mxArray *
+mxCreateStructMatrix (mwSize m, mwSize n, int num_keys,
+                               const char **keys)
+{
+  return maybe_mark_array (new mxArray (false, m, n, num_keys, keys));
 }
 
 // Copy constructor.
@@ -2918,12 +3789,6 @@
   return static_cast<double *> (ptr->get_data ());
 }
 
-double *
-mxGetPi (const mxArray *ptr)
-{
-  return static_cast<double *> (ptr->get_imag_data ());
-}
-
 double
 mxGetScalar (const mxArray *ptr)
 {
@@ -2951,12 +3816,121 @@
   return ptr->get_data ();
 }
 
+double *
+mxGetPi (const mxArray *ptr)
+{
+  return static_cast<double *> (ptr->get_imag_data ());
+}
+
 void *
 mxGetImagData (const mxArray *ptr)
 {
   return ptr->get_imag_data ();
 }
 
+mxDouble * mxGetDoubles (const mxArray *ptr)
+{
+  return ptr->get_doubles ();
+}
+
+mxSingle * mxGetSingles (const mxArray *ptr)
+{
+  return ptr->get_singles ();
+}
+
+mxInt8 * mxGetInt8s (const mxArray *ptr)
+{
+  return ptr->get_int8s ();
+}
+
+mxInt16 * mxGetInt16s (const mxArray *ptr)
+{
+  return ptr->get_int16s ();
+}
+
+mxInt32 * mxGetInt32s (const mxArray *ptr)
+{
+  return ptr->get_int32s ();
+}
+
+mxInt64 * mxGetInt64s (const mxArray *ptr)
+{
+  return ptr->get_int64s ();
+}
+
+mxUint8 * mxGetUint8s (const mxArray *ptr)
+{
+  return ptr->get_uint8s ();
+}
+
+mxUint16 * mxGetUint16s (const mxArray *ptr)
+{
+  return ptr->get_uint16s ();
+}
+
+mxUint32 * mxGetUint32s (const mxArray *ptr)
+{
+  return ptr->get_uint32s ();
+}
+
+mxUint64 * mxGetUint64s (const mxArray *ptr)
+{
+  return ptr->get_uint64s ();
+}
+
+mxComplexDouble * mxGetComplexDoubles (const mxArray *ptr)
+{
+  return ptr->get_complex_doubles ();
+}
+
+mxComplexSingle * mxGetComplexSingles (const mxArray *ptr)
+{
+  return ptr->get_complex_singles ();
+}
+
+#if 0
+/* We don't have these yet. */
+mxComplexInt8 * mxGetComplexInt8s (const mxArray *ptr)
+{
+  return ptr->get_complex_int8s ();
+}
+
+mxComplexInt16 * mxGetComplexInt16s (const mxArray *ptr)
+{
+  return ptr->get_complex_int16s ();
+}
+
+mxComplexInt32 * mxGetComplexInt32s (const mxArray *ptr)
+{
+  return ptr->get_complex_int32s ();
+}
+
+mxComplexInt64 * mxGetComplexInt64s (const mxArray *ptr)
+{
+  return ptr->get_complex_int64s ();
+}
+
+mxComplexUint8 * mxGetComplexUint8s (const mxArray *ptr)
+{
+  return ptr->get_complex_uint8s ();
+}
+
+mxComplexUint16 * mxGetComplexUint16s (const mxArray *ptr)
+{
+  return ptr->get_complex_uint16s ();
+}
+
+mxComplexUint32 * mxGetComplexUint32s (const mxArray *ptr)
+{
+  return ptr->get_complex_uint32s ();
+}
+
+mxComplexUint64 * mxGetComplexUint64s (const mxArray *ptr)
+{
+  return ptr->get_complex_uint64s ();
+}
+#endif
+
 // Data setters.
 void
 mxSetPr (mxArray *ptr, double *pr)
@@ -2965,18 +3939,121 @@
 }
 
 void
+mxSetData (mxArray *ptr, void *pr)
+{
+  ptr->set_data (maybe_unmark (pr));
+}
+
+int mxSetDoubles (mxArray *ptr, mxDouble *data)
+{
+  return ptr->set_doubles (maybe_unmark (data));
+}
+
+int mxSetSingles (mxArray *ptr, mxSingle *data)
+{
+  return ptr->set_singles (maybe_unmark (data));
+}
+
+int mxSetInt8s (mxArray *ptr, mxInt8 *data)
+{
+  return ptr->set_int8s (maybe_unmark (data));
+}
+
+int mxSetInt16s (mxArray *ptr, mxInt16 *data)
+{
+  return ptr->set_int16s (maybe_unmark (data));
+}
+
+int mxSetInt32s (mxArray *ptr, mxInt32 *data)
+{
+  return ptr->set_int32s (maybe_unmark (data));
+}
+
+int mxSetInt64s (mxArray *ptr, mxInt64 *data)
+{
+  return ptr->set_int64s (maybe_unmark (data));
+}
+
+int mxSetUint8s (mxArray *ptr, mxUint8 *data)
+{
+  return ptr->set_uint8s (maybe_unmark (data));
+}
+
+int mxSetUint16s (mxArray *ptr, mxUint16 *data)
+{
+  return ptr->set_uint16s (maybe_unmark (data));
+}
+
+int mxSetUint32s (mxArray *ptr, mxUint32 *data)
+{
+  return ptr->set_uint32s (maybe_unmark (data));
+}
+
+int mxSetUint64s (mxArray *ptr, mxUint64 *data)
+{
+  return ptr->set_uint64s (maybe_unmark (data));
+}
+
+int mxSetComplexDoubles (mxArray *ptr, mxComplexDouble *data)
+{
+  return ptr->set_complex_doubles (maybe_unmark (data));
+}
+
+int mxSetComplexSingles (mxArray *ptr, mxComplexSingle *data)
+{
+  return ptr->set_complex_singles (maybe_unmark (data));
+}
+
+#if 0
+/* We don't have these yet. */
+int mxSetComplexInt8s (mxArray *ptr, mxComplexInt8 *data)
+{
+  return ptr->set_complex_int8s (maybe_unmark (data));
+}
+
+int mxSetComplexInt16s (mxArray *ptr, mxComplexInt16 *data)
+{
+  return ptr->set_complex_int16s (maybe_unmark (data));
+}
+
+int mxSetComplexInt32s (mxArray *ptr, mxComplexInt32 *data)
+{
+  return ptr->set_complex_int32s (maybe_unmark (data));
+}
+
+int mxSetComplexInt64s (mxArray *ptr, mxComplexInt64 *data)
+{
+  return ptr->set_complex_int64s (maybe_unmark (data));
+}
+
+int mxSetComplexUint8s (mxArray *ptr, mxComplexUint8 *data)
+{
+  return ptr->set_complex_uint8s (maybe_unmark (data));
+}
+
+int mxSetComplexUint16s (mxArray *ptr, mxComplexUint16 *data)
+{
+  return ptr->set_complex_uint16s (maybe_unmark (data));
+}
+
+int mxSetComplexUint32s (mxArray *ptr, mxComplexUint32 *data)
+{
+  return ptr->set_complex_uint32s (maybe_unmark (data));
+}
+
+int mxSetComplexUint64s (mxArray *ptr, mxComplexUint64 *data)
+{
+  return ptr->set_complex_uint64s (maybe_unmark (data));
+}
+#endif
+
+void
 mxSetPi (mxArray *ptr, double *pi)
 {
   ptr->set_imag_data (maybe_unmark (pi));
 }
 
 void
-mxSetData (mxArray *ptr, void *pr)
-{
-  ptr->set_data (maybe_unmark (pr));
-}
-
-void
 mxSetImagData (mxArray *ptr, void *pi)
 {
   ptr->set_imag_data (maybe_unmark (pi));
@@ -3172,12 +4249,10 @@
   for (int i = 0; i < nout; i++)
     argout[i] = nullptr;
 
-  octave::unwind_protect_safe frame;
-
   // Save old mex pointer.
-  frame.protect_var (mex_context);
-
-  mex context (&mex_fcn);
+  octave::unwind_protect_var<mex *> restore_var (mex_context);
+
+  mex context (mex_fcn);
 
   for (int i = 0; i < nargin; i++)
     argin[i] = context.make_value (args(i));
@@ -3619,17 +4694,28 @@
 {
   if (mex_context)
     {
-      octave_mex_function *curr_mex_fcn = mex_context->current_mex_function ();
-
-      assert (curr_mex_fcn);
-
-      curr_mex_fcn->atexit (f);
+      octave_mex_function& curr_mex_fcn = mex_context->current_mex_function ();
+
+      curr_mex_fcn.atexit (f);
     }
 
   return 0;
 }
 
 const mxArray *
+mexGet_interleaved (double handle, const char *property)
+{
+  mxArray *m = nullptr;
+
+  octave_value ret = get_property_from_handle (handle, property, "mexGet");
+
+  if (ret.is_defined ())
+    m = ret.as_mxArray (true);
+
+  return m;
+}
+
+const mxArray *
 mexGet (double handle, const char *property)
 {
   mxArray *m = nullptr;
@@ -3637,7 +4723,7 @@
   octave_value ret = get_property_from_handle (handle, property, "mexGet");
 
   if (ret.is_defined ())
-    m = ret.as_mxArray ();
+    m = ret.as_mxArray (false);
 
   return m;
 }
--- a/libinterp/corefcn/mexproto.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/mexproto.h	Thu Nov 19 13:08:00 2020 -0800
@@ -61,10 +61,19 @@
 #  include <stdbool.h>
 #endif
 
+#if ! defined (MX_HAS_INTERLEAVED_COMPLEX)
+#  define MX_HAS_INTERLEAVED_COMPLEX 0
+#endif
+
 #define MXARRAY_TYPEDEFS_ONLY
 #include "mxarray.h"
 #undef MXARRAY_TYPEDEFS_ONLY
 
+/* Prototype for the gateway function.  */
+
+extern void mexFunction (int nlhs, mxArray *plhs[],
+                         int nrhs, const mxArray *prhs[]);
+
 /* Interface to the interpreter.  */
 extern OCTINTERP_API const char * mexFunctionName (void);
 
@@ -98,8 +107,12 @@
 extern OCTINTERP_API int mexPutVariable (const char *space, const char *name,
                                          const mxArray *ptr);
 
+#if MX_HAS_INTERLEAVED_COMPLEX
+#  define mexGet mexGet_interleaved
+#endif
 extern OCTINTERP_API const mxArray * mexGet (double handle,
                                              const char *property);
+
 extern OCTINTERP_API int mexSet (double handle, const char *property,
                                  mxArray *val);
 
@@ -131,6 +144,27 @@
 extern OCTINTERP_API void mxFree (void *ptr);
 
 /* Constructors.  */
+#if MX_HAS_INTERLEAVED_COMPLEX
+#  define mxCreateCellArray mxCreateCellArray_interleaved
+#  define mxCreateCellMatrix mxCreateCellMatrix_interleaved
+#  define mxCreateCharArray mxCreateCharArray_interleaved
+#  define mxCreateCharMatrixFromStrings mxCreateCharMatrixFromStrings_interleaved
+#  define mxCreateDoubleMatrix mxCreateDoubleMatrix_interleaved
+#  define mxCreateDoubleScalar mxCreateDoubleScalar_interleaved
+#  define mxCreateLogicalArray mxCreateLogicalArray_interleaved
+#  define mxCreateLogicalMatrix mxCreateLogicalMatrix_interleaved
+#  define mxCreateLogicalScalar mxCreateLogicalScalar_interleaved
+#  define mxCreateNumericArray mxCreateNumericArray_interleaved
+#  define mxCreateNumericMatrix mxCreateNumericMatrix_interleaved
+#  define mxCreateUninitNumericArray mxCreateUninitNumericArray_interleaved
+#  define mxCreateUninitNumericMatrix mxCreateUninitNumericMatrix_interleaved
+#  define mxCreateSparse mxCreateSparse_interleaved
+#  define mxCreateSparseLogicalMatrix mxCreateSparseLogicalMatrix_interleaved
+#  define mxCreateString mxCreateString_interleaved
+#  define mxCreateStructArray mxCreateStructArray_interleaved
+#  define mxCreateStructMatrix mxCreateStructMatrix_interleaved
+#endif
+
 extern OCTINTERP_API mxArray * mxCreateCellArray (mwSize ndims,
                                                   const mwSize *dims);
 extern OCTINTERP_API mxArray * mxCreateCellMatrix (mwSize m, mwSize n);
@@ -227,20 +261,79 @@
 extern OCTINTERP_API int mxSetDimensions (mxArray *ptr, const mwSize *dims,
                                           mwSize ndims);
 
+#if MX_HAS_INTERLEAVED_COMPLEX
+extern OCTINTERP_API int mxMakeArrayReal (mxArray *ptr);
+extern OCTINTERP_API int mxMakeArrayComplex (mxArray *ptr);
+#endif
+
 /* Data extractors.  */
-extern OCTINTERP_API double * mxGetPi (const mxArray *ptr);
 extern OCTINTERP_API double * mxGetPr (const mxArray *ptr);
 extern OCTINTERP_API double mxGetScalar (const mxArray *ptr);
 extern OCTINTERP_API mxChar * mxGetChars (const mxArray *ptr);
 extern OCTINTERP_API mxLogical * mxGetLogicals (const mxArray *ptr);
 extern OCTINTERP_API void * mxGetData (const mxArray *ptr);
+#if MX_HAS_INTERLEAVED_COMPLEX
+extern OCTINTERP_API mxDouble * mxGetDoubles (const mxArray *p);
+extern OCTINTERP_API mxSingle * mxGetSingles (const mxArray *p);
+extern OCTINTERP_API mxInt8 * mxGetInt8s (const mxArray *p);
+extern OCTINTERP_API mxInt16 * mxGetInt16s (const mxArray *p);
+extern OCTINTERP_API mxInt32 * mxGetInt32s (const mxArray *p);
+extern OCTINTERP_API mxInt64 * mxGetInt64s (const mxArray *p);
+extern OCTINTERP_API mxUint8 * mxGetUint8s (const mxArray *p);
+extern OCTINTERP_API mxUint16 * mxGetUint16s (const mxArray *p);
+extern OCTINTERP_API mxUint32 * mxGetUint32s (const mxArray *p);
+extern OCTINTERP_API mxUint64 * mxGetUint64s (const mxArray *p);
+
+extern OCTINTERP_API mxComplexDouble * mxGetComplexDoubles (const mxArray *p);
+extern OCTINTERP_API mxComplexSingle * mxGetComplexSingles (const mxArray *p);
+#if 0
+/* We don't have these yet. */
+extern OCTINTERP_API mxComplexInt8 * mxGetComplexInt8s (const mxArray *p);
+extern OCTINTERP_API mxComplexInt16 * mxGetComplexInt16s (const mxArray *p);
+extern OCTINTERP_API mxComplexInt32 * mxGetComplexInt32s (const mxArray *p);
+extern OCTINTERP_API mxComplexInt64 * mxGetComplexInt64s (const mxArray *p);
+extern OCTINTERP_API mxComplexUint8 * mxGetComplexUint8s (const mxArray *p);
+extern OCTINTERP_API mxComplexUint16 * mxGetComplexUint16s (const mxArray *p);
+extern OCTINTERP_API mxComplexUint32 * mxGetComplexUint32s (const mxArray *p);
+extern OCTINTERP_API mxComplexUint64 * mxGetComplexUint64s (const mxArray *p);
+#endif
+#else
+extern OCTINTERP_API double * mxGetPi (const mxArray *ptr);
 extern OCTINTERP_API void * mxGetImagData (const mxArray *ptr);
+#endif
 
 /* Data setters.  */
 extern OCTINTERP_API void mxSetPr (mxArray *ptr, double *pr);
+extern OCTINTERP_API void mxSetData (mxArray *ptr, void *data);
+#if MX_HAS_INTERLEAVED_COMPLEX
+extern OCTINTERP_API int mxSetDoubles (mxArray *p, mxDouble *d);
+extern OCTINTERP_API int mxSetSingles (mxArray *p, mxSingle *d);
+extern OCTINTERP_API int mxSetInt8s (mxArray *p, mxInt8 *d);
+extern OCTINTERP_API int mxSetInt16s (mxArray *p, mxInt16 *d);
+extern OCTINTERP_API int mxSetInt32s (mxArray *p, mxInt32 *d);
+extern OCTINTERP_API int mxSetInt64s (mxArray *p, mxInt64 *d);
+extern OCTINTERP_API int mxSetUint8s (mxArray *p, mxUint8 *d);
+extern OCTINTERP_API int mxSetUint16s (mxArray *p, mxUint16 *d);
+extern OCTINTERP_API int mxSetUint32s (mxArray *p, mxUint32 *d);
+extern OCTINTERP_API int mxSetUint64s (mxArray *p, mxUint64 *d);
+
+extern OCTINTERP_API int mxSetComplexDoubles (mxArray *p, mxComplexDouble *d);
+extern OCTINTERP_API int mxSetComplexSingles (mxArray *p, mxComplexSingle *d);
+#if 0
+/* We don't have these yet. */
+extern OCTINTERP_API int mxSetComplexInt8s (mxArray *p, mxComplexInt8 *d);
+extern OCTINTERP_API int mxSetComplexInt16s (mxArray *p, mxComplexInt16 *d);
+extern OCTINTERP_API int mxSetComplexInt32s (mxArray *p, mxComplexInt32 *d);
+extern OCTINTERP_API int mxSetComplexInt64s (mxArray *p, mxComplexInt64 *d);
+extern OCTINTERP_API int mxSetComplexUint8s (mxArray *p, mxComplexUint8 *d);
+extern OCTINTERP_API int mxSetComplexUint16s (mxArray *p, mxComplexUint16 *d);
+extern OCTINTERP_API int mxSetComplexUint32s (mxArray *p, mxComplexUint32 *d);
+extern OCTINTERP_API int mxSetComplexUint64s (mxArray *p, mxComplexUint64 *d);
+#endif
+#else
 extern OCTINTERP_API void mxSetPi (mxArray *ptr, double *pi);
-extern OCTINTERP_API void mxSetData (mxArray *ptr, void *data);
 extern OCTINTERP_API void mxSetImagData (mxArray *ptr, void *pi);
+#endif
 
 /* Classes.  */
 extern OCTINTERP_API mxClassID mxGetClassID (const mxArray *ptr);
--- a/libinterp/corefcn/mk-mxarray-h.in.sh	Thu Nov 19 13:05:51 2020 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-#! /bin/sh
-#
-########################################################################
-#
-# Copyright (C) 2016-2020 The Octave Project Developers
-#
-# See the file COPYRIGHT.md in the top-level directory of this
-# distribution or <https://octave.org/copyright/>.
-#
-# This file is part of Octave.
-#
-# Octave is free software: you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Octave is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Octave; see the file COPYING.  If not, see
-# <https://www.gnu.org/licenses/>.
-#
-########################################################################
-
-: ${SED=@SED@}
-
-OCTAVE_IDX_TYPE="@OCTAVE_IDX_TYPE@"
-
-$SED \
-  -e "s|%NO_EDIT_WARNING%|DO NOT EDIT!  Generated automatically by mx-mxarray-h.|" \
-  -e "s|%OCTAVE_IDX_TYPE%|${OCTAVE_IDX_TYPE}|"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/mk-mxtypes-h.in.sh	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,34 @@
+#! /bin/sh
+#
+########################################################################
+#
+# Copyright (C) 2016-2020 The Octave Project Developers
+#
+# See the file COPYRIGHT.md in the top-level directory of this
+# distribution or <https://octave.org/copyright/>.
+#
+# This file is part of Octave.
+#
+# Octave is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Octave is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Octave; see the file COPYING.  If not, see
+# <https://www.gnu.org/licenses/>.
+#
+########################################################################
+
+: ${SED=@SED@}
+
+OCTAVE_IDX_TYPE="@OCTAVE_IDX_TYPE@"
+
+$SED \
+  -e "s|%NO_EDIT_WARNING%|DO NOT EDIT!  Generated automatically by mx-mxtypes-h.sh|" \
+  -e "s|%OCTAVE_IDX_TYPE%|${OCTAVE_IDX_TYPE}|"
--- a/libinterp/corefcn/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -58,6 +58,8 @@
   %reldir%/ls-utils.h \
   %reldir%/mex.h \
   %reldir%/mexproto.h \
+  %reldir%/mx-type-traits.h \
+  %reldir%/mxarray.h \
   %reldir%/oct-errno.h \
   %reldir%/oct-fstrm.h \
   %reldir%/oct-handle.h \
@@ -89,7 +91,6 @@
   %reldir%/sysdep.h \
   %reldir%/text-engine.h \
   %reldir%/text-renderer.h \
-  %reldir%/txt-eng.h \
   %reldir%/url-handle-manager.h \
   %reldir%/utils.h \
   %reldir%/variables.h \
@@ -185,6 +186,8 @@
   %reldir%/interpreter-private.cc \
   %reldir%/interpreter.cc \
   %reldir%/inv.cc \
+  %reldir%/jsondecode.cc \
+  %reldir%/jsonencode.cc \
   %reldir%/kron.cc \
   %reldir%/load-path.cc \
   %reldir%/load-save.cc \
@@ -218,6 +221,7 @@
   %reldir%/oct-tex-lexer.ll \
   %reldir%/oct-tex-parser.h \
   %reldir%/oct-tex-parser.yy \
+  %reldir%/ordqz.cc \
   %reldir%/ordschur.cc \
   %reldir%/pager.cc \
   %reldir%/pinv.cc \
@@ -298,8 +302,8 @@
 	fi && \
 	mv $@-t $@
 
-%reldir%/mxarray.h: %reldir%/mxarray.in.h %reldir%/mk-mxarray-h.sh | %reldir%/$(octave_dirstamp)
-	$(AM_V_GEN)$(call simple-filter-rule,%reldir%/mk-mxarray-h.sh)
+%reldir%/mxtypes.h: %reldir%/mxtypes.in.h %reldir%/mk-mxtypes-h.sh | %reldir%/$(octave_dirstamp)
+	$(AM_V_GEN)$(call simple-filter-rule,%reldir%/mk-mxtypes-h.sh)
 
 %reldir%/oct-tex-lexer.ll: %reldir%/oct-tex-lexer.in.ll %reldir%/oct-tex-symbols.in | %reldir%/$(octave_dirstamp)
 	$(AM_V_GEN)rm -f $@-t && \
@@ -332,11 +336,11 @@
   %reldir%/genprops.awk \
   %reldir%/graphics.in.h \
   %reldir%/mk-errno-list.sh \
-  %reldir%/mk-mxarray-h.in.sh \
-  %reldir%/mxarray.in.h \
+  %reldir%/mk-mxtypes-h.in.sh \
+  %reldir%/mxtypes.in.h \
   %reldir%/oct-errno.in.cc \
   %reldir%/oct-tex-lexer.in.ll \
   %reldir%/oct-tex-symbols.in
 
 GEN_CONFIG_SHELL += \
-  %reldir%/mk-mxarray-h.sh
+  %reldir%/mk-mxtypes-h.sh
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/mx-type-traits.h	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,151 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if ! defined (octave_mx_type_traits_h)
+#define octave_mx_type_traits_h 1
+
+#include "octave-config.h"
+
+#include "mxtypes.h"
+#include "oct-inttypes.h"
+
+template <typename T>
+class
+mx_type_traits
+{
+public:
+  static const mxClassID mx_class;
+  typedef T mx_type;
+};
+
+template <>
+class
+mx_type_traits<bool>
+{
+public:
+  static const mxClassID mx_class = mxLOGICAL_CLASS;
+  typedef mxDouble mx_type;
+};
+
+template <>
+class
+mx_type_traits<char>
+{
+public:
+  static const mxClassID mx_class = mxCHAR_CLASS;
+  typedef mxChar mx_type;
+};
+
+template <>
+class
+mx_type_traits<double>
+{
+public:
+  static const mxClassID mx_class = mxDOUBLE_CLASS;
+  typedef mxDouble mx_type;
+};
+
+template <>
+class
+mx_type_traits<float>
+{
+public:
+  static const mxClassID mx_class = mxSINGLE_CLASS;
+  typedef mxSingle mx_type;
+};
+
+template <>
+class
+mx_type_traits<octave_int8>
+{
+public:
+  static const mxClassID mx_class = mxINT8_CLASS;
+  typedef mxInt8 mx_type;
+};
+
+template <>
+class
+mx_type_traits<octave_uint8>
+{
+public:
+  static const mxClassID mx_class = mxUINT8_CLASS;
+  typedef mxUint8 mx_type;
+};
+
+template <>
+class
+mx_type_traits<octave_int16>
+{
+public:
+  static const mxClassID mx_class = mxINT16_CLASS;
+  typedef mxInt16 mx_type;
+};
+
+template <>
+class
+mx_type_traits<octave_uint16>
+{
+public:
+  static const mxClassID mx_class = mxUINT16_CLASS;
+  typedef mxUint16 mx_type;
+};
+
+template <>
+class
+mx_type_traits<octave_int32>
+{
+public:
+  static const mxClassID mx_class = mxINT32_CLASS;
+  typedef mxInt32 mx_type;
+};
+
+template <>
+class
+mx_type_traits<octave_uint32>
+{
+public:
+  static const mxClassID mx_class = mxUINT32_CLASS;
+  typedef mxUint32 mx_type;
+};
+
+template <>
+class
+mx_type_traits<octave_int64>
+{
+public:
+  static const mxClassID mx_class = mxINT64_CLASS;
+  typedef mxInt64 mx_type;
+};
+
+template <>
+class
+mx_type_traits<octave_uint64>
+{
+public:
+  static const mxClassID mx_class = mxUINT64_CLASS;
+  typedef mxUint64 mx_type;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/mxarray.h	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,746 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001-2020 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+/*
+
+Part of this code was originally distributed as part of Octave Forge under
+the following terms:
+
+Author: Paul Kienzle
+I grant this code to the public domain.
+2001-03-22
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+*/
+
+#if ! defined (octave_mxarray_h)
+#define octave_mxarray_h 1
+
+#include "octave-config.h"
+
+#include "mxtypes.h"
+
+#if ! defined (MXARRAY_TYPEDEFS_ONLY)
+
+#include <cstring>
+#include "error.h"
+
+class octave_value;
+class dim_vector;
+
+#define DO_MUTABLE_METHOD(RET_T, METHOD_CALL)   \
+  RET_T retval = rep->METHOD_CALL;              \
+                                                \
+  if (rep->mutation_needed ())                  \
+    {                                           \
+      maybe_mutate ();                          \
+      retval = rep->METHOD_CALL;                \
+    }                                           \
+                                                \
+  return retval
+
+#define DO_VOID_MUTABLE_METHOD(METHOD_CALL)     \
+  rep->METHOD_CALL;                             \
+                                                \
+  if (rep->mutation_needed ())                  \
+    {                                           \
+      maybe_mutate ();                          \
+      rep->METHOD_CALL;                         \
+    }
+
+class mxArray;
+
+// A class to provide the default implementation of some of the
+// virtual functions declared in the mxArray class.
+
+class mxArray_base
+{
+protected:
+
+  mxArray_base (bool interleaved);
+
+public:
+
+  virtual mxArray_base * dup (void) const = 0;
+
+  virtual mxArray * as_mxArray (void) const { return nullptr; }
+
+  virtual ~mxArray_base (void) = default;
+
+  virtual bool is_octave_value (void) const { return false; }
+
+  virtual int iscell (void) const = 0;
+
+  virtual int is_char (void) const = 0;
+
+  virtual int is_class (const char *name_arg) const
+  {
+    int retval = 0;
+
+    const char *cname = get_class_name ();
+
+    if (cname && name_arg)
+      retval = ! strcmp (cname, name_arg);
+
+    return retval;
+  }
+
+  virtual int is_complex (void) const = 0;
+
+  virtual int is_double (void) const = 0;
+
+  virtual int is_function_handle (void) const = 0;
+
+  virtual int is_int16 (void) const = 0;
+
+  virtual int is_int32 (void) const = 0;
+
+  virtual int is_int64 (void) const = 0;
+
+  virtual int is_int8 (void) const = 0;
+
+  virtual int is_logical (void) const = 0;
+
+  virtual int is_numeric (void) const = 0;
+
+  virtual int is_single (void) const = 0;
+
+  virtual int is_sparse (void) const = 0;
+
+  virtual int is_struct (void) const = 0;
+
+  virtual int is_uint16 (void) const = 0;
+
+  virtual int is_uint32 (void) const = 0;
+
+  virtual int is_uint64 (void) const = 0;
+
+  virtual int is_uint8 (void) const = 0;
+
+  virtual int is_logical_scalar (void) const
+  {
+    return is_logical () && get_number_of_elements () == 1;
+  }
+
+  virtual int is_logical_scalar_true (void) const = 0;
+
+  virtual mwSize get_m (void) const = 0;
+
+  virtual mwSize get_n (void) const = 0;
+
+  virtual mwSize * get_dimensions (void) const = 0;
+
+  virtual mwSize get_number_of_dimensions (void) const = 0;
+
+  virtual void set_m (mwSize m) = 0;
+
+  virtual void set_n (mwSize n) = 0;
+
+  virtual int set_dimensions (mwSize *dims_arg, mwSize ndims_arg) = 0;
+
+  virtual mwSize get_number_of_elements (void) const = 0;
+
+  virtual int isempty (void) const = 0;
+
+  virtual bool is_scalar (void) const = 0;
+
+  virtual mxClassID get_class_id (void) const = 0;
+
+  virtual const char * get_class_name (void) const = 0;
+
+  virtual void set_class_name (const char *name_arg) = 0;
+
+  // The following functions aren't pure virtual because they are only
+  // valid for one type.  Making them pure virtual would mean that they
+  // have to be implemented for all derived types, and all of those
+  // would need to throw errors instead of just doing it once here.
+
+  virtual mxArray *
+  get_property (mwIndex /*idx*/, const char * /*pname*/) const
+  {
+    return nullptr;
+  }
+
+  virtual void set_property (mwIndex /*idx*/, const char * /*pname*/,
+                             const mxArray * /*pval*/)
+  {
+    err_invalid_type ("set_property");
+  }
+
+  virtual mxArray * get_cell (mwIndex /*idx*/) const
+  {
+    err_invalid_type ("get_cell");
+  }
+
+  virtual void set_cell (mwIndex idx, mxArray *val) = 0;
+
+  virtual double get_scalar (void) const = 0;
+
+  virtual void * get_data (void) const = 0;
+
+  virtual mxDouble * get_doubles (void) const = 0;
+  virtual mxSingle * get_singles (void) const = 0;
+  virtual mxInt8 * get_int8s (void) const = 0;
+  virtual mxInt16 * get_int16s (void) const = 0;
+  virtual mxInt32 * get_int32s (void) const = 0;
+  virtual mxInt64 * get_int64s (void) const = 0;
+  virtual mxUint8 * get_uint8s (void) const = 0;
+  virtual mxUint16 * get_uint16s (void) const = 0;
+  virtual mxUint32 * get_uint32s (void) const = 0;
+  virtual mxUint64 * get_uint64s (void) const = 0;
+
+  virtual mxComplexDouble * get_complex_doubles (void) const = 0;
+  virtual mxComplexSingle * get_complex_singles (void) const = 0;
+#if 0
+  /* We don't have these yet. */
+  virtual mxComplexInt8 * get_complex_int8s (void) const = 0;
+  virtual mxComplexInt16 * get_complex_int16s (void) const = 0;
+  virtual mxComplexInt32 * get_complex_int32s (void) const = 0;
+  virtual mxComplexInt64 * get_complex_int64s (void) const = 0;
+  virtual mxComplexUint8 * get_complex_uint8s (void) const = 0;
+  virtual mxComplexUint16 * get_complex_uint16s (void) const = 0;
+  virtual mxComplexUint32 * get_complex_uint32s (void) const = 0;
+  virtual mxComplexUint64 * get_complex_uint64s (void) const = 0;
+#endif
+
+  virtual void * get_imag_data (void) const = 0;
+
+  virtual void set_data (void *pr) = 0;
+
+  virtual int set_doubles (mxDouble *data) = 0;
+  virtual int set_singles (mxSingle *data) = 0;
+  virtual int set_int8s (mxInt8 *data) = 0;
+  virtual int set_int16s (mxInt16 *data) = 0;
+  virtual int set_int32s (mxInt32 *data) = 0;
+  virtual int set_int64s (mxInt64 *data) = 0;
+  virtual int set_uint8s (mxUint8 *data) = 0;
+  virtual int set_uint16s (mxUint16 *data) = 0;
+  virtual int set_uint32s (mxUint32 *data) = 0;
+  virtual int set_uint64s (mxUint64 *data) = 0;
+
+  virtual int set_complex_doubles (mxComplexDouble *data) = 0;
+  virtual int set_complex_singles (mxComplexSingle *data) = 0;
+#if 0
+  /* We don't have these yet. */
+  virtual int set_complex_int8s (mxComplexInt8 *data) = 0;
+  virtual int set_complex_int16s (mxComplexInt16 *data) = 0;
+  virtual int set_complex_int32s (mxComplexInt32 *data) = 0;
+  virtual int set_complex_int64s (mxComplexInt64 *data) = 0;
+  virtual int set_complex_uint8s (mxComplexUint8 *data) = 0;
+  virtual int set_complex_uint16s (mxComplexUint16 *data) = 0;
+  virtual int set_complex_uint32s (mxComplexUint32 *data) = 0;
+  virtual int set_complex_uint64s (mxComplexUint64 *data) = 0;
+#endif
+
+  virtual void set_imag_data (void *pi) = 0;
+
+  virtual mwIndex * get_ir (void) const = 0;
+
+  virtual mwIndex * get_jc (void) const = 0;
+
+  virtual mwSize get_nzmax (void) const = 0;
+
+  virtual void set_ir (mwIndex *ir) = 0;
+
+  virtual void set_jc (mwIndex *jc) = 0;
+
+  virtual void set_nzmax (mwSize nzmax) = 0;
+
+  virtual int add_field (const char *key) = 0;
+
+  virtual void remove_field (int key_num) = 0;
+
+  virtual mxArray * get_field_by_number (mwIndex index, int key_num) const = 0;
+
+  virtual void
+  set_field_by_number (mwIndex index, int key_num, mxArray *val) = 0;
+
+  virtual int get_number_of_fields (void) const = 0;
+
+  virtual const char * get_field_name_by_number (int key_num) const = 0;
+
+  virtual int get_field_number (const char *key) const = 0;
+
+  virtual int get_string (char *buf, mwSize buflen) const = 0;
+
+  virtual char * array_to_string (void) const = 0;
+
+  virtual mwIndex calc_single_subscript (mwSize nsubs, mwIndex *subs) const = 0;
+
+  virtual size_t get_element_size (void) const = 0;
+
+  virtual bool mutation_needed (void) const { return false; }
+
+  virtual mxArray * mutate (void) const { return nullptr; }
+
+  virtual octave_value as_octave_value (void) const = 0;
+
+protected:
+
+  // If TRUE, we are using interleaved storage for complex numeric arrays.
+  bool m_interleaved;
+
+  mxArray_base (const mxArray_base&) = default;
+
+  size_t get_numeric_element_size (size_t size) const
+  {
+    return (m_interleaved
+            ? is_complex () ? 2 * size : size
+            : size);
+  }
+
+  OCTAVE_NORETURN void err_invalid_type (const char *op) const
+  {
+    error ("%s: invalid type for mxArray::%s", get_class_name (), op);
+  }
+};
+
+// The main interface class.  The representation can be based on an
+// octave_value object or a separate object that tries to reproduce
+// the semantics of mxArray objects in Matlab more directly.
+
+class mxArray
+{
+public:
+
+  mxArray (bool interleaved, const octave_value& ov);
+
+  mxArray (bool interleaved, mxClassID id, mwSize ndims, const mwSize *dims,
+           mxComplexity flag = mxREAL, bool init = true);
+
+  mxArray (bool interleaved, mxClassID id, const dim_vector& dv,
+           mxComplexity flag = mxREAL);
+
+  mxArray (bool interleaved, mxClassID id, mwSize m, mwSize n,
+           mxComplexity flag = mxREAL, bool init = true);
+
+  mxArray (bool interleaved, mxClassID id, double val);
+
+  mxArray (bool interleaved, mxClassID id, mxLogical val);
+
+  mxArray (bool interleaved, const char *str);
+
+  mxArray (bool interleaved, mwSize m, const char **str);
+
+  mxArray (bool interleaved, mxClassID id, mwSize m, mwSize n, mwSize nzmax,
+           mxComplexity flag = mxREAL);
+
+  mxArray (bool interleaved, mwSize ndims, const mwSize *dims, int num_keys,
+           const char **keys);
+
+  mxArray (bool interleaved, const dim_vector& dv, int num_keys,
+           const char **keys);
+
+  mxArray (bool interleaved, mwSize m, mwSize n, int num_keys,
+           const char **keys);
+
+  mxArray (bool interleaved, mwSize ndims, const mwSize *dims);
+
+  mxArray (bool interleaved, const dim_vector& dv);
+
+  mxArray (bool interleaved, mwSize m, mwSize n);
+
+  mxArray * dup (void) const
+  {
+    mxArray *retval = rep->as_mxArray ();
+
+    if (retval)
+      retval->set_name (name);
+    else
+      {
+        mxArray_base *new_rep = rep->dup ();
+
+        retval = new mxArray (new_rep, name);
+      }
+
+    return retval;
+  }
+
+  // No copying!
+
+  mxArray (const mxArray&) = delete;
+
+  mxArray& operator = (const mxArray&) = delete;
+
+  ~mxArray (void);
+
+  bool is_octave_value (void) const { return rep->is_octave_value (); }
+
+  int iscell (void) const { return rep->iscell (); }
+
+  int is_char (void) const { return rep->is_char (); }
+
+  int is_class (const char *name_arg) const { return rep->is_class (name_arg); }
+
+  int is_complex (void) const { return rep->is_complex (); }
+
+  int is_double (void) const { return rep->is_double (); }
+
+  int is_function_handle (void) const { return rep->is_function_handle (); }
+
+  int is_int16 (void) const { return rep->is_int16 (); }
+
+  int is_int32 (void) const { return rep->is_int32 (); }
+
+  int is_int64 (void) const { return rep->is_int64 (); }
+
+  int is_int8 (void) const { return rep->is_int8 (); }
+
+  int is_logical (void) const { return rep->is_logical (); }
+
+  int is_numeric (void) const { return rep->is_numeric (); }
+
+  int is_single (void) const { return rep->is_single (); }
+
+  int is_sparse (void) const { return rep->is_sparse (); }
+
+  int is_struct (void) const { return rep->is_struct (); }
+
+  int is_uint16 (void) const { return rep->is_uint16 (); }
+
+  int is_uint32 (void) const { return rep->is_uint32 (); }
+
+  int is_uint64 (void) const { return rep->is_uint64 (); }
+
+  int is_uint8 (void) const { return rep->is_uint8 (); }
+
+  int is_logical_scalar (void) const { return rep->is_logical_scalar (); }
+
+  int is_logical_scalar_true (void) const
+  { return rep->is_logical_scalar_true (); }
+
+  mwSize get_m (void) const { return rep->get_m (); }
+
+  mwSize get_n (void) const { return rep->get_n (); }
+
+  mwSize * get_dimensions (void) const { return rep->get_dimensions (); }
+
+  mwSize get_number_of_dimensions (void) const
+  { return rep->get_number_of_dimensions (); }
+
+  void set_m (mwSize m) { DO_VOID_MUTABLE_METHOD (set_m (m)); }
+
+  void set_n (mwSize n) { DO_VOID_MUTABLE_METHOD (set_n (n)); }
+
+  int set_dimensions (mwSize *dims_arg, mwSize ndims_arg)
+  { DO_MUTABLE_METHOD (int, set_dimensions (dims_arg, ndims_arg)); }
+
+  mwSize get_number_of_elements (void) const
+  { return rep->get_number_of_elements (); }
+
+  int isempty (void) const { return get_number_of_elements () == 0; }
+
+  bool is_scalar (void) const { return rep->is_scalar (); }
+
+  const char * get_name (void) const { return name; }
+
+  void set_name (const char *name_arg);
+
+  mxClassID get_class_id (void) const { return rep->get_class_id (); }
+
+  const char * get_class_name (void) const { return rep->get_class_name (); }
+
+  mxArray * get_property (mwIndex idx, const char *pname) const
+  { return rep->get_property (idx, pname); }
+
+  void set_property (mwIndex idx, const char *pname, const mxArray *pval)
+  { rep->set_property (idx, pname, pval); }
+
+  void set_class_name (const char *name_arg)
+  { DO_VOID_MUTABLE_METHOD (set_class_name (name_arg)); }
+
+  mxArray * get_cell (mwIndex idx) const
+  { DO_MUTABLE_METHOD (mxArray *, get_cell (idx)); }
+
+  void set_cell (mwIndex idx, mxArray *val)
+  { DO_VOID_MUTABLE_METHOD (set_cell (idx, val)); }
+
+  double get_scalar (void) const { return rep->get_scalar (); }
+
+  void * get_data (void) const { DO_MUTABLE_METHOD (void *, get_data ()); }
+
+  mxDouble * get_doubles (void) const
+  { DO_MUTABLE_METHOD (mxDouble *, get_doubles ()); }
+
+  mxSingle * get_singles (void) const
+  { DO_MUTABLE_METHOD (mxSingle *, get_singles ()); }
+
+  mxInt8 * get_int8s (void) const
+  { DO_MUTABLE_METHOD (mxInt8 *, get_int8s ()); }
+
+  mxInt16 * get_int16s (void) const
+  { DO_MUTABLE_METHOD (mxInt16 *, get_int16s ()); }
+
+  mxInt32 * get_int32s (void) const
+  { DO_MUTABLE_METHOD (mxInt32 *, get_int32s ()); }
+
+  mxInt64 * get_int64s (void) const
+  { DO_MUTABLE_METHOD (mxInt64 *, get_int64s ()); }
+
+  mxUint8 * get_uint8s (void) const
+  { DO_MUTABLE_METHOD (mxUint8 *, get_uint8s ()); }
+
+  mxUint16 * get_uint16s (void) const
+  { DO_MUTABLE_METHOD (mxUint16 *, get_uint16s ()); }
+
+  mxUint32 * get_uint32s (void) const
+  { DO_MUTABLE_METHOD (mxUint32 *, get_uint32s ()); }
+
+  mxUint64 * get_uint64s (void) const
+  { DO_MUTABLE_METHOD (mxUint64 *, get_uint64s ()); }
+
+  mxComplexDouble * get_complex_doubles (void) const
+  { DO_MUTABLE_METHOD (mxComplexDouble *, get_complex_doubles ()); }
+
+  mxComplexSingle * get_complex_singles (void) const
+  { DO_MUTABLE_METHOD (mxComplexSingle *, get_complex_singles ()); }
+
+#if 0
+  /* We don't have these yet. */
+  mxComplexInt8 * get_complex_int8s (void) const
+  { DO_MUTABLE_METHOD (mxComplexInt8 *, get_complex_int8s ()); }
+
+  mxComplexInt16 * get_complex_int16s (void) const
+  { DO_MUTABLE_METHOD (mxComplexInt16 *, get_complex_int16s ()); }
+
+  mxComplexInt32 * get_complex_int32s (void) const
+  { DO_MUTABLE_METHOD (mxComplexInt32 *, get_complex_int32s ()); }
+
+  mxComplexInt64 * get_complex_int64s (void) const
+  { DO_MUTABLE_METHOD (mxComplexInt64 *, get_complex_int64s ()); }
+
+  mxComplexUint8 * get_complex_uint8s (void) const
+  { DO_MUTABLE_METHOD (mxComplexUint8 *, get_complex_uint8s ()); }
+
+  mxComplexUint16 * get_complex_uint16s (void) const
+  { DO_MUTABLE_METHOD (mxComplexUint16 *, get_complex_uint16s ()); }
+
+  mxComplexUint32 * get_complex_uint32s (void) const
+  { DO_MUTABLE_METHOD (mxComplexUint32 *, get_complex_uint32s ()); }
+
+  mxComplexUint64 * get_complex_uint64s (void) const
+  { DO_MUTABLE_METHOD (mxComplexUint64 *, get_complex_uint64s ()); }
+#endif
+
+  void * get_imag_data (void) const
+  { DO_MUTABLE_METHOD (void *, get_imag_data ()); }
+
+  void set_data (void *pr) { DO_VOID_MUTABLE_METHOD (set_data (pr)); }
+
+  int set_doubles (mxDouble *data)
+  { DO_MUTABLE_METHOD (int, set_doubles (data)); }
+
+  int set_singles (mxSingle *data)
+  { DO_MUTABLE_METHOD (int, set_singles (data)); }
+
+  int set_int8s (mxInt8 *data)
+  { DO_MUTABLE_METHOD (int, set_int8s (data)); }
+
+  int set_int16s (mxInt16 *data)
+  { DO_MUTABLE_METHOD (int, set_int16s (data)); }
+
+  int set_int32s (mxInt32 *data)
+  { DO_MUTABLE_METHOD (int, set_int32s (data)); }
+
+  int set_int64s (mxInt64 *data)
+  { DO_MUTABLE_METHOD (int, set_int64s (data)); }
+
+  int set_uint8s (mxUint8 *data)
+  { DO_MUTABLE_METHOD (int, set_uint8s (data)); }
+
+  int set_uint16s (mxUint16 *data)
+  { DO_MUTABLE_METHOD (int, set_uint16s (data)); }
+
+  int set_uint32s (mxUint32 *data)
+  { DO_MUTABLE_METHOD (int, set_uint32s (data)); }
+
+  int set_uint64s (mxUint64 *data)
+  { DO_MUTABLE_METHOD (int, set_uint64s (data)); }
+
+  int set_complex_doubles (mxComplexDouble *data)
+  { DO_MUTABLE_METHOD (int, set_complex_doubles (data)); }
+
+  int set_complex_singles (mxComplexSingle *data)
+  { DO_MUTABLE_METHOD (int, set_complex_singles (data)); }
+
+#if 0
+  /* We don't have these yet. */
+  int set_complex_int8s (mxComplexInt8 *data)
+  { DO_MUTABLE_METHOD (int, set_complex_int8s (data)); }
+
+  int set_complex_int16s (mxComplexInt16 *data)
+  { DO_MUTABLE_METHOD (int, set_complex_int16s (data)); }
+
+  int set_complex_int32s (mxComplexInt32 *data)
+  { DO_MUTABLE_METHOD (int, set_complex_int32s (data)); }
+
+  int set_complex_int64s (mxComplexInt64 *data)
+  { DO_MUTABLE_METHOD (int, set_complex_int64s (data)); }
+
+  int set_complex_uint8s (mxComplexUint8 *data)
+  { DO_MUTABLE_METHOD (int, set_complex_uint8s (data)); }
+
+  int set_complex_uint16s (mxComplexUint16 *data)
+  { DO_MUTABLE_METHOD (int, set_complex_uint16s (data)); }
+
+  int set_complex_uint32s (mxComplexUint32 *data)
+  { DO_MUTABLE_METHOD (int, set_complex_uint32s (data)); }
+
+  int set_complex_uint64s (mxComplexUint64 *data)
+  { DO_MUTABLE_METHOD (int, set_complex_uint64s (data)); }
+#endif
+
+  void set_imag_data (void *pi) { DO_VOID_MUTABLE_METHOD (set_imag_data (pi)); }
+
+  mwIndex * get_ir (void) const { DO_MUTABLE_METHOD (mwIndex *, get_ir ()); }
+
+  mwIndex * get_jc (void) const { DO_MUTABLE_METHOD (mwIndex *, get_jc ()); }
+
+  mwSize get_nzmax (void) const { return rep->get_nzmax (); }
+
+  void set_ir (mwIndex *ir) { DO_VOID_MUTABLE_METHOD (set_ir (ir)); }
+
+  void set_jc (mwIndex *jc) { DO_VOID_MUTABLE_METHOD (set_jc (jc)); }
+
+  void set_nzmax (mwSize nzmax) { DO_VOID_MUTABLE_METHOD (set_nzmax (nzmax)); }
+
+  int add_field (const char *key) { DO_MUTABLE_METHOD (int, add_field (key)); }
+
+  void remove_field (int key_num)
+  { DO_VOID_MUTABLE_METHOD (remove_field (key_num)); }
+
+  mxArray * get_field_by_number (mwIndex index, int key_num) const
+  { DO_MUTABLE_METHOD (mxArray *, get_field_by_number (index, key_num)); }
+
+  void set_field_by_number (mwIndex index, int key_num, mxArray *val)
+  { DO_VOID_MUTABLE_METHOD (set_field_by_number (index, key_num, val)); }
+
+  int get_number_of_fields (void) const { return rep->get_number_of_fields (); }
+
+  const char * get_field_name_by_number (int key_num) const
+  { DO_MUTABLE_METHOD (const char*, get_field_name_by_number (key_num)); }
+
+  int get_field_number (const char *key) const
+  { DO_MUTABLE_METHOD (int, get_field_number (key)); }
+
+  int get_string (char *buf, mwSize buflen) const
+  { return rep->get_string (buf, buflen); }
+
+  char * array_to_string (void) const { return rep->array_to_string (); }
+
+  mwIndex calc_single_subscript (mwSize nsubs, mwIndex *subs) const
+  { return rep->calc_single_subscript (nsubs, subs); }
+
+  size_t get_element_size (void) const { return rep->get_element_size (); }
+
+  bool mutation_needed (void) const { return rep->mutation_needed (); }
+
+  mxArray * mutate (void) const { return rep->mutate (); }
+
+  static void * malloc (size_t n);
+
+  static void * calloc (size_t n, size_t t);
+
+  static char * strsave (const char *str)
+  {
+    char *retval = nullptr;
+
+    if (str)
+      {
+        mwSize sz = sizeof (mxChar) * (strlen (str) + 1);
+
+        retval = static_cast<char *> (mxArray::malloc (sz));
+
+        if (retval)
+          strcpy (retval, str);
+      }
+
+    return retval;
+  }
+
+  static octave_value
+  as_octave_value (const mxArray *ptr, bool null_is_empty = true);
+
+  octave_value as_octave_value (void) const;
+
+private:
+
+  mutable mxArray_base *rep;
+
+  char *name;
+
+  mxArray (mxArray_base *r, const char *n)
+    : rep (r), name (mxArray::strsave (n)) { }
+
+  static mxArray_base *
+  create_rep (bool interleaved, const octave_value& ov);
+
+  static mxArray_base *
+  create_rep (bool interleaved, mxClassID id, mwSize ndims,
+              const mwSize *dims, mxComplexity flag, bool init);
+
+  static mxArray_base *
+  create_rep (bool interleaved, mxClassID id, const dim_vector& dv,
+              mxComplexity flag);
+
+  static mxArray_base *
+  create_rep (bool interleaved, mxClassID id, mwSize m, mwSize n,
+              mxComplexity flag, bool init);
+
+  static mxArray_base *
+  create_rep (bool interleaved, mxClassID id, double val);
+
+  static mxArray_base *
+  create_rep (bool interleaved, mxClassID id, mxLogical val);
+
+  static mxArray_base *
+  create_rep (bool interleaved, const char *str);
+
+  static mxArray_base *
+  create_rep (bool interleaved, mwSize m, const char **str);
+
+  static mxArray_base *
+  create_rep (bool interleaved, mxClassID id, mwSize m, mwSize n,
+              mwSize nzmax, mxComplexity flag);
+
+  void maybe_mutate (void) const;
+};
+
+#undef DO_MUTABLE_METHOD
+#undef DO_VOID_MUTABLE_METHOD
+
+#endif
+#endif
--- a/libinterp/corefcn/mxarray.in.h	Thu Nov 19 13:05:51 2020 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,570 +0,0 @@
-// %NO_EDIT_WARNING%
-
-////////////////////////////////////////////////////////////////////////
-//
-// Copyright (C) 2001-2020 The Octave Project Developers
-//
-// See the file COPYRIGHT.md in the top-level directory of this
-// distribution or <https://octave.org/copyright/>.
-//
-// This file is part of Octave.
-//
-// Octave is free software: you can redistribute it and/or modify it
-// under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Octave is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Octave; see the file COPYING.  If not, see
-// <https://www.gnu.org/licenses/>.
-//
-////////////////////////////////////////////////////////////////////////
-
-/*
-
-Part of this code was originally distributed as part of Octave Forge under
-the following terms:
-
-Author: Paul Kienzle
-I grant this code to the public domain.
-2001-03-22
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
-*/
-
-#if ! defined (octave_mxarray_h)
-#define octave_mxarray_h 1
-
-#include "octave-config.h"
-
-typedef enum
-{
-  mxUNKNOWN_CLASS = 0,
-  mxCELL_CLASS,
-  mxSTRUCT_CLASS,
-  mxLOGICAL_CLASS,
-  mxCHAR_CLASS,
-  mxVOID_CLASS,
-  mxDOUBLE_CLASS,
-  mxSINGLE_CLASS,
-  mxINT8_CLASS,
-  mxUINT8_CLASS,
-  mxINT16_CLASS,
-  mxUINT16_CLASS,
-  mxINT32_CLASS,
-  mxUINT32_CLASS,
-  mxINT64_CLASS,
-  mxUINT64_CLASS,
-  mxFUNCTION_CLASS
-}
-mxClassID;
-
-typedef enum
-{
-  mxREAL = 0,
-  mxCOMPLEX = 1
-}
-mxComplexity;
-
-/* Matlab uses a wide char (uint16) internally, but Octave uses plain char. */
-/* typedef Uint16 mxChar; */
-typedef char mxChar;
-
-typedef unsigned char mxLogical;
-
-/*
- * FIXME: Mathworks says mwSize, mwIndex should be int generally.
- * But on 64-bit systems, or when mex -largeArrayDims is used, it is size_t.
- * mwSignedIndex is supposed to be ptrdiff_t.  All of this is confusing.
- * Its better to conform to the same indexing as the rest of Octave.
- */
-typedef %OCTAVE_IDX_TYPE% mwSize;
-typedef %OCTAVE_IDX_TYPE% mwIndex;
-typedef %OCTAVE_IDX_TYPE% mwSignedIndex;
-
-#if ! defined (MXARRAY_TYPEDEFS_ONLY)
-
-#include <cstring>
-#include "error.h"
-
-class octave_value;
-class dim_vector;
-
-#define DO_MUTABLE_METHOD(RET_T, METHOD_CALL)   \
-  RET_T retval = rep->METHOD_CALL;              \
-                                                \
-  if (rep->mutation_needed ())                  \
-    {                                           \
-      maybe_mutate ();                          \
-      retval = rep->METHOD_CALL;                \
-    }                                           \
-                                                \
-  return retval
-
-#define DO_VOID_MUTABLE_METHOD(METHOD_CALL)     \
-  rep->METHOD_CALL;                             \
-                                                \
-  if (rep->mutation_needed ())                  \
-    {                                           \
-      maybe_mutate ();                          \
-      rep->METHOD_CALL;                         \
-    }
-
-class mxArray;
-
-// A class to provide the default implementation of some of the
-// virtual functions declared in the mxArray class.
-
-class mxArray_base
-{
-protected:
-
-  mxArray_base (void) { }
-
-public:
-
-  virtual mxArray_base * dup (void) const = 0;
-
-  virtual mxArray * as_mxArray (void) const { return nullptr; }
-
-  virtual ~mxArray_base (void) = default;
-
-  virtual bool is_octave_value (void) const { return false; }
-
-  virtual int iscell (void) const = 0;
-
-  virtual int is_char (void) const = 0;
-
-  virtual int is_class (const char *name_arg) const
-  {
-    int retval = 0;
-
-    const char *cname = get_class_name ();
-
-    if (cname && name_arg)
-      retval = ! strcmp (cname, name_arg);
-
-    return retval;
-  }
-
-  virtual int is_complex (void) const = 0;
-
-  virtual int is_double (void) const = 0;
-
-  virtual int is_function_handle (void) const = 0;
-
-  virtual int is_int16 (void) const = 0;
-
-  virtual int is_int32 (void) const = 0;
-
-  virtual int is_int64 (void) const = 0;
-
-  virtual int is_int8 (void) const = 0;
-
-  virtual int is_logical (void) const = 0;
-
-  virtual int is_numeric (void) const = 0;
-
-  virtual int is_single (void) const = 0;
-
-  virtual int is_sparse (void) const = 0;
-
-  virtual int is_struct (void) const = 0;
-
-  virtual int is_uint16 (void) const = 0;
-
-  virtual int is_uint32 (void) const = 0;
-
-  virtual int is_uint64 (void) const = 0;
-
-  virtual int is_uint8 (void) const = 0;
-
-  virtual int is_logical_scalar (void) const
-  {
-    return is_logical () && get_number_of_elements () == 1;
-  }
-
-  virtual int is_logical_scalar_true (void) const = 0;
-
-  virtual mwSize get_m (void) const = 0;
-
-  virtual mwSize get_n (void) const = 0;
-
-  virtual mwSize * get_dimensions (void) const = 0;
-
-  virtual mwSize get_number_of_dimensions (void) const = 0;
-
-  virtual void set_m (mwSize m) = 0;
-
-  virtual void set_n (mwSize n) = 0;
-
-  virtual int set_dimensions (mwSize *dims_arg, mwSize ndims_arg) = 0;
-
-  virtual mwSize get_number_of_elements (void) const = 0;
-
-  virtual int isempty (void) const = 0;
-
-  virtual bool is_scalar (void) const = 0;
-
-  virtual mxClassID get_class_id (void) const = 0;
-
-  virtual const char * get_class_name (void) const = 0;
-
-  virtual void set_class_name (const char *name_arg) = 0;
-
-  // The following functions aren't pure virtual because they are only
-  // valid for one type.  Making them pure virtual would mean that they
-  // have to be implemented for all derived types, and all of those
-  // would need to throw errors instead of just doing it once here.
-
-  virtual mxArray *
-  get_property (mwIndex /*idx*/, const char * /*pname*/) const
-  {
-    return nullptr;
-  }
-
-  virtual void set_property (mwIndex /*idx*/, const char * /*pname*/,
-                             const mxArray * /*pval*/)
-  {
-    err_invalid_type ();
-  }
-
-  virtual mxArray * get_cell (mwIndex /*idx*/) const
-  {
-    err_invalid_type ();
-  }
-
-  virtual void set_cell (mwIndex idx, mxArray *val) = 0;
-
-  virtual double get_scalar (void) const = 0;
-
-  virtual void * get_data (void) const = 0;
-
-  virtual void * get_imag_data (void) const = 0;
-
-  virtual void set_data (void *pr) = 0;
-
-  virtual void set_imag_data (void *pi) = 0;
-
-  virtual mwIndex * get_ir (void) const = 0;
-
-  virtual mwIndex * get_jc (void) const = 0;
-
-  virtual mwSize get_nzmax (void) const = 0;
-
-  virtual void set_ir (mwIndex *ir) = 0;
-
-  virtual void set_jc (mwIndex *jc) = 0;
-
-  virtual void set_nzmax (mwSize nzmax) = 0;
-
-  virtual int add_field (const char *key) = 0;
-
-  virtual void remove_field (int key_num) = 0;
-
-  virtual mxArray * get_field_by_number (mwIndex index, int key_num) const = 0;
-
-  virtual void
-  set_field_by_number (mwIndex index, int key_num, mxArray *val) = 0;
-
-  virtual int get_number_of_fields (void) const = 0;
-
-  virtual const char * get_field_name_by_number (int key_num) const = 0;
-
-  virtual int get_field_number (const char *key) const = 0;
-
-  virtual int get_string (char *buf, mwSize buflen) const = 0;
-
-  virtual char * array_to_string (void) const = 0;
-
-  virtual mwIndex calc_single_subscript (mwSize nsubs, mwIndex *subs) const = 0;
-
-  virtual size_t get_element_size (void) const = 0;
-
-  virtual bool mutation_needed (void) const { return false; }
-
-  virtual mxArray * mutate (void) const { return nullptr; }
-
-  virtual octave_value as_octave_value (void) const = 0;
-
-protected:
-
-  mxArray_base (const mxArray_base&) { }
-
-  OCTAVE_NORETURN void err_invalid_type (void) const
-  {
-    error ("invalid type for operation");
-  }
-};
-
-// The main interface class.  The representation can be based on an
-// octave_value object or a separate object that tries to reproduce
-// the semantics of mxArray objects in Matlab more directly.
-
-class mxArray
-{
-public:
-
-  mxArray (const octave_value& ov);
-
-  mxArray (mxClassID id, mwSize ndims, const mwSize *dims,
-           mxComplexity flag = mxREAL, bool init = true);
-
-  mxArray (mxClassID id, const dim_vector& dv, mxComplexity flag = mxREAL);
-
-  mxArray (mxClassID id, mwSize m, mwSize n,
-           mxComplexity flag = mxREAL, bool init = true);
-
-  mxArray (mxClassID id, double val);
-
-  mxArray (mxClassID id, mxLogical val);
-
-  mxArray (const char *str);
-
-  mxArray (mwSize m, const char **str);
-
-  mxArray (mxClassID id, mwSize m, mwSize n, mwSize nzmax,
-           mxComplexity flag = mxREAL);
-
-  mxArray (mwSize ndims, const mwSize *dims, int num_keys, const char **keys);
-
-  mxArray (const dim_vector& dv, int num_keys, const char **keys);
-
-  mxArray (mwSize m, mwSize n, int num_keys, const char **keys);
-
-  mxArray (mwSize ndims, const mwSize *dims);
-
-  mxArray (const dim_vector& dv);
-
-  mxArray (mwSize m, mwSize n);
-
-  mxArray * dup (void) const
-  {
-    mxArray *retval = rep->as_mxArray ();
-
-    if (retval)
-      retval->set_name (name);
-    else
-      {
-        mxArray_base *new_rep = rep->dup ();
-
-        retval = new mxArray (new_rep, name);
-      }
-
-    return retval;
-  }
-
-  // No copying!
-
-  mxArray (const mxArray&) = delete;
-
-  mxArray& operator = (const mxArray&) = delete;
-
-  ~mxArray (void);
-
-  bool is_octave_value (void) const { return rep->is_octave_value (); }
-
-  int iscell (void) const { return rep->iscell (); }
-
-  int is_char (void) const { return rep->is_char (); }
-
-  int is_class (const char *name_arg) const { return rep->is_class (name_arg); }
-
-  int is_complex (void) const { return rep->is_complex (); }
-
-  int is_double (void) const { return rep->is_double (); }
-
-  int is_function_handle (void) const { return rep->is_function_handle (); }
-
-  int is_int16 (void) const { return rep->is_int16 (); }
-
-  int is_int32 (void) const { return rep->is_int32 (); }
-
-  int is_int64 (void) const { return rep->is_int64 (); }
-
-  int is_int8 (void) const { return rep->is_int8 (); }
-
-  int is_logical (void) const { return rep->is_logical (); }
-
-  int is_numeric (void) const { return rep->is_numeric (); }
-
-  int is_single (void) const { return rep->is_single (); }
-
-  int is_sparse (void) const { return rep->is_sparse (); }
-
-  int is_struct (void) const { return rep->is_struct (); }
-
-  int is_uint16 (void) const { return rep->is_uint16 (); }
-
-  int is_uint32 (void) const { return rep->is_uint32 (); }
-
-  int is_uint64 (void) const { return rep->is_uint64 (); }
-
-  int is_uint8 (void) const { return rep->is_uint8 (); }
-
-  int is_logical_scalar (void) const { return rep->is_logical_scalar (); }
-
-  int is_logical_scalar_true (void) const
-  { return rep->is_logical_scalar_true (); }
-
-  mwSize get_m (void) const { return rep->get_m (); }
-
-  mwSize get_n (void) const { return rep->get_n (); }
-
-  mwSize * get_dimensions (void) const { return rep->get_dimensions (); }
-
-  mwSize get_number_of_dimensions (void) const
-  { return rep->get_number_of_dimensions (); }
-
-  void set_m (mwSize m) { DO_VOID_MUTABLE_METHOD (set_m (m)); }
-
-  void set_n (mwSize n) { DO_VOID_MUTABLE_METHOD (set_n (n)); }
-
-  int set_dimensions (mwSize *dims_arg, mwSize ndims_arg)
-  { DO_MUTABLE_METHOD (int, set_dimensions (dims_arg, ndims_arg)); }
-
-  mwSize get_number_of_elements (void) const
-  { return rep->get_number_of_elements (); }
-
-  int isempty (void) const { return get_number_of_elements () == 0; }
-
-  bool is_scalar (void) const { return rep->is_scalar (); }
-
-  const char * get_name (void) const { return name; }
-
-  void set_name (const char *name_arg);
-
-  mxClassID get_class_id (void) const { return rep->get_class_id (); }
-
-  const char * get_class_name (void) const { return rep->get_class_name (); }
-
-  mxArray * get_property (mwIndex idx, const char *pname) const
-  { return rep->get_property (idx, pname); }
-
-  void set_property (mwIndex idx, const char *pname, const mxArray *pval)
-  { rep->set_property (idx, pname, pval); }
-
-  void set_class_name (const char *name_arg)
-  { DO_VOID_MUTABLE_METHOD (set_class_name (name_arg)); }
-
-  mxArray * get_cell (mwIndex idx) const
-  { DO_MUTABLE_METHOD (mxArray *, get_cell (idx)); }
-
-  void set_cell (mwIndex idx, mxArray *val)
-  { DO_VOID_MUTABLE_METHOD (set_cell (idx, val)); }
-
-  double get_scalar (void) const { return rep->get_scalar (); }
-
-  void * get_data (void) const { DO_MUTABLE_METHOD (void *, get_data ()); }
-
-  void * get_imag_data (void) const
-  { DO_MUTABLE_METHOD (void *, get_imag_data ()); }
-
-  void set_data (void *pr) { DO_VOID_MUTABLE_METHOD (set_data (pr)); }
-
-  void set_imag_data (void *pi) { DO_VOID_MUTABLE_METHOD (set_imag_data (pi)); }
-
-  mwIndex * get_ir (void) const { DO_MUTABLE_METHOD (mwIndex *, get_ir ()); }
-
-  mwIndex * get_jc (void) const { DO_MUTABLE_METHOD (mwIndex *, get_jc ()); }
-
-  mwSize get_nzmax (void) const { return rep->get_nzmax (); }
-
-  void set_ir (mwIndex *ir) { DO_VOID_MUTABLE_METHOD (set_ir (ir)); }
-
-  void set_jc (mwIndex *jc) { DO_VOID_MUTABLE_METHOD (set_jc (jc)); }
-
-  void set_nzmax (mwSize nzmax) { DO_VOID_MUTABLE_METHOD (set_nzmax (nzmax)); }
-
-  int add_field (const char *key) { DO_MUTABLE_METHOD (int, add_field (key)); }
-
-  void remove_field (int key_num)
-  { DO_VOID_MUTABLE_METHOD (remove_field (key_num)); }
-
-  mxArray * get_field_by_number (mwIndex index, int key_num) const
-  { DO_MUTABLE_METHOD (mxArray *, get_field_by_number (index, key_num)); }
-
-  void set_field_by_number (mwIndex index, int key_num, mxArray *val)
-  { DO_VOID_MUTABLE_METHOD (set_field_by_number (index, key_num, val)); }
-
-  int get_number_of_fields (void) const { return rep->get_number_of_fields (); }
-
-  const char * get_field_name_by_number (int key_num) const
-  { DO_MUTABLE_METHOD (const char*, get_field_name_by_number (key_num)); }
-
-  int get_field_number (const char *key) const
-  { DO_MUTABLE_METHOD (int, get_field_number (key)); }
-
-  int get_string (char *buf, mwSize buflen) const
-  { return rep->get_string (buf, buflen); }
-
-  char * array_to_string (void) const { return rep->array_to_string (); }
-
-  mwIndex calc_single_subscript (mwSize nsubs, mwIndex *subs) const
-  { return rep->calc_single_subscript (nsubs, subs); }
-
-  size_t get_element_size (void) const { return rep->get_element_size (); }
-
-  bool mutation_needed (void) const { return rep->mutation_needed (); }
-
-  mxArray * mutate (void) const { return rep->mutate (); }
-
-  static void * malloc (size_t n);
-
-  static void * calloc (size_t n, size_t t);
-
-  static char * strsave (const char *str)
-  {
-    char *retval = nullptr;
-
-    if (str)
-      {
-        mwSize sz = sizeof (mxChar) * (strlen (str) + 1);
-
-        retval = static_cast<char *> (mxArray::malloc (sz));
-
-        if (retval)
-          strcpy (retval, str);
-      }
-
-    return retval;
-  }
-
-  static octave_value
-  as_octave_value (const mxArray *ptr, bool null_is_empty = true);
-
-  octave_value as_octave_value (void) const;
-
-private:
-
-  mutable mxArray_base *rep;
-
-  char *name;
-
-  mxArray (mxArray_base *r, const char *n)
-    : rep (r), name (mxArray::strsave (n)) { }
-
-  void maybe_mutate (void) const;
-};
-
-#undef DO_MUTABLE_METHOD
-#undef DO_VOID_MUTABLE_METHOD
-
-#endif
-#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/mxtypes.in.h	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,128 @@
+// %NO_EDIT_WARNING%
+
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001-2020 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+/*
+
+Part of this code was originally distributed as part of Octave Forge under
+the following terms:
+
+Author: Paul Kienzle
+I grant this code to the public domain.
+2001-03-22
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+*/
+
+#if ! defined (octave_mxtypes_h)
+#define octave_mxtypes_h 1
+
+#include "octave-config.h"
+
+typedef enum
+{
+  mxUNKNOWN_CLASS = 0,
+  mxCELL_CLASS,
+  mxSTRUCT_CLASS,
+  mxLOGICAL_CLASS,
+  mxCHAR_CLASS,
+  mxVOID_CLASS,
+  mxDOUBLE_CLASS,
+  mxSINGLE_CLASS,
+  mxINT8_CLASS,
+  mxUINT8_CLASS,
+  mxINT16_CLASS,
+  mxUINT16_CLASS,
+  mxINT32_CLASS,
+  mxUINT32_CLASS,
+  mxINT64_CLASS,
+  mxUINT64_CLASS,
+  mxFUNCTION_CLASS
+}
+mxClassID;
+
+typedef enum
+{
+  mxREAL = 0,
+  mxCOMPLEX = 1
+}
+mxComplexity;
+
+/* Matlab uses a wide char (uint16) internally, but Octave uses plain char. */
+/* typedef Uint16 mxChar; */
+typedef char mxChar;
+
+typedef unsigned char mxLogical;
+
+typedef double mxDouble;
+typedef float mxSingle;
+
+typedef int8_t mxInt8;
+typedef int16_t mxInt16;
+typedef int32_t mxInt32;
+typedef int64_t mxInt64;
+
+typedef uint8_t mxUint8;
+typedef uint16_t mxUint16;
+typedef uint32_t mxUint32;
+typedef uint64_t mxUint64;
+
+typedef struct { mxDouble real; mxDouble imag; } mxComplexDouble;
+typedef struct { mxSingle real; mxSingle imag; } mxComplexSingle;
+
+/* We don't have these yet but we can define the types. */
+typedef struct { mxInt8 real; mxInt8 imag; } mxComplexInt8;
+typedef struct { mxInt16 real; mxInt16 imag; } mxComplexInt16;
+typedef struct { mxInt32 real; mxInt32 imag; } mxComplexInt32;
+typedef struct { mxInt64 real; mxInt64 imag; } mxComplexInt64;
+
+typedef struct { mxUint8 real; mxUint8 imag; } mxComplexUint8;
+typedef struct { mxUint16 real; mxUint16 imag; } mxComplexUint16;
+typedef struct { mxUint32 real; mxUint32 imag; } mxComplexUint32;
+typedef struct { mxUint64 real; mxUint64 imag; } mxComplexUint64;
+
+/*
+ * FIXME: Mathworks says mwSize, mwIndex should be int generally.
+ * But on 64-bit systems, or when mex -largeArrayDims is used, it is size_t.
+ * mwSignedIndex is supposed to be ptrdiff_t.  All of this is confusing.
+ * Its better to conform to the same indexing as the rest of Octave.
+ */
+typedef %OCTAVE_IDX_TYPE% mwSize;
+typedef %OCTAVE_IDX_TYPE% mwIndex;
+typedef %OCTAVE_IDX_TYPE% mwSignedIndex;
+
+#endif
--- a/libinterp/corefcn/oct-hist.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/oct-hist.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -327,12 +327,14 @@
   {
     bool numbered_output = nargout == 0;
 
-    unwind_protect frame;
+    unwind_action restore_history_filename
+      ([] (const std::string& old_filename)
+       {
+         command_history::set_file (old_filename);
+       }, command_history::file ());
 
     string_vector hlist;
 
-    frame.add_fcn (command_history::set_file, command_history::file ());
-
     int nargin = args.length ();
 
     // Number of history lines to show (-1 = all)
@@ -545,8 +547,18 @@
       file = env_file;
 
     if (file.empty ())
-      file = sys::file_ops::concat (sys::env::get_home_directory (),
-                                    ".octave_hist");
+      {
+        // Default to $DATA/octave/history, where $DATA is the platform-
+        // dependent location for (roaming) user data files.
+
+        std::string user_data_dir = sys::env::get_user_data_directory ();
+
+        std::string hist_dir = user_data_dir + sys::file_ops::dir_sep_str ()
+                               + "octave";
+
+        file = sys::env::make_absolute ("history", hist_dir);
+      }
+
 
     return file;
   }
@@ -819,8 +831,11 @@
 All future commands issued during the current Octave session will be written to
 this new file (if the current setting of @code{history_save} allows for this).
 
-The default value is @file{~/.octave_hist}, but may be overridden by the
-environment variable @w{@env{OCTAVE_HISTFILE}}.
+The default value is @file{@w{@env{$DATA}}/octave/history}, where
+@w{@env{$DATA}} is the platform-specific location for (roaming) user data files
+(e.g. @w{@env{$XDG_DATA_HOME}} or, if that is not set, @file{~/.local/share} on
+Unix-like operating systems or @w{@env{%APPDATA%}} on Windows).  The default
+value may be overridden by the environment variable @w{@env{OCTAVE_HISTFILE}}.
 
 Programming Notes:
 
--- a/libinterp/corefcn/oct-map.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/oct-map.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -564,8 +564,8 @@
 %! reshape (x, 3, 8, 1, 1);
 
 %!test <*46385>
-%! M = repmat (struct ('a', ones(100), 'b', true), 1, 2);
-%! M = repmat(M, 1, 2);
+%! M = repmat (struct ('a', ones (100), 'b', true), 1, 2);
+%! M = repmat (M, 1, 2);
 %! assert (size (M), [1, 4]);
 
 libinterp/corefcn/oct-map.cc
--- a/libinterp/corefcn/oct-stream.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/oct-stream.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -97,8 +97,7 @@
       }
     catch (const execution_exception&)
       {
-        octave::interpreter& interp
-          = __get_interpreter__ ("convert_to_valid_int");
+        interpreter& interp = __get_interpreter__ ("convert_to_valid_int");
 
         interp.recover_from_exception ();
 
@@ -1914,7 +1913,7 @@
 
     bool match_literal (delimited_stream& isp, const textscan_format_elt& elem);
 
-    int skip_whitespace (delimited_stream& is, bool EOLstop = false);
+    int skip_whitespace (delimited_stream& is, bool EOLstop = true);
 
     int skip_delim (delimited_stream& is);
 
@@ -2472,7 +2471,7 @@
     while (! ds.eof ())
       {
         bool already_skipped_delim = false;
-        ts.skip_whitespace (ds);
+        ts.skip_whitespace (ds, false);
         ds.progress_benchmark ();
         ts.scan_complex (ds, *fmt_elts[0], val);
         if (ds.fail ())
@@ -2714,8 +2713,8 @@
               dv = dim_vector (std::max (valid_rows - 1, 0), 1);
 
             ra_idx(1) = i;
-            retval = do_cat_op (retval, octave_value (Cell (col.resize (dv,0))),
-                                ra_idx);
+            retval = cat_op (retval, octave_value (Cell (col.resize (dv,0))),
+                             ra_idx);
             i++;
           }
       }
@@ -2734,8 +2733,7 @@
                 if (prev_type != -1)
                   {
                     ra_idx(1) = i++;
-                    retval = do_cat_op (retval, octave_value (Cell (cur)),
-                                        ra_idx);
+                    retval = cat_op (retval, octave_value (Cell (cur)), ra_idx);
                   }
                 cur = octave_value (col.resize (dv,0));
                 group_size = 1;
@@ -2744,12 +2742,11 @@
             else
               {
                 ra_idx(1) = group_size++;
-                cur = do_cat_op (cur, octave_value (col.resize (dv,0)),
-                                 ra_idx);
+                cur = cat_op (cur, octave_value (col.resize (dv,0)), ra_idx);
               }
           }
         ra_idx(1) = i;
-        retval = do_cat_op (retval, octave_value (Cell (cur)), ra_idx);
+        retval = cat_op (retval, octave_value (Cell (cur)), ra_idx);
       }
 
     return retval;
@@ -2960,7 +2957,7 @@
       {
         char *pos = is.tellg ();
         std::ios::iostate state = is.rdstate ();
-        //re = octave_read_value<double> (is);
+        //re = read_value<double> (is);
         re = read_double (is, fmt);
 
         // check for "treat as empty" string
@@ -3025,7 +3022,7 @@
                 pos   = is.tellg ();
                 state = is.rdstate ();
 
-                //im = octave_read_value<double> (is);
+                //im = read_value<double> (is);
                 im = read_double (is, fmt);
                 if (is.fail ())
                   im = 1;
@@ -3276,7 +3273,7 @@
                     else
                       {
                         if (ov.isreal ())  // cat does type conversion
-                          ov = do_cat_op (ov, octave_value (v), row);
+                          ov = cat_op (ov, octave_value (v), row);
                         else
                           ov.internal_rep ()->fast_elem_insert (row(0), v);
                       }
@@ -3289,7 +3286,7 @@
                     else
                       {
                         if (ov.isreal ())  // cat does type conversion
-                          ov = do_cat_op (ov, octave_value (v), row);
+                          ov = cat_op (ov, octave_value (v), row);
                         else
                           ov.internal_rep ()->fast_elem_insert (row(0),
                                                                 FloatComplex (v));
@@ -3374,7 +3371,7 @@
           }
 
         if (is.fail () & ! fmt.discard)
-          ov = do_cat_op (ov, empty_value, row);
+          ov = cat_op (ov, empty_value, row);
       }
     else
       {
@@ -3500,11 +3497,12 @@
         elem = fmt_list.next ();
         char *pos = is.tellg ();
 
-        // FIXME: these conversions "ignore delimiters".  Should they include
-        // delimiters at the start of the conversion, or can those be skipped?
-        if (elem->type != textscan_format_elt::literal_conversion
-            // && elem->type != '[' && elem->type != '^' && elem->type != 'c'
-           )
+        // Skip delimiter before reading the next fmt conversion,
+        // unless the fmt is a string literal which begins with a delimiter,
+        // in which case the literal must match everything.  Bug #58008
+        if (elem->type != textscan_format_elt::literal_conversion)
+          skip_delim (is);
+        else if (! is_delim (elem->text[0]))
           skip_delim (is);
 
         if (is.eof ())
@@ -3892,8 +3890,8 @@
   int
   textscan::skip_delim (delimited_stream& is)
   {
-    int c1 = skip_whitespace (is, true);  // 'true': stop once EOL is read
-    if (delim_list.numel () == 0)         // single character delimiter
+    int c1 = skip_whitespace (is);  // Stop once EOL is read
+    if (delim_list.numel () == 0)   // single character delimiter
       {
         if (is_delim (c1) || c1 == eol1 || c1 == eol2)
           {
@@ -3943,7 +3941,7 @@
                 int prev = -1;
                 // skip multiple delims.
                 // Increment lines for each end-of-line seen; for \r\n, decrement
-                while (is && ((c1 = skip_whitespace (is, true))
+                while (is && ((c1 = skip_whitespace (is))
                               != std::istream::traits_type::eof ())
                        && (((c1 == eol1 || c1 == eol2) && ++lines)
                            || -1 != lookahead (is, delim_list, delim_len)))
@@ -4369,7 +4367,7 @@
             {
               is.putback (c1);
 
-              ref = octave_read_value<double> (is);
+              ref = read_value<double> (is);
             }
         }
         break;
@@ -5715,7 +5713,7 @@
         // Easier than dispatching here...
 
         octave_value ov_is_ge_zero
-          = do_binary_op (octave_value::op_ge, val, octave_value (0.0));
+          = binary_op (octave_value::op_ge, val, octave_value (0.0));
 
         return ov_is_ge_zero.is_true ();
       }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/ordqz.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,678 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+// Generalized eigenvalue reordering via LAPACK
+
+// Originally written by M. Koehler <koehlerm(AT)mpi-magdeburg.mpg.de>
+
+#undef DEBUG
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include <cctype>
+#include <cmath>
+
+#include "f77-fcn.h"
+#include "lo-lapack-proto.h"
+#include "qr.h"
+#include "quit.h"
+
+#include "defun.h"
+#include "error.h"
+#include "errwarn.h"
+#include "ovl.h"
+
+
+#if defined (DEBUG)
+#  include "pager.h"
+#  include "pr-output.h"
+#endif
+
+
+DEFUN (ordqz, args, nargout,
+       doc: /* -*- texinfo -*-
+@deftypefn  {} {[@var{AR}, @var{BR}, @var{QR}, @var{ZR}] =} ordqz (@var{AA}, @var{BB}, @var{Q}, @var{Z}, @var{keyword})
+@deftypefnx {} {[@var{AR}, @var{BR}, @var{QR}, @var{ZR}] =} ordqz (@var{AA}, @var{BB}, @var{Q}, @var{Z}, @var{select})
+Reorder the QZ@tie{}decomposition of a generalized eigenvalue problem.
+
+The generalized eigenvalue problem is defined as
+
+@tex
+$$A x = \lambda B x$$
+@end tex
+@ifnottex
+
+@math{A x = @var{lambda} B x}
+
+@end ifnottex
+
+Its generalized Schur decomposition is computed using the @code{qz} algorithm:
+
+@code{[@var{AA}, @var{BB}, @var{Q}, @var{Z}] = qz (@var{A}, @var{B})}
+
+where @var{AA}, @var{BB}, @var{Q}, and @var{Z} fulfill
+@tex
+$$ AA = Q \cdot A \cdot Z, BB = Q \cdot B \cdot Z $$
+@end tex
+@ifnottex
+
+@example
+@group
+
+@var{AA} = @var{Q} * @var{A} * @var{Z}, @var{BB} = @var{Q} * @var{B} * @var{Z}
+
+@end group
+@end example
+
+@end ifnottex
+
+The @code{ordqz} function computes a unitary transformation @var{QR} and
+@var{ZR} such that the order of the eigenvalue on the diagonal of @var{AA} and
+@var{BB} is changed.  The resulting reordered matrices @var{AR} and @var{BR}
+fulfill:
+
+@tex
+$$ A_R = Q_R \cdot A \cdot Z_R, B_R = Q_R \cdot B \cdot Z_R $$
+@end tex
+@ifnottex
+
+@example
+@group
+
+@var{AR} = @var{QR} * @var{A} * @var{ZR}, @var{BR} = @var{QR} * @var{B} * @var{ZR}
+
+@end group
+@end example
+
+@end ifnottex
+
+The function can either be called with the @var{keyword} argument which
+selects the eigenvalues in the top left block of @var{AR} and @var{BR} in the
+following way:
+
+@table @asis
+@item @qcode{"S"}, @qcode{"udi"}
+small: leading block has all
+@tex
+$|\lambda| < 1$
+@end tex
+@ifnottex
+|@var{lambda}| < 1
+@end ifnottex
+
+@item @qcode{"B"}, @qcode{"udo"}
+big: leading block has all
+@tex
+$|\lambda| \geq 1$
+@end tex
+@ifnottex
+|@var{lambda}| @geq{} 1
+@end ifnottex
+
+@item @qcode{"-"}, @qcode{"lhp"}
+negative real part: leading block has all eigenvalues in the open left
+half-plane
+
+@item @qcode{"+"}, @qcode{"rhp"}
+non-negative real part: leading block has all eigenvalues in the closed right
+half-plane
+@end table
+
+If a logical vector @var{select} is given instead of a keyword the @code{ordqz}
+function reorders all eigenvalues @code{k} to the left block for which
+@code{select(k)} is true.
+
+Note: The keywords are compatible with the ones from @code{qr}.
+
+@seealso{eig, ordeig, qz, schur, ordschur}
+@end deftypefn */)
+{
+  enum { LHP, RHP, UDI, UDO, VEC, NONE } select_mode = NONE;
+
+  if (args.length () != 5)
+    print_usage ();
+
+  // Check select argument
+  if (args(4).is_string())
+    {
+      std::string opts = args(4).string_value ();
+      std::for_each (opts.begin (), opts.end (),
+                     [] (char & c) { c = std::tolower (c); });
+      if (opts == "lhp" || opts == "-")
+        select_mode = LHP;
+      else if (opts == "rhp" || opts == "+")
+        select_mode = RHP;
+      else if (opts == "udi" || opts == "s")
+        select_mode = UDI;
+      else if (opts == "udo" || opts == "b")
+        select_mode = UDO;
+      else
+        error_with_id ("Octave:ordqz:unknown-keyword",
+                       "ordqz: unknown KEYWORD, possible values: "
+                       "lhp, rhp, udi, udo");
+    }
+  else if (args(4).isreal () || args(4).isinteger () || args(4).islogical ())
+    {
+      if (args(4).rows () > 1 && args(4).columns () > 1)
+        error_with_id ("Octave:ordqz:select-not-vector",
+                       "ordqz: SELECT argument must be a vector");
+      select_mode = VEC;
+    }
+  else
+    error_with_id ("Octave:ordqz:unknown-arg",
+                   "ordqz: OPT must be string or a logical vector");
+
+  if (nargout > 4)
+    error_with_id ("Octave:ordqz:nargout",
+                   "ordqz: at most four output arguments possible");
+
+  // Matrix A: check dimensions.
+  F77_INT nn = octave::to_f77_int (args(0).rows ());
+  F77_INT nc = octave::to_f77_int (args(0).columns ());
+
+  if (args(0).isempty ())
+    {
+      warn_empty_arg ("qz: A");
+      return octave_value_list (2, Matrix ());
+    }
+  else if (nc != nn)
+    err_square_matrix_required ("qz", "A");
+
+  // Matrix A: get value.
+  Matrix aa;
+  ComplexMatrix caa;
+
+  if (args(0).iscomplex ())
+    caa = args(0).complex_matrix_value ();
+  else
+    aa = args(0).matrix_value ();
+
+  // Extract argument 2 (bb, or cbb if complex).
+  F77_INT b_nr = octave::to_f77_int (args(1).rows ());
+  F77_INT b_nc = octave::to_f77_int (args(1).columns ());
+
+  if (nn != b_nc || nn != b_nr)
+    err_nonconformant ();
+
+  Matrix bb;
+  ComplexMatrix cbb;
+
+  if (args(1).iscomplex ())
+    cbb = args(1).complex_matrix_value ();
+  else
+    bb = args(1).matrix_value ();
+
+  // Extract argument 3 (qq, or cqq if complex).
+  F77_INT q_nr = octave::to_f77_int (args(2).rows ());
+  F77_INT q_nc = octave::to_f77_int (args(2).columns ());
+
+  if (nn != q_nc || nn != q_nr)
+    err_nonconformant ();
+
+  Matrix qq;
+  ComplexMatrix cqq;
+
+  if (args(2).iscomplex ())
+    cqq = args(2).complex_matrix_value ().hermitian ();
+  else
+    qq = args(2).matrix_value ().transpose ();
+
+  // Extract argument 4 (zz, or czz if complex).
+  F77_INT z_nr = octave::to_f77_int (args(3).rows ());
+  F77_INT z_nc = octave::to_f77_int (args(3).columns ());
+
+  if (nn != z_nc || nn != z_nr)
+    err_nonconformant ();
+
+  Matrix zz;
+  ComplexMatrix czz;
+
+  if (args(3).iscomplex ())
+    czz = args(3).complex_matrix_value ();
+  else
+    zz = args(3).matrix_value ();
+
+  bool complex_case = (args(0).iscomplex () || args(1).iscomplex ()
+                       || args(2).iscomplex () || args(3).iscomplex ());
+
+  if (select_mode == VEC && args(4).rows () != nn && args(4).columns () != nn)
+    error_with_id ("Octave:ordqz:numel_select",
+                   "ordqz: SELECT vector has the wrong number of elements");
+
+  Array<double> select_array (dim_vector (nn, 1));
+  if (select_mode == VEC)
+    select_array = args(4).vector_value ();
+
+  Array<F77_LOGICAL> select (dim_vector (nn, 1));
+
+  if (complex_case)
+    {
+      // Complex
+      if (args(0).isreal ())
+        caa = ComplexMatrix (aa);
+      if (args(1).isreal ())
+        cbb = ComplexMatrix (bb);
+      if (args(2).isreal ())
+        cqq = ComplexMatrix (qq);
+      if (args(3).isreal ())
+        czz = ComplexMatrix (zz);
+
+      ComplexRowVector alpha (dim_vector (nn, 1));
+      ComplexRowVector beta  (dim_vector (nn, 1));
+      octave_idx_type k;
+
+      for (k = 0; k < nn-1; k++)
+        {
+          if (caa(k+1,k) != 0.0)
+            error_with_id ("Octave:ordqz:unsupported_AA",
+                           "ordqz: quasi upper triangular matrices are not "
+                           "allowed with complex data");
+        }
+
+      for (k = 0; k < nn; k++)
+        {
+          alpha(k) = caa(k,k);
+          beta(k)  = cbb(k,k);
+        }
+
+      for (k = 0; k < nn; k++)
+        {
+          switch (select_mode)
+            {
+            case LHP:
+              select(k) = real (alpha(k) * beta(k)) < 0;
+              break;
+            case RHP:
+              select(k) = real (alpha(k) * beta(k)) > 0;
+              break;
+            case UDI:
+              if (beta(k) != 0.0)
+                select(k) = abs (alpha(k)/beta(k)) < 1.0;
+              else
+                select(k) = false;
+              break;
+            case UDO:
+              if (beta(k) != 0.0)
+                select(k) = abs (alpha(k)/beta(k)) > 1.0;
+              else
+                select(k) = true;
+              break;
+            case VEC:
+              if (select_array(k) != 0.0)
+                select(k) = true;
+              else
+                select(k) = false;
+              break;
+            default:
+              // default: case just here to suppress compiler warning.
+              panic_impossible ();
+            }
+        }
+
+      F77_LOGICAL wantq, wantz;
+      wantq = 1,  wantz = 1;
+      F77_INT ijob, mm, lrwork3, liwork, info;
+      ijob = 0,  lrwork3 = 1,  liwork = 1;
+      F77_DBLE pl, pr;
+      ComplexRowVector work3 (lrwork3);
+      Array<F77_INT> iwork (dim_vector (liwork, 1));
+
+      F77_XFCN (ztgsen, ZTGSEN,
+                (ijob, wantq, wantz,
+                 select.fortran_vec (), nn,
+                 F77_DBLE_CMPLX_ARG (caa.fortran_vec ()), nn,
+                 F77_DBLE_CMPLX_ARG (cbb.fortran_vec ()), nn,
+                 F77_DBLE_CMPLX_ARG (alpha.fortran_vec ()),
+                 F77_DBLE_CMPLX_ARG (beta.fortran_vec ()),
+                 F77_DBLE_CMPLX_ARG (cqq.fortran_vec ()), nn,
+                 F77_DBLE_CMPLX_ARG (czz.fortran_vec ()), nn,
+                 mm,
+                 pl, pr,
+                 nullptr,
+                 F77_DBLE_CMPLX_ARG (work3.fortran_vec ()), lrwork3,
+                 iwork.fortran_vec (), liwork,
+                 info));
+      if (info != 0)
+        error_with_id ("Octave:ordqz:ztgsen_failed",
+                       "ordqz: failed to reorder eigenvalues");
+    }
+  else
+    {
+      // Extract eigenvalues
+      RowVector alphar (dim_vector (nn, 1));
+      RowVector alphai (dim_vector (nn, 1));
+      RowVector beta (dim_vector (nn, 1));
+
+      octave_idx_type k;
+
+      k = 0;
+      while (k < nn)
+        {
+#ifdef DEBUG
+          octave_stdout << "ordqz: k = " << k  << " nn = " << nn << " \n";
+#endif
+          if ((k < nn-1 && aa(k+1,k) == 0.0) || k == nn-1)
+            {
+              alphar(k) = aa(k,k);
+              alphai(k) = 0.0;
+              beta(k)   = bb(k,k);
+              k++;
+            }
+          else
+            {
+              double ar[2], ai[2], b[2], work[4];
+              char qz_job = 'E';
+              char comp_q = 'N';
+              char comp_z = 'N';
+              F77_INT nl = 2;
+              F77_INT ilo = 1;
+              F77_INT ihi = 2;
+              F77_INT lwork = 4;
+              F77_INT info = 0;
+              double * aa_vec = aa.fortran_vec ();
+              double * bb_vec = bb.fortran_vec ();
+
+              F77_XFCN (dhgeqz, DHGEQZ,
+                        (F77_CONST_CHAR_ARG2 (&qz_job, 1),
+                         F77_CONST_CHAR_ARG2 (&comp_q, 1),
+                         F77_CONST_CHAR_ARG2 (&comp_z, 1),
+                         nl, ilo, ihi,
+                         &aa_vec[k+k*nn] , nn,
+                         &bb_vec[k+k*nn], nn,
+                         ar, ai, b,
+                         nullptr, nn,
+                         nullptr, nn, work, lwork, info
+                         F77_CHAR_ARG_LEN (1)
+                         F77_CHAR_ARG_LEN (1)
+                         F77_CHAR_ARG_LEN (1)));
+              if (info != 0)
+                error("ordqz: failed to extract eigenvalues");
+
+              alphar(k)   = ar[0];
+              alphar(k+1) = ar[1];
+              alphai(k)   = ai[0];
+              alphai(k+1) = ai[1];
+              beta(k)   = b[0];
+              beta(k+1) = b[1];
+
+              k += 2;
+            }
+
+        }
+
+      for (k = 0; k < nn; k++)
+        {
+          switch (select_mode)
+            {
+            case LHP:
+              select(k) = alphar(k) * beta(k) < 0;
+              break;
+            case RHP:
+              select(k) = alphar(k) * beta(k) > 0;
+              break;
+            case UDI:
+              select(k) = alphar(k)*alphar(k)
+                          + alphai(k)*alphai(k) < beta(k)*beta(k);
+              break;
+            case UDO:
+              select(k) = alphar(k)*alphar(k)
+                          + alphai(k)*alphai(k) > beta(k)*beta(k);
+              break;
+            case VEC:
+              if (select_array(k) != 0.0)
+                select(k) = true;
+              else
+                select(k) = false;
+              break;
+            default:
+              // default: case just here to suppress compiler warning.
+              panic_impossible();
+            }
+        }
+
+      F77_LOGICAL wantq, wantz;
+      wantq = 1,  wantz = 1;
+      F77_INT ijob, mm, lrwork3, liwork, info;
+      ijob = 0,  lrwork3 = 4*nn+16,  liwork = nn;
+      F77_DBLE pl, pr;
+      RowVector rwork3 (lrwork3);
+      Array<F77_INT> iwork (dim_vector (liwork, 1));
+
+      F77_XFCN (dtgsen, DTGSEN,
+                (ijob, wantq, wantz,
+                 select.fortran_vec (), nn,
+                 aa.fortran_vec (), nn,
+                 bb.fortran_vec (), nn,
+                 alphar.fortran_vec (),
+                 alphai.fortran_vec (),
+                 beta.fortran_vec (),
+                 qq.fortran_vec (), nn,
+                 zz.fortran_vec (), nn,
+                 mm,
+                 pl, pr,
+                 nullptr,
+                 rwork3.fortran_vec (), lrwork3,
+                 iwork.fortran_vec (), liwork,
+                 info));
+      if (info != 0)
+        error("ordqz: failed to reorder eigenvalues");
+    }
+
+  octave_value_list retval (nargout);
+  switch (nargout)
+    {
+    case 4:
+      if (complex_case)
+        retval(3) = czz;
+      else
+        retval(3) = zz;
+      OCTAVE_FALLTHROUGH;
+    case 3:
+      if (complex_case)
+        retval(2) = cqq.hermitian();
+      else
+        retval(2) = qq.transpose();
+      OCTAVE_FALLTHROUGH;
+    case 2:
+      if (complex_case)
+        retval(1) = cbb;
+      else
+        retval(1) = bb;
+      OCTAVE_FALLTHROUGH;
+    case 1:
+      if (complex_case)
+        retval(0) = caa;
+      else
+        retval(0) = aa;
+      break;
+    case 0:
+      if (complex_case)
+        retval(0) = caa;
+      else
+        retval(0) = aa;
+      break;
+    }
+
+  return retval;
+}
+
+
+/*
+%!shared A, B, AA, BB, QQ, ZZ, AC, BC, AAC, BBC, QQC, ZZC, select, selectc
+%! A = [ -1.03428  0.24929  0.43205 -0.12860;
+%!        1.16228  0.27870  2.12954  0.69250;
+%!       -0.51524 -0.34939 -0.77820  2.13721;
+%!       -1.32941  2.11870  0.72005  1.00835 ];
+%! B = [  1.407302 -0.632956 -0.360628  0.068534;
+%!        0.149898  0.298248  0.991777  0.023652;
+%!        0.169281 -0.405205 -1.775834  1.511730;
+%!        0.717770  1.291390 -1.766607 -0.531352 ];
+%! AC = [ 0.4577 + 0.7199i   0.1476 + 0.6946i   0.6202 + 0.2092i   0.7559 + 0.2759i;
+%!        0.5868 + 0.7275i   0.9174 + 0.8781i   0.6741 + 0.1985i   0.4320 + 0.7023i;
+%!        0.2408 + 0.6359i   0.2959 + 0.8501i   0.3904 + 0.5613i   0.5000 + 0.1428i;
+%!        0.8177 + 0.8581i   0.2583 + 0.8970i   0.7706 + 0.5451i   0.1068 + 0.1650i];
+%! BC = [ 0.089898 + 0.209257i   0.157769 + 0.311387i   0.018926 + 0.622517i   0.058825 + 0.374647i;
+%!        0.009367 + 0.098211i   0.736087 + 0.095797i   0.973192 + 0.583765i   0.434018 + 0.461909i;
+%!        0.880784 + 0.868215i   0.032839 + 0.569461i   0.873437 + 0.266081i   0.739426 + 0.362017i;
+%!        0.121649 + 0.115111i   0.426695 + 0.492222i   0.247670 + 0.034414i   0.771629 + 0.078153i];
+%! [AA, BB, QQ, ZZ] = qz (A, B);
+%! [AAC, BBC, QQC, ZZC] = qz (AC, BC);
+%! select = [0 0 1 1];
+%! selectc = [0 0 0 1];
+
+%!test
+%! [AAX, BBX, QQX, ZZX] = ordqz (AA, BB, QQ, ZZ, "rhp");
+%! assert (all (real (eig (AAX(1:3,1:3), BBX(1:3,1:3))) >= 0));
+%! assert (all (real (eig (AAX(4:4,4:4), BBX(4:4,4:4))) < 0));
+%! assert (norm (QQX'*AAX*ZZX' - A, "fro"), 0, 1e-12);
+%! assert (norm (QQX'*BBX*ZZX' - B, "fro"), 0, 1e-12);
+
+%!test
+%! [AAX, BBX, QQX, ZZX] = ordqz (AA, BB, QQ, ZZ, "+");
+%! assert (all (real (eig (AAX(1:3,1:3), BBX(1:3,1:3))) >= 0));
+%! assert (all (real (eig (AAX(4:4,4:4), BBX(4:4,4:4))) < 0));
+
+%!test
+%! [AAX, BBX, QQX, ZZX] = ordqz (AA, BB, QQ, ZZ, "lhp");
+%! assert (all (real (eig (AAX(2:4,2:4), BBX(2:4,2:4))) >= 0));
+%! assert (all (real (eig (AAX(1:1,1:1), BBX(1:1,1:1))) < 0));
+%! assert (norm (QQX'*AAX*ZZX' - A, "fro"), 0, 1e-12);
+%! assert (norm (QQX'*BBX*ZZX' - B, "fro"), 0, 1e-12);
+
+%!test
+%! [AAX, BBX, QQX, ZZX] = ordqz (AA, BB, QQ, ZZ, "-");
+%! assert (all (real (eig (AAX(2:4,2:4), BBX(2:4,2:4))) >= 0));
+%! assert (all (real (eig (AAX(1:1,1:1), BBX(1:1,1:1))) < 0));
+
+%!test
+%! [AAX, BBX, QQX, ZZX] = ordqz (AA, BB, QQ, ZZ, "udi");
+%! assert (all (abs (eig (AAX(1:1,1:1), BBX(1:1,1:1))) < 1));
+%! assert (all (abs (eig (AAX(2:4,2:4), BBX(2:4,2:4))) > 1));
+%! assert (norm (QQX'*AAX*ZZX' - A, "fro"), 0, 1e-12);
+%! assert (norm (QQX'*BBX*ZZX' - B, "fro"), 0, 1e-12);
+
+%!test
+%! [AAX, BBX, QQX, ZZX] = ordqz (AA, BB, QQ, ZZ, "S");
+%! assert (all (abs (eig (AAX(1:1,1:1), BBX(1:1,1:1))) < 1));
+%! assert (all (abs (eig (AAX(2:4,2:4), BBX(2:4,2:4))) > 1));
+
+%!test
+%! [AAX, BBX, QQX, ZZX] = ordqz (AA, BB, QQ, ZZ, "udo");
+%! assert (all (abs (eig (AAX(1:3,1:3), BBX(1:3,1:3))) >= 1));
+%! assert (all (abs (eig (AAX(4:4,4:4), BBX(4:4,4:4))) < 1));
+%! assert (norm (QQX'*AAX*ZZX' - A, "fro"), 0, 1e-12);
+%! assert (norm (QQX'*BBX*ZZX' - B, "fro"), 0, 1e-12);
+
+%!test
+%! [AAX, BBX, QQX, ZZX] = ordqz (AA, BB, QQ, ZZ, "B");
+%! assert (all (abs (eig (AAX(1:3,1:3), BBX(1:3,1:3))) >= 1));
+%! assert (all (abs (eig (AAX(4:4,4:4), BBX(4:4,4:4))) < 1));
+
+%!test
+%! [AAX, BBX, QQX, ZZX] = ordqz (AA, BB, QQ, ZZ, select);
+%! assert (all (iscomplex (eig (AAX(1:2,1:2), BBX(1:2,1:2)))));
+%! assert (norm (QQX'*AAX*ZZX' - A, "fro"), 0, 1e-12);
+%! assert (norm (QQX'*BBX*ZZX' - B, "fro"), 0, 1e-12);
+
+%!test
+%! [AACX, BBCX, QQCX, ZZCX] = ordqz (AAC, BBC, QQC, ZZC, "rhp");
+%! assert (all (real (eig (AACX(1:2,1:2), BBCX(1:2,1:2))) >= 0));
+%! assert (all (real (eig (AACX(3:4,3:4), BBCX(3:4,3:4))) < 0));
+%! assert (norm (QQCX'*AACX*ZZCX' - AC, "fro"), 0, 1e-12);
+%! assert (norm (QQCX'*BBCX*ZZCX' - BC, "fro"), 0, 1e-12);
+
+%!test
+%! [AACX, BBCX, QQCX, ZZCX] = ordqz (AAC, BBC, QQC, ZZC, "lhp");
+%! assert (all (real (eig (AACX(1:2,1:2), BBCX(1:2,1:2))) < 0));
+%! assert (all (real (eig (AACX(3:4,3:4), BBCX(3:4,3:4))) >= 0));
+%! assert (norm (QQCX'*AACX*ZZCX' - AC, "fro"), 0, 1e-12);
+%! assert (norm (QQCX'*BBCX*ZZCX' - BC, "fro"), 0, 1e-12);
+
+%!test
+%! [AACX, BBCX, QQCX, ZZCX] = ordqz (AAC, BBC, QQC, ZZC, "udi");
+%! assert (all (abs (eig (AACX(1:2,1:2), BBCX(1:2,1:2))) < 1));
+%! assert (all (abs (eig (AACX(3:4,3:4), BBCX(3:4,3:4))) >= 1));
+%! assert (norm (QQCX'*AACX*ZZCX' - AC, "fro"), 0, 1e-12);
+%! assert (norm (QQCX'*BBCX*ZZCX' - BC, "fro"), 0, 1e-12);
+
+%!test
+%! [AACX, BBCX, QQCX, ZZCX] = ordqz (AAC, BBC, QQC, ZZC, "udo");
+%! assert (all (abs (eig (AACX(1:2,1:2), BBCX(1:2,1:2))) >= 1));
+%! assert (all (abs (eig (AACX(3:4,3:4), BBCX(3:4,3:4))) < 1));
+%! assert (norm (QQCX'*AACX*ZZCX' - AC, "fro"), 0, 1e-12);
+%! assert (norm (QQCX'*BBCX*ZZCX' - BC, "fro"), 0,  1e-12);
+
+%!test
+%! [AACX, BBCX, QQCX, ZZCX] = ordqz (AAC, BBC, QQC, ZZC, selectc);
+%! ev = abs (eig (AACX(1:1,1:1), BBCX(1:1,1:1)));
+%! assert(ev > 0.6 && ev < 0.7);
+%! assert (norm (QQCX'*AACX*ZZCX' - AC, "fro"), 0, 1e-12);
+%! assert (norm (QQCX'*BBCX*ZZCX' - BC, "fro"), 0, 1e-12);
+
+%!test
+%! A = toeplitz ([1,2,3,4]);
+%! [B, A] = qr (A);
+%! B = B';
+%! [AA, BB, Q, Z] = qz (A, B);
+%! [AAS, BBS, QS, ZS] = ordqz (AA, BB, Q, Z, "lhp");
+%! E2 = ordeig (AAS, BBS);
+%! ECOMP = [-3.414213562373092; -1.099019513592784;
+%!          -0.5857864376269046; 9.099019513592784];
+%! assert (norm (ECOMP - E2, "Inf"), 0, 1e-8);
+
+## Test input validation
+%!error <Invalid call> ordqz ()
+%!error <Invalid call> ordqz (eye (2))
+%!error <Invalid call> ordqz (eye (2), eye (2))
+%!error <Invalid call> ordqz (eye (2), eye (2), eye (2))
+%!error <Invalid call> ordqz (eye (2), eye (2), eye (2), eye (2))
+%!error id=Octave:ordqz:unknown-keyword
+%! ordqz (eye (2), eye (2), eye (2), eye (2), "foobar");
+%!error id=Octave:ordqz:select-not-vector
+%! ordqz (eye (2), eye (2), eye (2), eye (2), eye (2));
+%!error id=Octave:ordqz:unknown-arg
+%! ordqz (eye (2), eye (2), eye (2), eye (2), {"foobar"});
+%!error id=Octave:ordqz:nargout
+%! [a,b,c,d,e] = ordqz (eye (2), eye (2), eye (2), eye (2), "udi");
+%!warning <A: argument is empty matrix> ordqz ([], [], [], [], "udi");
+%!error <A must be a square matrix> ordqz (ones (1,2), [], [], [], "udi");
+%!error <nonconformant matrices>
+%! ordqz (eye (3), eye (2), eye (2), eye (2), "udi");
+%!error <nonconformant matrices>
+%! ordqz (eye (2), eye (3), eye (2), eye (2), "udi");
+%!error <nonconformant matrices>
+%! ordqz (eye (2), eye (2), eye (3), eye (2), "udi");
+%!error <nonconformant matrices>
+%! ordqz (eye (2), eye (2), eye (2), eye (3), "udi");
+%!error <SELECT vector .* wrong number of elements>
+%! ordqz (eye (2), eye (2), eye (2), eye (2), ones (1,5));
+%!error <quasi upper triangular matrices are not allowed with complex data>
+%! AA = zeros (2, 2);
+%! AA(2,1) = i;
+%! ordqz (AA, eye (2), eye (2), eye (2), "udi");
+
+*/
--- a/libinterp/corefcn/ordschur.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/ordschur.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -74,7 +74,7 @@
 [@var{U}, @var{S}] = ordschur (@var{U}, @var{S}, [0,1])
 @end example
 
-@seealso{schur, ordeig}
+@seealso{schur, ordeig, ordqz}
 @end deftypefn */)
 {
   if (args.length () != 3)
--- a/libinterp/corefcn/pager.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/pager.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -324,10 +324,8 @@
   {
     if (! m_flushing_output_to_pager)
       {
-        unwind_protect frame;
-
-        frame.protect_var (m_really_flush_to_pager);
-        frame.protect_var (m_flushing_output_to_pager);
+        unwind_protect_var<bool> restore_var1 (m_really_flush_to_pager);
+        unwind_protect_var<bool> restore_var2 (m_flushing_output_to_pager);
 
         m_really_flush_to_pager = true;
         m_flushing_output_to_pager = true;
--- a/libinterp/corefcn/pr-output.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/pr-output.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -1319,7 +1319,7 @@
 
 template <>
 float_display_format
-make_format (const Range& r)
+make_format (const octave::range<double>& r)
 {
   if (free_format)
     return float_display_format ();
@@ -2488,12 +2488,13 @@
 }
 
 void
-octave_print_internal (std::ostream& os, const Range& r,
+octave_print_internal (std::ostream& os, const octave::range<double>& r,
                        bool pr_as_read_syntax, int extra_indent)
 {
   double base = r.base ();
-  double increment = r.inc ();
+  double increment = r.increment ();
   double limit = r.limit ();
+  double final_value = r.final_value ();
   octave_idx_type num_elem = r.numel ();
 
   if (plus_format && ! pr_as_read_syntax)
@@ -2575,12 +2576,7 @@
                     val = base + i * increment;
 
                   if (i == num_elem - 1)
-                    {
-                      // See the comments in Range::matrix_value.
-                      if ((increment > 0 && val >= limit)
-                          || (increment < 0 && val <= limit))
-                        val = limit;
-                    }
+                    val = final_value;
 
                   os << "  ";
 
@@ -3608,7 +3604,7 @@
   frame.protect_var (Vcompact_format);
   frame.protect_var (uppercase_format);
   int prec = output_precision ();
-  frame.add ([prec] (void) { set_output_prec (prec); });
+  frame.add ([=] (void) { set_output_prec (prec); });
 
   format = format_string;   // Initialize with existing value
   while (argc-- > 0)
--- a/libinterp/corefcn/pr-output.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/pr-output.h	Thu Nov 19 13:08:00 2020 -0800
@@ -48,7 +48,6 @@
 class FloatDiagMatrix;
 class NDArray;
 class FloatNDArray;
-class Range;
 class boolMatrix;
 class boolNDArray;
 class charMatrix;
@@ -57,6 +56,11 @@
 class Cell;
 class octave_value;
 
+namespace octave
+{
+  template <typename T> class range;
+}
+
 template <typename T> class intNDArray;
 
 template <typename T>
@@ -91,7 +95,7 @@
 
 template <>
 float_display_format
-make_format (const Range& r);
+make_format (const octave::range<double>& r);
 
 template <>
 float_display_format
@@ -309,7 +313,7 @@
                        int extra_indent = 0);
 
 extern OCTINTERP_API void
-octave_print_internal (std::ostream& os, const Range& r,
+octave_print_internal (std::ostream& os, const octave::range<double>& r,
                        bool pr_as_read_syntax = false,
                        int extra_indent = 0);
 
--- a/libinterp/corefcn/psi.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/psi.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -175,7 +175,7 @@
 ## "Introduction to the Gamma Function"
 
 ## Interesting identities of the digamma function, in section of 5.1.3
-%!assert (psi (1/3), - em - (3/2) * log(3) - ((sqrt (3) / 6) * pi), eps*10)
+%!assert (psi (1/3), - em - (3/2) * log (3) - ((sqrt (3) / 6) * pi), eps*10)
 %!assert (psi (1/4), - em -3 * log (2) - pi/2, eps*10)
 %!assert (psi (1/6), - em -2 * log (2) - (3/2) * log (3) - ((sqrt (3) / 2) * pi), eps*10)
 
--- a/libinterp/corefcn/quad.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/quad.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -180,9 +180,7 @@
 
   warned_imaginary = false;
 
-  octave::unwind_protect frame;
-
-  frame.protect_var (call_depth);
+  octave::unwind_protect_var<int> restore_var (call_depth);
   call_depth++;
 
   if (call_depth > 1)
--- a/libinterp/corefcn/quadcc.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/quadcc.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -2242,9 +2242,9 @@
 %! assert (class (quadcc (@sin, single (0), single (1))), "single");
 
 ## Test input validation
-%!error (quadcc ())
-%!error (quadcc (@sin))
-%!error (quadcc (@sin, 0))
+%!error quadcc ()
+%!error quadcc (@sin)
+%!error quadcc (@sin, 0)
 %!error <lower limit .* must be a .* scalar> (quadcc (@sin, ones (2), pi))
 %!error <lower limit .* must be a real scalar> (quadcc (@sin, -i, pi))
 %!error <upper limit .* must be a .* scalar> (quadcc (@sin, 0, ones (2)))
--- a/libinterp/corefcn/qz.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/qz.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -162,9 +162,9 @@
 @end enumerate
 
 Note: @code{qz} performs permutation balancing, but not scaling
-(@pxref{XREFbalance,,balance}), which may be lead to less accurate results than
-@code{eig}.  The order of output arguments was selected for compatibility with
-@sc{matlab}.
+(@pxref{XREFbalance,,@code{balance}}), which may be lead to less accurate
+results than @code{eig}.  The order of output arguments was selected for
+compatibility with @sc{matlab}.
 @seealso{eig, ordeig, balance, lu, chol, hess, qr, qzhess, schur, svd}
 @end deftypefn */)
 {
--- a/libinterp/corefcn/rand.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/rand.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -117,10 +117,12 @@
   octave_value retval;
   dim_vector dims;
 
-  octave::unwind_protect frame;
   // Restore current distribution on any exit.
-  frame.add_fcn (octave::rand::distribution,
-                 octave::rand::distribution ());
+  octave::unwind_action restore_distribution
+    ([] (const std::string& old_distribution)
+     {
+       octave::rand::distribution (old_distribution);
+     }, octave::rand::distribution ());
 
   octave::rand::distribution (distribution);
 
@@ -181,7 +183,7 @@
           }
         else if (tmp.is_range ())
           {
-            Range r = tmp.range_value ();
+            octave::range<double> r = tmp.range_value ();
 
             if (! r.all_elements_are_ints ())
               error ("%s: all elements of range must be integers", fcn);
@@ -191,7 +193,7 @@
             dims.resize (n);
 
             octave_idx_type base = octave::math::nint_big (r.base ());
-            octave_idx_type incr = octave::math::nint_big (r.inc ());
+            octave_idx_type incr = octave::math::nint_big (r.increment ());
 
             for (octave_idx_type i = 0; i < n; i++)
               {
@@ -388,12 +390,14 @@
 @leq{} 625 for @var{v}.  This new state will be a hash based on the value of
 @var{v}, not @var{v} itself.
 
-By default, the generator is initialized from @code{/dev/urandom} if it is
-available, otherwise from CPU time, wall clock time, and the current
-fraction of a second.  Note that this differs from @sc{matlab}, which
-always initializes the state to the same state at startup.  To obtain
-behavior comparable to @sc{matlab}, initialize with a deterministic state
-vector in Octave's startup files (@pxref{Startup Files}).
+By default, the generator is initialized by contributing entropy from the
+wall clock time, the CPU time, the current fraction of a second, the process
+ID and---if available---up to 1024 bits from the C++ random numbers source
+@code{random_device}, which might be non-deterministic (implementation
+specific).  Note that this differs from @sc{matlab}, which always initializes
+the state to the same state at startup.  To obtain behavior comparable to
+@sc{matlab}, initialize with a deterministic state vector in Octave's startup
+files (@pxref{Startup Files}).
 
 To compute the pseudo-random sequence, @code{rand} uses the Mersenne
 Twister with a period of @math{2^{19937}-1}
--- a/libinterp/corefcn/regexp.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/regexp.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -1199,7 +1199,8 @@
 
 Search for @var{pat} in UTF-8 encoded @var{str} and return the positions and
 substrings of any matches, or empty values if there are none.
-@xref{XREFregexp,,regexp}, for details on the syntax of the search pattern.
+@xref{XREFregexp,,@code{regexp}}, for details on the syntax of the search
+pattern.
 @seealso{regexp}
 @end deftypefn */)
 {
@@ -1396,7 +1397,7 @@
 Replace occurrences of pattern @var{pat} in @var{string} with @var{repstr}.
 
 The pattern is a regular expression as documented for @code{regexp}.
-@xref{XREFregexp,,regexp}.
+@xref{XREFregexp,,@code{regexp}}.
 
 All strings must be UTF-8 encoded.
 
--- a/libinterp/corefcn/sighandlers.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/sighandlers.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -540,7 +540,7 @@
 %! debug_on_interrupt (orig_val);
 %! assert (debug_on_interrupt (), orig_val);
 
-%!error (debug_on_interrupt (1, 2))
+%!error debug_on_interrupt (1, 2)
 */
 
 DEFUN (sighup_dumps_octave_core, args, nargout,
@@ -571,7 +571,7 @@
 %! sighup_dumps_octave_core (orig_val);
 %! assert (sighup_dumps_octave_core (), orig_val);
 
-%!error (sighup_dumps_octave_core (1, 2))
+%!error sighup_dumps_octave_core (1, 2)
 */
 
 DEFUN (sigquit_dumps_octave_core, args, nargout,
@@ -602,7 +602,7 @@
 %! sigquit_dumps_octave_core (orig_val);
 %! assert (sigquit_dumps_octave_core (), orig_val);
 
-%!error (sigquit_dumps_octave_core (1, 2))
+%!error sigquit_dumps_octave_core (1, 2)
 */
 
 DEFUN (sigterm_dumps_octave_core, args, nargout,
@@ -633,5 +633,5 @@
 %! sigterm_dumps_octave_core (orig_val);
 %! assert (sigterm_dumps_octave_core (), orig_val);
 
-%!error (sigterm_dumps_octave_core (1, 2))
+%!error sigterm_dumps_octave_core (1, 2)
 */
--- a/libinterp/corefcn/sparse.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/sparse.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -101,8 +101,9 @@
 
 @strong{Note}: if multiple values are specified with the same @var{i},
 @var{j} indices, the corresponding value in @var{s} will be the sum of the
-values at the repeated location.  See @code{accumarray} for an example of
-how to produce different behavior, such as taking the minimum instead.
+values at the repeated location.  @xref{XREFaccumarray,,@code{accumarray}}, for
+an example of how to produce different behavior such as taking the minimum
+instead.
 
 If the option @qcode{"unique"} is given, and more than one value is
 specified at the same @var{i}, @var{j} indices, then the last specified
@@ -152,9 +153,7 @@
   octave_value retval;
 
   // Temporarily disable sparse_auto_mutate if set (it's obsolete anyway).
-  octave::unwind_protect frame;
-  frame.protect_var (Vsparse_auto_mutate);
-  Vsparse_auto_mutate = false;
+  octave::unwind_protect_var<bool> restore_var (Vsparse_auto_mutate, false);
 
   if (nargin == 1)
     {
@@ -244,7 +243,7 @@
 
 /*
 ## Tests for sparse constructor are in test/sparse.tst
-%!assert (1);
+%!assert (1)
 */
 
 DEFUN (spalloc, args, ,
--- a/libinterp/corefcn/stack-frame.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/stack-frame.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -1163,7 +1163,7 @@
 
     while (frame)
       {
-        octave::symbol_info_list symbols = frame->all_variables ();
+        symbol_info_list symbols = frame->all_variables ();
 
         octave_scalar_map ws;
 
--- a/libinterp/corefcn/stack-frame.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/stack-frame.h	Thu Nov 19 13:08:00 2020 -0800
@@ -474,15 +474,15 @@
         varref (sym).assign (op, type, idx, rhs);
     }
 
-    void do_non_const_unary_op (octave_value::unary_op op,
+    void non_const_unary_op (octave_value::unary_op op,
                                 const symbol_record& sym,
                                 const std::string& type,
                                 const std::list<octave_value_list>& idx)
     {
       if (idx.empty ())
-        varref (sym).do_non_const_unary_op (op);
+        varref (sym).non_const_unary_op (op);
       else
-        varref (sym).do_non_const_unary_op (op, type, idx);
+        varref (sym).non_const_unary_op (op, type, idx);
     }
 
     octave_value value (const symbol_record& sym, const std::string& type,
--- a/libinterp/corefcn/strfind.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/strfind.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -418,17 +418,18 @@
   if (nargin == 5)
     {
       if (! args(3).is_string () || ! args(4).is_scalar_type ())
-        error ("strrep: invalid optional arguments");
+        error ("strrep: invalid optional argument");
 
       std::string opt = args(3).string_value ();
-      if (opt == "overlaps")
-        overlaps = args(4).bool_value ();
-      else
+      if (opt != "overlaps")
         error ("strrep: unknown option: %s", opt.c_str ());
+
+      overlaps = args(4).bool_value ();
     }
 
   octave_value retval;
 
+  // Aliasing for better code readability
   octave_value argstr = args(0);
   octave_value argpat = args(1);
   octave_value argrep = args(2);
@@ -442,25 +443,42 @@
       qs_preprocess (pat, table);
 
       if (argstr.is_string ())
-        retval = qs_replace (argstr.char_array_value (), pat, rep,
-                             table, overlaps);
+        if (argstr.rows () == 1)  // most common case of a single string
+          retval = qs_replace (argstr.char_array_value (), pat, rep,
+                               table, overlaps);
+        else
+          {
+            const charMatrix argchm = argstr.char_matrix_value ();
+            octave_idx_type nel = argchm.rows ();
+            octave_idx_type nc = argchm.columns ();
+            charMatrix retchm (nel, 0);
+
+            for (octave_idx_type i = 0; i < nel; i++)
+              {
+                charMatrix rowchm;
+                rowchm = qs_replace (argchm.extract (i, 0, i, nc-1),
+                                     pat, rep, table, overlaps);
+                retchm.insert (rowchm, i, 0);
+              }
+
+            retval = retchm;
+          }
       else if (argstr.iscell ())
         {
-          const Cell argsc = argstr.cell_value ();
-          Cell retc (argsc.dims ());
-          octave_idx_type ns = argsc.numel ();
+          const Cell argcell = argstr.cell_value ();
+          if (! argcell.iscellstr ())
+            error ("strrep: each element of S must be a string");
 
-          for (octave_idx_type i = 0; i < ns; i++)
+          Cell retcell (argcell.dims ());
+          octave_idx_type nel = argcell.numel ();
+
+          for (octave_idx_type i = 0; i < nel; i++)
             {
-              octave_value argse = argsc(i);
-              if (argse.is_string ())
-                retc(i) = qs_replace (argse.char_array_value (), pat, rep,
-                                      table, overlaps);
-              else
-                error ("strrep: each element of S must be a string");
+              retcell(i) = qs_replace (argcell(i).char_array_value (),
+                                       pat, rep, table, overlaps);
             }
 
-          retval = retc;
+          retval = retcell;
         }
       else
         error ("strrep: S must be a string or cell array of strings");
@@ -478,9 +496,23 @@
 %!                "Th&%$ &%$ a test string")
 %!assert (strrep ("abababc", "abab", "xyz"), "xyzxyzc")
 %!assert (strrep ("abababc", "abab", "xyz", "overlaps", false), "xyzabc")
+%!assert (strrep ({"Hello World"; "Goodbye World"}, "World", "Jane"),
+%!                {"Hello Jane"; "Goodbye Jane"})
+%!assert (strrep (char ("Hello World", "Goodbye World"), "World", "Jane"),
+%!                char ("Hello Jane", "Goodbye Jane"))
 
 %!assert (size (strrep ("a", "a", "")), [0 0])
 
 %!error strrep ()
-%!error strrep ("foo", "bar", 3, 4)
+%!error strrep ("A")
+%!error strrep ("A", "B")
+%!error strrep ("A", "B", "C", "D")
+%!error strrep ("A", "B", "C", "D", "E", "F")
+%!error <invalid optional argument> strrep ("A", "B", "C", 3, true)
+%!error <invalid optional argument> strrep ("A", "B", "C", "str", ones (2,2))
+%!error <unknown option: foobar> strrep ("A", "B", "C", "foobar", true)
+%!error <each element of S must be a string> strrep ({"A", 1.0}, "B", "C")
+%!error <S must be a string or cell array of strings> strrep (1.0, "B", "C")
+%!error <PTN and REP arguments must be strings> strrep ("A", 1.0, "C")
+%!error <PTN and REP arguments must be strings> strrep ("A", "B", 1.0)
 */
--- a/libinterp/corefcn/strfns.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/strfns.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -870,7 +870,7 @@
 %!assert (str2double (zeros (3,1,2)), NaN)
 %!assert (str2double (''), NaN)
 %!assert (str2double ([]), NaN)
-%!assert (str2double (char(zeros(3,0))), NaN)
+%!assert (str2double (char (zeros (3,0))), NaN)
 */
 
 DEFUN (__native2unicode__, args, ,
@@ -881,9 +881,7 @@
 @seealso{native2unicode, __unicode2native__}
 @end deftypefn */)
 {
-  int nargin = args.length ();
-
-  if (nargin != 2)
+  if (args.length () != 2)
     print_usage ();
 
   if (args(0).is_string ())
@@ -901,8 +899,6 @@
   size_t length;
   uint8_t *utf8_str = nullptr;
 
-  octave::unwind_protect frame;
-
   utf8_str = octave_u8_conv_from_encoding (codepage, src, srclen, &length);
 
   if (! utf8_str)
@@ -915,7 +911,7 @@
                codepage, std::strerror (errno));
     }
 
-  frame.add_fcn (::free, static_cast<void *> (utf8_str));
+  octave::unwind_action free_utf8_str ([=] () { ::free (utf8_str); });
 
   octave_idx_type len = length;
 
@@ -936,9 +932,7 @@
 @seealso{unicode2native, __native2unicode__}
 @end deftypefn */)
 {
-  int nargin = args.length ();
-
-  if (nargin != 2)
+  if (args.length () != 2)
     print_usage ();
 
   std::string tmp = args(1).string_value ();
@@ -953,8 +947,6 @@
   size_t length;
   char *native_bytes = nullptr;
 
-  octave::unwind_protect frame;
-
   native_bytes = octave_u8_conv_to_encoding (codepage, src, srclen, &length);
 
   if (! native_bytes)
@@ -967,7 +959,7 @@
                codepage, std::strerror (errno));
     }
 
-  frame.add_fcn (::free, static_cast<void *> (native_bytes));
+  octave::unwind_action free_native_bytes ([=] () { ::free (native_bytes); });
 
   octave_idx_type len = length;
 
@@ -1005,9 +997,7 @@
 
 @end deftypefn */)
 {
-  int nargin = args.length ();
-
-  if (nargin != 1)
+  if (args.length () != 1)
     print_usage ();
 
   charNDArray str = args(0).xchar_array_value ("STR must be a string");
@@ -1042,7 +1032,7 @@
 }
 
 /*
-%!assert (unicode_idx (["aäou"; "Ä∞"]), [1 2 2 3 4; 5 5 6 6 6]);
+%!assert (unicode_idx (["aäou"; "Ä∞"]), [1 2 2 3 4; 5 5 6 6 6])
 */
 
 DEFUN (__u8_validate__, args, ,
@@ -1051,23 +1041,24 @@
 Return string with valid UTF-8.
 
 On encountering invalid UTF-8 in @var{in_str}, the bytes are either replaced by
-the replacement character "�" (if @var{mode} is omitted or the string
-"replace") or interpreted as the Unicode code points U+0080–U+00FF with the
-same value as the byte (if @var{mode} is the string "unicode"), thus
-interpreting the bytes according to ISO-8859-1.
-
+the replacement character @qcode{"�"} (if @var{mode} is omitted or is the
+string @qcode{"replace"}) or interpreted as the Unicode code points
+U+0080–U+00FF with the same value as the byte (if @var{mode} is the string
+@qcode{"unicode"}), thus interpreting the bytes according to ISO-8859-1.
 @end deftypefn */)
 {
-  if (args.length () < 1 || args.length () > 2)
+  int nargin = args.length ();
+
+  if (nargin < 1 || nargin > 2)
     print_usage ();
 
   // Input check
   std::string in_str =
-      args(0).xstring_value ("__u8_validate__: IN_STR must be a string.");
+    args(0).xstring_value ("__u8_validate__: IN_STR must be a string");
 
   std::string mode = "replace";
-  if (args.length () > 1)
-    mode = args(1).xstring_value ("__u8_validate__: MODE must be a string.");
+  if (nargin == 2)
+    mode = args(1).xstring_value ("__u8_validate__: MODE must be a string");
 
   octave::string::u8_fallback_type fb_type;
   if (mode == "replace")
@@ -1075,7 +1066,7 @@
   else if (mode == "unicode")
     fb_type = octave::string::U8_ISO_8859_1;
   else
-    error ("__u8_validate__: MODE must either be \"replace\" or \"unicode\".");
+    error (R"(__u8_validate__: MODE must be either "replace" or "unicode")");
 
   octave::string::u8_validate ("__u8_validate__", in_str, fb_type);
 
@@ -1115,6 +1106,8 @@
 %!assert (newline (), "\n")
 
 %!error newline (1)
+## FIXME: The next error() test requires a semicolon at EOL until
+##        bug #59265 is resolved.
 %!error [a, b] = newline ();
 */
 
--- a/libinterp/corefcn/sub2ind.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/sub2ind.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -68,8 +68,8 @@
 Convert subscripts to linear indices.
 
 The input @var{dims} is a dimension vector where each element is the size of
-the array in the respective dimension (@pxref{XREFsize,,size}).  The remaining
-inputs are scalars or vectors of subscripts to be converted.
+the array in the respective dimension (@pxref{XREFsize,,@code{size}}).  The
+remaining inputs are scalars or vectors of subscripts to be converted.
 
 The output vector @var{ind} contains the converted linear indices.
 
@@ -193,8 +193,8 @@
 Convert linear indices to subscripts.
 
 The input @var{dims} is a dimension vector where each element is the size of
-the array in the respective dimension (@pxref{XREFsize,,size}).  The second
-input @var{ind} contains linear indies to be converted.
+the array in the respective dimension (@pxref{XREFsize,,@code{size}}).  The
+second input @var{ind} contains linear indies to be converted.
 
 The outputs @var{s1}, @dots{}, @var{sN} contain the converted subscripts.
 
@@ -313,7 +313,7 @@
 %! r = ind2sub ([2, 2, 2], 1:8);
 %! assert (r, 1:8);
 
-%!error <DIMS must contain integers> ind2sub ([2, -2], 3);
-%!error <index out of range> ind2sub ([2, 2, 2], 1:9);
-%!error <invalid index> ind2sub ([2, 2, 2], -1:8);
+%!error <DIMS must contain integers> ind2sub ([2, -2], 3)
+%!error <index out of range> ind2sub ([2, 2, 2], 1:9)
+%!error <invalid index> ind2sub ([2, 2, 2], -1:8)
 */
--- a/libinterp/corefcn/symscope.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/symscope.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -116,7 +116,7 @@
             if (! fcn)
               continue;
 
-            octave::symbol_scope scope = fcn->scope ();
+            symbol_scope scope = fcn->scope ();
 
             std::list<std::string> plst = scope.parent_fcn_names ();
 
@@ -211,7 +211,7 @@
   void
   symbol_scope_rep::cache_dir_name (const std::string& name)
   {
-    m_dir_name = octave::sys::canonicalize_file_name (name);
+    m_dir_name = sys::canonicalize_file_name (name);
   }
 
   bool
--- a/libinterp/corefcn/syscalls.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/syscalls.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -377,9 +377,10 @@
 
 */
 
-DEFMETHODX ("fcntl", Ffcntl, interp, args, ,
+DEFMETHODX ("fcntl", Ffcntl, interp, args, nargout,
             doc: /* -*- texinfo -*-
-@deftypefn {} {[@var{err}, @var{msg}] =} fcntl (@var{fid}, @var{request}, @var{arg})
+@deftypefn  {} {} fcntl (@var{fid}, @var{request}, @var{arg})
+@deftypefnx {} {[@var{status}, @var{msg}] =} fcntl (@var{fid}, @var{request}, @var{arg})
 Change the properties of the open file @var{fid}.
 
 The following values may be passed as @var{request}:
@@ -430,8 +431,8 @@
 @w{@code{O_NONBLOCK}}.
 @end vtable
 
-If successful, @var{err} is 0 and @var{msg} is an empty string.  Otherwise,
-@var{err} is nonzero and @var{msg} contains a system-dependent error
+If successful, @var{status} is 0 and @var{msg} is an empty string.  Otherwise,
+@var{status} is -1 and @var{msg} contains a system-dependent error
 message.
 @seealso{fopen, dup2}
 @end deftypefn */)
@@ -454,11 +455,25 @@
   if (fid < 0)
     error ("fcntl: invalid file id");
 
+  octave_value_list retval;
   std::string msg;
 
   int status = octave::sys::fcntl (fid, req, arg, msg);
 
-  return ovl (status, msg);
+  if (nargout == 0)
+    {
+      if (status < 0)
+        error ("fcntl: operation failed: %s", msg.c_str ());
+    }
+  else
+    {
+      if (status < 0)
+        retval = ovl (-1.0, msg);
+      else
+        retval = ovl (0.0, "");
+    }
+
+  return retval;
 }
 
 DEFMETHODX ("fork", Ffork, interp, args, ,
@@ -591,26 +606,29 @@
   return ovl (octave::sys::getuid ());
 }
 
-DEFUNX ("kill", Fkill, args, ,
+DEFUNX ("kill", Fkill, args, nargout,
         doc: /* -*- texinfo -*-
-@deftypefn {} {[@var{err}, @var{msg}] =} kill (@var{pid}, @var{sig})
+@deftypefn  {} {} kill (@var{pid}, @var{sig})
+@deftypefnx {} {[@var{status}, @var{msg}] =} kill (@var{pid}, @var{sig})
 Send signal @var{sig} to process @var{pid}.
 
 If @var{pid} is positive, then signal @var{sig} is sent to @var{pid}.
 
-If @var{pid} is 0, then signal @var{sig} is sent to every process
-in the process group of the current process.
+If @var{pid} is 0, then signal @var{sig} is sent to every process in the
+process group of the current process.
 
-If @var{pid} is -1, then signal @var{sig} is sent to every process
-except process 1.
+If @var{pid} is -1, then signal @var{sig} is sent to every process except
+process 1.
 
-If @var{pid} is less than -1, then signal @var{sig} is sent to every
-process in the process group @var{-pid}.
+If @var{pid} is less than -1, then signal @var{sig} is sent to every process in
+the process group @var{-pid}.
 
 If @var{sig} is 0, then no signal is sent, but error checking is still
 performed.
 
-Return 0 if successful, otherwise return -1.
+If successful, @var{status} is 0 and @var{msg} is an empty string.
+Otherwise, @var{status} is -1 and @var{msg} contains a system-dependent
+error message.
 @end deftypefn */)
 {
   if (args.length () != 2)
@@ -620,11 +638,25 @@
 
   int sig = args(1).int_value (true);
 
+  octave_value_list retval;
   std::string msg;
 
   int status = octave::sys::kill (pid, sig, msg);
 
-  return ovl (status, msg);
+  if (nargout == 0)
+    {
+      if (status < 0)
+        error ("kill: operation failed: %s", msg.c_str ());
+    }
+  else
+    {
+      if (status < 0)
+        retval = ovl (-1.0, msg);
+      else
+        retval = ovl (0.0, "");
+    }
+
+  return retval;
 }
 
 DEFUNX ("lstat", Flstat, args, ,
@@ -676,17 +708,17 @@
   return retval;
 }
 
-DEFUNX ("mkfifo", Fmkfifo, args, ,
+DEFUNX ("mkfifo", Fmkfifo, args, nargout,
         doc: /* -*- texinfo -*-
-@deftypefn  {} {@var{err} =} mkfifo (@var{name}, @var{mode})
-@deftypefnx {} {[@var{err}, @var{msg}] =} mkfifo (@var{name}, @var{mode})
+@deftypefn  {} {} mkfifo (@var{name}, @var{mode})
+@deftypefnx {} {[@var{status}, @var{msg}] =} mkfifo (@var{name}, @var{mode})
 Create a FIFO special file named @var{name} with file mode @var{mode}.
 
 @var{mode} is interpreted as an octal number and is subject to umask
 processing.  The final calculated mode is @code{@var{mode} - @var{umask}}.
 
-If successful, @var{err} is 0 and @var{msg} is an empty string.
-Otherwise, @var{err} is nonzero and @var{msg} contains a system-dependent
+If successful, @var{status} is 0 and @var{msg} is an empty string.
+Otherwise, @var{status} is -1 and @var{msg} contains a system-dependent
 error message.
 @seealso{pipe, umask}
 @end deftypefn */)
@@ -703,11 +735,25 @@
 
   int mode = convert (octal_mode, 8, 10);
 
+  octave_value_list retval;
   std::string msg;
 
   int status = octave::sys::mkfifo (name, mode, msg);
 
-  return ovl (status, msg);
+  if (nargout == 0)
+    {
+      if (status < 0)
+        error ("mkfifo: operation failed: %s", msg.c_str ());
+    }
+  else
+    {
+      if (status < 0)
+        retval = ovl (-1.0, msg);
+      else
+        retval = ovl (0.0, "");
+    }
+
+  return retval;
 }
 
 /*
@@ -1073,13 +1119,14 @@
 %! endif
 */
 
-DEFMETHODX ("unlink", Funlink, interp, args, ,
+DEFMETHODX ("unlink", Funlink, interp, args, nargout,
             doc: /* -*- texinfo -*-
-@deftypefn {} {[@var{err}, @var{msg}] =} unlink (@var{file})
+@deftypefn  {} {} unlink (@var{file})
+@deftypefnx {} {[@var{status}, @var{msg}] =} unlink (@var{file})
 Delete the file named @var{file}.
 
-If successful, @var{err} is 0 and @var{msg} is an empty string.
-Otherwise, @var{err} is nonzero and @var{msg} contains a system-dependent
+If successful, @var{status} is 0 and @var{msg} is an empty string.
+Otherwise, @var{status} is -1 and @var{msg} contains a system-dependent
 error message.
 @seealso{delete, rmdir}
 @end deftypefn */)
@@ -1089,6 +1136,7 @@
 
   std::string name = args(0).xstring_value ("unlink: FILE must be a string");
 
+  octave_value_list retval;
   std::string msg;
 
   octave::event_manager& evmgr = interp.get_event_manager ();
@@ -1099,7 +1147,20 @@
 
   evmgr.file_renamed (status == 0);
 
-  return ovl (status, msg);
+  if (nargout == 0)
+    {
+      if (status < 0)
+        error ("unlink: operation failed: %s", msg.c_str ());
+    }
+  else
+    {
+      if (status < 0)
+        retval = ovl (-1.0, msg);
+      else
+        retval = ovl (0.0, "");
+    }
+
+  return retval;
 }
 
 /*
@@ -1111,13 +1172,13 @@
 %! endif
 %! fdisp (fid, pi);
 %! fclose (fid);
-%! [err, msg] = unlink (file);
-%! assert (err, 0);
+%! [status, msg] = unlink (file);
+%! assert (status, 0);
 %! assert (msg, "");
 
 ## Test input validation
-%!error unlink ()
-%!error unlink ("a", "b")
+%!error <Invalid call> unlink ()
+%!error <Invalid call> unlink ("a", "b")
 %!error <FILE must be a string> unlink (123)
 */
 
--- a/libinterp/corefcn/sysdep.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/sysdep.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -97,6 +97,7 @@
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 #include <tlhelp32.h>
+#include <psapi.h>
 #include <shellapi.h>
 
 #endif
@@ -225,7 +226,7 @@
   return octave_value (reinterpret_cast<ptrdiff_t> (status) > 32);
 #else
   // Quote file path
-  file = "\"" + file + "\"";
+  file = '"' + file + '"';
 
 #  if defined (__APPLE__)
 #    define FSYSTEM_OPEN_STR "open "
@@ -246,10 +247,10 @@
 
 DEFUN (__is_elevated_process__, args, ,
        doc: /* -*- texinfo -*-
-@deftypefn  {} {@var{retval} =} __is_elevated_process__ ()
+@deftypefn {} {@var{retval} =} __is_elevated_process__ ()
 Check if current process has elevated rights.
 
-On Windows, return true if the current process has elevated right. Otherwise,
+On Windows, return true if the current process has elevated right.  Otherwise,
 return false.
 On non-Windows platforms, this function fails with an error.
 @end deftypefn */)
@@ -282,6 +283,101 @@
 #endif
 }
 
+DEFUN (__wmemory__, args, ,
+       doc: /* -*- texinfo -*-
+@deftypefn {} {[@var{proc}, @var{sys}] =} __wmemory__ ()
+Return memory information on Windows.
+
+On non-Windows platforms, this function fails with an error.
+@end deftypefn */)
+{
+#if defined (OCTAVE_USE_WINDOWS_API)
+  if (args.length () != 0)
+    print_usage ();
+
+  // Get memory usage of the current process
+  octave_scalar_map proc_struct;
+
+  HANDLE h_proc = GetCurrentProcess ();
+  if (h_proc == nullptr)
+    error ("__wmemory__: Couldn't open handle to own process");
+
+  PROCESS_MEMORY_COUNTERS proc_mem_count;
+  if (GetProcessMemoryInfo (h_proc, &proc_mem_count, sizeof (proc_mem_count)))
+    {
+      proc_struct.setfield ("PageFaultCount",
+                            proc_mem_count.PageFaultCount);
+      proc_struct.setfield ("PeakWorkingSetSize",
+                            proc_mem_count.PeakWorkingSetSize);
+      proc_struct.setfield ("WorkingSetSize",
+                            proc_mem_count.WorkingSetSize);
+      proc_struct.setfield ("QuotaPeakPagedPoolUsage",
+                            proc_mem_count.QuotaPeakPagedPoolUsage);
+      proc_struct.setfield ("QuotaPagedPoolUsage",
+                            proc_mem_count.QuotaPagedPoolUsage);
+      proc_struct.setfield ("QuotaPeakNonPagedPoolUsage",
+                            proc_mem_count.QuotaPeakNonPagedPoolUsage);
+      proc_struct.setfield ("QuotaNonPagedPoolUsage",
+                            proc_mem_count.QuotaNonPagedPoolUsage);
+      proc_struct.setfield ("PagefileUsage",
+                            proc_mem_count.PagefileUsage);
+      proc_struct.setfield ("PeakPagefileUsage",
+                            proc_mem_count.PeakPagefileUsage);
+    }
+  else
+    {
+      proc_struct.setfield ("PageFaultCount", 0);
+      proc_struct.setfield ("PeakWorkingSetSize", 0);
+      proc_struct.setfield ("WorkingSetSize", 0);
+      proc_struct.setfield ("QuotaPeakPagedPoolUsage", 0);
+      proc_struct.setfield ("QuotaPagedPoolUsage", 0);
+      proc_struct.setfield ("QuotaPeakNonPagedPoolUsage", 0);
+      proc_struct.setfield ("QuotaNonPagedPoolUsage", 0);
+      proc_struct.setfield ("PagefileUsage", 0);
+      proc_struct.setfield ("PeakPagefileUsage", 0);
+    }
+
+  CloseHandle (h_proc);
+
+  // Get system memory usage
+  octave_scalar_map sys_struct;
+
+  MEMORYSTATUSEX mem_stat;
+
+  mem_stat.dwLength = sizeof (mem_stat);
+
+  if (GlobalMemoryStatusEx (&mem_stat))
+    {
+      sys_struct.setfield ("MemoryLoad", mem_stat.dwMemoryLoad);
+      sys_struct.setfield ("TotalPhys", mem_stat.ullTotalPhys);
+      sys_struct.setfield ("AvailPhys", mem_stat.ullAvailPhys);
+      sys_struct.setfield ("TotalPageFile", mem_stat.ullTotalPageFile);
+      sys_struct.setfield ("AvailPageFile", mem_stat.ullAvailPageFile);
+      sys_struct.setfield ("TotalVirtual", mem_stat.ullTotalVirtual);
+      sys_struct.setfield ("AvailVirtual", mem_stat.ullAvailVirtual);
+      sys_struct.setfield ("AvailExtendedVirtual",
+                           mem_stat.ullAvailExtendedVirtual);
+    }
+  else
+    {
+      sys_struct.setfield ("MemoryLoad", 0);
+      sys_struct.setfield ("TotalPhys", 0);
+      sys_struct.setfield ("AvailPhys", 0);
+      sys_struct.setfield ("TotalPageFile", 0);
+      sys_struct.setfield ("AvailPageFile", 0);
+      sys_struct.setfield ("TotalVirtual", 0);
+      sys_struct.setfield ("AvailVirtual", 0);
+      sys_struct.setfield ("AvailExtendedVirtual", 0);
+    }
+
+  return ovl (proc_struct, sys_struct);
+
+#else
+  octave_unused_parameter (args);
+  error ("__wmemory__: Function is only supported on Windows platforms");
+#endif
+}
+
 namespace octave
 {
 #if defined (__MINGW32__)
@@ -392,11 +488,11 @@
     if (len > 4 && name[0] == '\\' && name[1] == '\\')
       {
         // It starts with two slashes.  Find the next slash.
-        size_t next_slash = name.find ("\\", 3);
+        size_t next_slash = name.find ('\\', 3);
         if (next_slash != std::string::npos && len > next_slash+1)
           {
             // Check if it ends with the share
-            size_t last_slash = name.find ("\\", next_slash+1);
+            size_t last_slash = name.find ('\\', next_slash+1);
             if (last_slash == std::string::npos
                 || (len > next_slash+2 && last_slash == len-1))
               candidate = true;
@@ -622,9 +718,11 @@
     wchar_t *wcommand = u8_to_wchar (command);
     wchar_t *wmode = u8_to_wchar (mode);
 
-    unwind_protect frame;
-    frame.add_fcn (::free, static_cast<void *> (wcommand));
-    frame.add_fcn (::free, static_cast<void *> (wmode));
+    unwind_action free_memory ([=] ()
+                               {
+                                 ::free (wcommand);
+                                 ::free (wmode);
+                               });
 
     if (wmode && wmode[0] && ! wmode[1])
       {
@@ -865,9 +963,7 @@
     if (result != ERROR_SUCCESS)
       return result;
 
-    unwind_protect frame;
-
-    frame.add_fcn (reg_close_key_wrapper, h_subkey);
+    unwind_action restore_keys ([=] () { reg_close_key_wrapper (h_subkey); });
 
     std::wstring wname = sys::u8_to_wstring (name);
     DWORD length = 0;
@@ -1074,7 +1170,7 @@
       LONG retval = octave::get_regkey_value (h_rootkey, subkey_name,
                                               value_name, key_val);
       if (retval == ERROR_FILE_NOT_FOUND)
-        error ("winqueryreg: no value found for '%s' at %s\\%s.",
+        error ("winqueryreg: no value found for '%s' at %s\\%s",
                value_name.c_str (), rootkey_name.c_str (),
                subkey_name.c_str ());
       if (retval != ERROR_SUCCESS)
@@ -1253,7 +1349,7 @@
       else if (state == "query")
         ;// Do nothing
       else
-        error ("pause: first argument must be \"on\", \"off\" or \"query\"");
+        error (R"(pause: first argument must be "on", "off", or "query")");
 
       if (nargout > 0 || state == "query")
         retval.append (saved_state ? "on" : "off");
@@ -1284,7 +1380,7 @@
 %!test
 %! pause (1);
 
-%!error (pause (1, 2))
+%!error pause (1, 2)
 */
 
 // FIXME: maybe this should only return 1 if IEEE floating
--- a/libinterp/corefcn/sysdep.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/sysdep.h	Thu Nov 19 13:08:00 2020 -0800
@@ -59,71 +59,4 @@
   extern OCTINTERP_API bool drive_or_unc_share (const std::string&);
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (5, "use 'octave::sysdep_init' instead")
-inline void
-sysdep_init (void)
-{
-  octave::sysdep_init ();
-}
-
-OCTAVE_DEPRECATED (5, "use 'octave::set_application_id' instead")
-inline void
-set_application_id (void)
-{
-  octave::set_application_id ();
-}
-
-OCTAVE_DEPRECATED (5, "use 'octave::sysdep_cleanup' instead")
-inline void
-sysdep_cleanup (void)
-{
-  octave::sysdep_cleanup ();
-}
-
-OCTAVE_DEPRECATED (5, "use 'octave::raw_mode' instead")
-inline void
-raw_mode (bool on, bool wait = true)
-{
-  octave::raw_mode (on, wait);
-}
-
-OCTAVE_DEPRECATED (5, "use 'octave::popen' instead")
-inline FILE *
-octave_popen (const char *command, const char *mode)
-{
-  return octave::popen (command, mode);
-}
-
-OCTAVE_DEPRECATED (5, "use 'octave::pclose' instead")
-inline int
-octave_pclose (FILE *f)
-{
-  return octave::pclose (f);
-}
-
-OCTAVE_DEPRECATED (5, "use 'octave::kbhit' instead")
-inline int
-octave_kbhit (bool wait = true)
-{
-  return octave::kbhit (wait);
-}
-
-OCTAVE_DEPRECATED (5, "use 'octave::get_P_tmpdir' instead")
-inline std::string
-get_P_tmpdir (void)
-{
-  return octave::get_P_tmpdir ();
-}
-
-OCTAVE_DEPRECATED (5, "use 'octave::same_file_internal' instead")
-inline bool
-same_file_internal (const std::string& a, const std::string& b)
-{
-  return octave::same_file_internal (a, b);
-}
-
 #endif
-
-#endif
--- a/libinterp/corefcn/text-engine.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/text-engine.h	Thu Nov 19 13:08:00 2020 -0800
@@ -459,53 +459,4 @@
   }
 }
 
-#if defined (OCAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (5, "use 'octave::text_element' instead")
-typedef octave::text_element text_element;
-
-OCTAVE_DEPRECATED (5, "use 'octave::text_element_string' instead")
-typedef octave::text_element_string text_element_string;
-
-OCTAVE_DEPRECATED (5, "use 'octave::text_element_symbol' instead")
-typedef octave::text_element_symbol text_element_symbol;
-
-OCTAVE_DEPRECATED (5, "use 'octave::text_element_list' instead")
-typedef octave::text_element_list text_element_list;
-
-OCTAVE_DEPRECATED (5, "use 'octave::text_element_subscript' instead")
-typedef octave::text_element_subscript text_element_subscript;
-
-OCTAVE_DEPRECATED (5, "use 'octave::text_element_superscript' instead")
-typedef octave::text_element_superscript text_element_superscript;
-
-OCTAVE_DEPRECATED (5, "use 'octave::text_element_combined' instead")
-typedef octave::text_element_combined text_element_combined;
-
-OCTAVE_DEPRECATED (5, "use 'octave::text_element_fontstyle' instead")
-typedef octave::text_element_fontstyle text_element_fontstyle;
-
-OCTAVE_DEPRECATED (5, "use 'octave::text_element_fontname' instead")
-typedef octave::text_element_fontname text_element_fontname;
-
-OCTAVE_DEPRECATED (5, "use 'octave::text_element_fontsize' instead")
-typedef octave::text_element_fontsize text_element_fontsize;
-
-OCTAVE_DEPRECATED (5, "use 'octave::text_element_color' instead")
-typedef octave::text_element_color text_element_color;
-
-OCTAVE_DEPRECATED (5, "use 'octave::text_processor' instead")
-typedef octave::text_processor text_processor;
-
-OCTAVE_DEPRECATED (5, "use 'octave::text_parser' instead")
-typedef octave::text_parser text_parser;
-
-OCTAVE_DEPRECATED (5, "use 'octave::text_parser_none' instead")
-typedef octave::text_parser_none text_parser_none;
-
-OCTAVE_DEPRECATED (5, "use 'octave::text_parser_tex' instead")
-typedef octave::text_parser_tex text_parser_tex;
-
 #endif
-
-#endif
--- a/libinterp/corefcn/toplev.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/toplev.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -281,9 +281,8 @@
     cmd_str = '"' + cmd_str + '"';
 #endif
 
-  octave::unwind_protect frame;
-
-  frame.add_fcn (restore_signal_mask, get_signal_mask ());
+  octave::unwind_action restore_mask
+    ([] (void *mask) { restore_signal_mask (mask); }, get_signal_mask ());
 
   octave_unblock_async_signals ();
   octave_unblock_signal_by_name ("SIGTSTP");
--- a/libinterp/corefcn/tril.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/tril.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -209,8 +209,10 @@
   dim_vector dims = arg.dims ();
   if (dims.ndims () != 2)
     error ("%s: need a 2-D matrix", name.c_str ());
-  else if (k < -dims(0) || k > dims(1))
-    error ("%s: requested diagonal out of range", name.c_str ());
+  else if (k < -dims(0))
+    k = -dims(0);
+  else if (k > dims(1))
+    k = dims(1);
 
   octave_value retval;
 
@@ -284,11 +286,11 @@
         octave_value_list ov_idx;
         std::list<octave_value_list> idx_tmp;
         ov_idx(1) = static_cast<double> (nc+1);
-        ov_idx(0) = Range (1, nr);
+        ov_idx(0) = octave::range<double> (1, nr);
         idx_tmp.push_back (ov_idx);
         ov_idx(1) = static_cast<double> (nc);
         tmp = tmp.resize (dim_vector (0,0));
-        tmp = tmp.subsasgn ("(", idx_tmp, arg.do_index_op (ov_idx));
+        tmp = tmp.subsasgn ("(", idx_tmp, arg.index_op (ov_idx));
         tmp = tmp.resize (dims);
 
         if (lower)
@@ -299,11 +301,11 @@
               {
                 octave_idx_type nr_limit = (1 > j - k ? 1 : j - k);
                 ov_idx(1) = static_cast<double> (j);
-                ov_idx(0) = Range (nr_limit, nr);
+                ov_idx(0) = octave::range<double> (nr_limit, nr);
                 std::list<octave_value_list> idx;
                 idx.push_back (ov_idx);
 
-                tmp = tmp.subsasgn ("(", idx, arg.do_index_op (ov_idx));
+                tmp = tmp.subsasgn ("(", idx, arg.index_op (ov_idx));
               }
           }
         else
@@ -314,11 +316,11 @@
               {
                 octave_idx_type nr_limit = (nr < j - k ? nr : j - k);
                 ov_idx(1) = static_cast<double> (j);
-                ov_idx(0) = Range (1, nr_limit);
+                ov_idx(0) = octave::range<double> (1, nr_limit);
                 std::list<octave_value_list> idx;
                 idx.push_back (ov_idx);
 
-                tmp = tmp.subsasgn ("(", idx, arg.do_index_op (ov_idx));
+                tmp = tmp.subsasgn ("(", idx, arg.index_op (ov_idx));
               }
           }
 
@@ -428,24 +430,51 @@
 }
 
 /*
-%!test
+%!shared a, l2, l1, l0, lm1, lm2, lm3, lm4
 %! a = [1, 2, 3; 4, 5, 6; 7, 8, 9; 10, 11, 12];
 %!
-%! l0 = [1, 0, 0; 4, 5, 0; 7, 8, 9; 10, 11, 12];
+%! l2 = [1, 2, 3; 4, 5, 6; 7, 8, 9; 10, 11, 12];
 %! l1 = [1, 2, 0; 4, 5, 6; 7, 8, 9; 10, 11, 12];
-%! l2 = [1, 2, 3; 4, 5, 6; 7, 8, 9; 10, 11, 12];
+%! l0 = [1, 0, 0; 4, 5, 0; 7, 8, 9; 10, 11, 12];
 %! lm1 = [0, 0, 0; 4, 0, 0; 7, 8, 0; 10, 11, 12];
 %! lm2 = [0, 0, 0; 0, 0, 0; 7, 0, 0; 10, 11, 0];
 %! lm3 = [0, 0, 0; 0, 0, 0; 0, 0, 0; 10, 0, 0];
 %! lm4 = [0, 0, 0; 0, 0, 0; 0, 0, 0; 0, 0, 0];
 %!
-%! assert (tril (a, -4), lm4);
-%! assert (tril (a, -3), lm3);
-%! assert (tril (a, -2), lm2);
-%! assert (tril (a, -1), lm1);
-%! assert (tril (a), l0);
-%! assert (tril (a, 1), l1);
-%! assert (tril (a, 2), l2);
+%!assert (tril (a, 3), l2)
+%!assert (tril (a, 2), l2)
+%!assert (tril (a, 1), l1)
+%!assert (tril (a, 0), l0)
+%!assert (tril (a), l0)
+%!assert (tril (a, -1), lm1)
+%!assert (tril (a, -2), lm2)
+%!assert (tril (a, -3), lm3)
+%!assert (tril (a, -4), lm4)
+%!assert (tril (a, -5), lm4)
+
+%!shared a, u3, u2, u1, u0, um1, um2, um3
+%!
+%! a = [1, 2, 3; 4, 5, 6; 7, 8, 9; 10, 11, 12];
+%!
+%! u3 = [0, 0, 0; 0, 0, 0; 0, 0, 0; 0, 0, 0];
+%! u2 = [0, 0, 3; 0, 0, 0; 0, 0, 0; 0, 0, 0];
+%! u1 = [0, 2, 3; 0, 0, 6; 0, 0, 0; 0, 0, 0];
+%! u0 = [1, 2, 3; 0, 5, 6; 0, 0, 9; 0, 0, 0];
+%! um1 = [1, 2, 3; 4, 5, 6; 0, 8, 9; 0, 0, 12];
+%! um2 = [1, 2, 3; 4, 5, 6; 7, 8, 9; 0, 11, 12];
+%! um3 = [1, 2, 3; 4, 5, 6; 7, 8, 9; 10, 11, 12];
+%!
+%!assert (triu (a, 4), u3)
+%!assert (triu (a, 3), u3)
+%!assert (triu (a, 2), u2)
+%!assert (triu (a, 1), u1)
+%!assert (triu (a, 0), u0)
+%!assert (triu (a), u0)
+%!assert (triu (a, -1), um1)
+%!assert (triu (a, -2), um2)
+%!assert (triu (a, -3), um3)
+%!assert (triu (a, -4), um3)
 
 %!error tril ()
+%!error triu ()
 */
--- a/libinterp/corefcn/txt-eng.h	Thu Nov 19 13:05:51 2020 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-////////////////////////////////////////////////////////////////////////
-//
-// Copyright (C) 2018-2020 The Octave Project Developers
-//
-// See the file COPYRIGHT.md in the top-level directory of this
-// distribution or <https://octave.org/copyright/>.
-//
-// This file is part of Octave.
-//
-// Octave is free software: you can redistribute it and/or modify it
-// under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Octave is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Octave; see the file COPYING.  If not, see
-// <https://www.gnu.org/licenses/>.
-//
-////////////////////////////////////////////////////////////////////////
-
-#if ! defined (octave_txt_eng_h)
-#define octave_txt_eng_h 1
-
-#include "octave-config.h"
-
-// Deprecated in Octave 5.  Remove in Octave 7
-#warning "txt-eng.h has been deprecated; use text-engine instead"
-
-#include "text-engine.h"
-
-#endif
--- a/libinterp/corefcn/utils.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/utils.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -1648,183 +1648,3 @@
 
 %!error isstudent (1)
 */
-
-// Always define these functions.  The macro is intended to allow the
-// declarations to be hidden, not so that Octave will not provide the
-// functions if they are requested.
-
-// #if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-#include "ov.h"
-#include "ovl.h"
-#include "str-vec.h"
-
-bool
-valid_identifier (const char *s)
-{
-  return octave::valid_identifier (s);
-}
-
-bool
-valid_identifier (const std::string& s)
-{
-  return octave::valid_identifier (s);
-}
-
-bool
-same_file (const std::string& f, const std::string& g)
-{
-  return octave::same_file (f, g);
-}
-
-int
-almost_match (const std::string& std, const std::string& s,
-              int min_match_len, int case_sens)
-{
-  return octave::almost_match (std, s, min_match_len, case_sens);
-}
-
-int
-keyword_almost_match (const char * const *std, int *min_len,
-                      const std::string& s, int min_toks_to_match,
-                      int max_toks)
-{
-  return octave::keyword_almost_match (std, min_len, s, min_toks_to_match,
-                                       max_toks);
-}
-
-std::string
-search_path_for_file (const std::string& path, const string_vector& names)
-{
-  return octave::search_path_for_file (path, names);
-}
-
-string_vector
-search_path_for_all_files (const std::string& path, const string_vector& names)
-{
-  return octave::search_path_for_all_files (path, names);
-}
-
-std::string
-file_in_path (const std::string& name, const std::string& suffix)
-{
-  return octave::file_in_path (name, suffix);
-}
-
-std::string
-find_data_file_in_load_path  (const std::string& fcn, const std::string& file,
-                              bool require_regular_file)
-{
-  return octave::find_data_file_in_load_path  (fcn, file, require_regular_file);
-}
-
-std::string
-contents_file_in_path (const std::string& s)
-{
-  return octave::contents_file_in_path (s);
-}
-
-std::string
-fcn_file_in_path (const std::string& s)
-{
-  return octave::fcn_file_in_path (s);
-}
-
-std::string
-do_string_escapes (const std::string& s)
-{
-  return octave::do_string_escapes (s);
-}
-
-const char *
-undo_string_escape (char c)
-{
-  return octave::undo_string_escape (c);
-}
-
-std::string
-undo_string_escapes (const std::string& s)
-{
-  return octave::undo_string_escapes (s);
-}
-
-void
-check_dimensions (dim_vector& dim, const char *warnfor)
-{
-  return octave::check_dimensions (dim, warnfor);
-}
-
-void
-get_dimensions (const octave_value& a, const char *warn_for,
-                dim_vector& dim)
-{
-  return octave::get_dimensions (a, warn_for, dim);
-}
-
-void
-get_dimensions (const octave_value& a, const octave_value& b,
-                const char *warn_for, octave_idx_type& nr,
-                octave_idx_type& nc)
-{
-  return octave::get_dimensions (a, b, warn_for, nr, nc);
-}
-
-void
-get_dimensions (const octave_value& a, const char *warn_for,
-                octave_idx_type& nr, octave_idx_type& nc)
-{
-  return octave::get_dimensions (a, warn_for, nr, nc);
-}
-
-octave_idx_type
-dims_to_numel (const dim_vector& dims, const octave_value_list& idx)
-{
-  return octave::dims_to_numel (dims, idx);
-}
-
-Matrix
-identity_matrix (octave_idx_type nr, octave_idx_type nc)
-{
-  return octave::identity_matrix (nr, nc);
-}
-
-FloatMatrix
-float_identity_matrix (octave_idx_type nr, octave_idx_type nc)
-{
-  return octave::float_identity_matrix (nr, nc);
-}
-
-size_t
-octave_vformat (std::ostream& os, const char *fmt, va_list args)
-{
-  return octave::vformat (os, fmt, args);
-}
-
-std::string
-octave_vasprintf (const char *fmt, va_list args)
-{
-  return octave::vasprintf (fmt, args);
-}
-
-void
-octave_sleep (double seconds)
-{
-  octave::sleep (seconds);
-}
-
-octave_value_list
-do_simple_cellfun (octave_value_list (*fun) (const octave_value_list&, int),
-                   const char *fun_name, const octave_value_list& args,
-                   int nargout)
-{
-  return octave::do_simple_cellfun (fun, fun_name, args, nargout);
-}
-
-octave_value
-do_simple_cellfun (octave_value_list (*fun) (const octave_value_list&, int),
-                   const char *fun_name, const octave_value_list& args)
-{
-  return octave::do_simple_cellfun (fun, fun_name, args);
-}
-
-// #endif
--- a/libinterp/corefcn/utils.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/utils.h	Thu Nov 19 13:08:00 2020 -0800
@@ -141,139 +141,4 @@
                      const char *fun_name, const octave_value_list& args);
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (5, "use 'octave::valid_identifier' instead")
-extern OCTINTERP_API bool
-valid_identifier (const char *s);
-
-OCTAVE_DEPRECATED (5, "use 'octave::valid_identifier' instead")
-extern OCTINTERP_API bool
-valid_identifier (const std::string& s);
-
-OCTAVE_DEPRECATED (5, "use 'octave::same_file' instead")
-extern OCTINTERP_API bool
-same_file (const std::string& f, const std::string& g);
-
-OCTAVE_DEPRECATED (5, "use 'octave::almost_match' instead")
-extern OCTINTERP_API int
-almost_match (const std::string& std, const std::string& s,
-              int min_match_len = 1, int case_sens = 1);
-
-OCTAVE_DEPRECATED (5, "use 'octave::keyword_almost_match' instead")
-extern OCTINTERP_API int
-keyword_almost_match (const char * const *std, int *min_len,
-                      const std::string& s, int min_toks_to_match,
-                      int max_toks);
-
-OCTAVE_DEPRECATED (5, "use 'octave::search_path_for_file' instead")
-extern OCTINTERP_API std::string
-search_path_for_file (const std::string& path, const string_vector& names);
-
-OCTAVE_DEPRECATED (5, "use 'octave::search_path_for_all_files' instead")
-extern OCTINTERP_API string_vector
-search_path_for_all_files (const std::string& path, const string_vector& names);
-
-OCTAVE_DEPRECATED (5, "use 'octave::file_in_path' instead")
-extern OCTINTERP_API std::string
-file_in_path (const std::string& name, const std::string& suffix);
-
-OCTAVE_DEPRECATED (5, "use 'octave::find_data_file_in_load_path ' instead")
-extern OCTINTERP_API std::string
-find_data_file_in_load_path  (const std::string& fcn, const std::string& file,
-                              bool require_regular_file = false);
-
-OCTAVE_DEPRECATED (5, "use 'octave::contents_file_in_path' instead")
-extern OCTINTERP_API std::string
-contents_file_in_path (const std::string& s);
-
-OCTAVE_DEPRECATED (5, "use 'octave::fcn_file_in_path' instead")
-extern OCTINTERP_API std::string
-fcn_file_in_path (const std::string& s);
-
-OCTAVE_DEPRECATED (5, "use 'octave::do_string_escapes' instead")
-extern OCTINTERP_API std::string
-do_string_escapes (const std::string& s);
-
-OCTAVE_DEPRECATED (5, "use 'octave::undo_string_escape' instead")
-extern OCTINTERP_API const char *
-undo_string_escape (char c);
-
-OCTAVE_DEPRECATED (5, "use 'octave::undo_string_escapes' instead")
-extern OCTINTERP_API std::string
-undo_string_escapes (const std::string& s);
-
-OCTAVE_DEPRECATED (5, "use 'octave::check_dimensions' instead")
-extern OCTINTERP_API void
-check_dimensions (dim_vector& dim, const char *warnfor);
-
-OCTAVE_DEPRECATED (5, "use 'octave::get_dimensions' instead")
-extern OCTINTERP_API void
-get_dimensions (const octave_value& a, const char *warn_for,
-                dim_vector& dim);
-
-OCTAVE_DEPRECATED (5, "use 'octave::get_dimensions' instead")
-extern OCTINTERP_API void
-get_dimensions (const octave_value& a, const octave_value& b,
-                const char *warn_for, octave_idx_type& nr,
-                octave_idx_type& nc);
-
-OCTAVE_DEPRECATED (5, "use 'octave::get_dimensions' instead")
-extern OCTINTERP_API void
-get_dimensions (const octave_value& a, const char *warn_for,
-                octave_idx_type& nr, octave_idx_type& nc);
-
-OCTAVE_DEPRECATED (5, "use 'octave::dims_to_numel' instead")
-extern OCTINTERP_API octave_idx_type
-dims_to_numel (const dim_vector& dims, const octave_value_list& idx);
-
-OCTAVE_DEPRECATED (5, "use 'octave::identity_matrix' instead")
-extern OCTINTERP_API Matrix
-identity_matrix (octave_idx_type nr, octave_idx_type nc);
-
-OCTAVE_DEPRECATED (5, "use 'octave::float_identity_matrix' instead")
-extern OCTINTERP_API FloatMatrix
-float_identity_matrix (octave_idx_type nr, octave_idx_type nc);
-
-template <typename ... Args>
-OCTAVE_DEPRECATED (5, "use 'octave::format' instead")
-size_t
-octave_format (std::ostream& os, const char *fmt, Args&& ... args)
-{
-  return octave::format (os, fmt, std::forward<Args> (args) ...);
-}
-
-OCTAVE_DEPRECATED (5, "use 'octave::vformat' instead")
-extern OCTINTERP_API size_t
-octave_vformat (std::ostream& os, const char *fmt, va_list args);
-
-OCTAVE_DEPRECATED (5, "use 'octave::vasprintf' instead")
-extern OCTINTERP_API std::string
-octave_vasprintf (const char *fmt, va_list args);
-
-template <typename ... Args>
-OCTAVE_DEPRECATED (5, "use 'octave::asprintf' instead")
-std::string
-octave_asprintf (const char *fmt, Args&& ... args)
-{
-  return octave::asprintf (fmt, std::forward<Args> (args) ...);
-}
-
-OCTAVE_DEPRECATED (5, "use 'octave::sleep' instead")
-extern OCTINTERP_API void
-octave_sleep (double seconds);
-
-OCTAVE_DEPRECATED (5, "use 'octave::do_simple_cellfun' instead")
-extern OCTINTERP_API octave_value_list
-do_simple_cellfun (octave_value_list (*fun) (const octave_value_list&, int),
-                   const char *fun_name, const octave_value_list& args,
-                   int nargout);
-
-OCTAVE_DEPRECATED (5, "use 'octave::do_simple_cellfun' instead")
-extern OCTINTERP_API octave_value
-do_simple_cellfun (octave_value_list (*fun) (const octave_value_list&, int),
-                   const char *fun_name, const octave_value_list& args);
-
 #endif
-
-#endif
--- a/libinterp/corefcn/variables.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/variables.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -531,10 +531,10 @@
 %! end_unwind_protect
 %! assert (exist (fullfile (pwd (), "%nonexistentfile%"), "file"), 0);
 
-%!assert (exist ("fftw"), 3);
-%!assert (exist ("fftw.oct"), 3);
-%!assert (exist ("fftw", "file"), 3);
-%!assert (exist ("fftw", "builtin"), 0);
+%!assert (exist ("fftw"), 3)
+%!assert (exist ("fftw.oct"), 3)
+%!assert (exist ("fftw", "file"), 3)
+%!assert (exist ("fftw", "builtin"), 0)
 
 %!assert (exist ("ftp"), 2);
 %!assert (exist ("ftp.m"), 2);
@@ -1446,8 +1446,8 @@
   if (val.is_defined ())
     {
       // Ensure auto-restoration.
-      octave::unwind_protect frame;
-      frame.protect_var (Vmissing_function_hook);
+      octave::unwind_protect_var<std::string>
+        restore_var (Vmissing_function_hook);
 
       // Clear the variable prior to calling the function.
       const std::string func_name = Vmissing_function_hook;
@@ -1465,27 +1465,49 @@
 
 DEFMETHOD (__varval__, interp, args, ,
            doc: /* -*- texinfo -*-
-@deftypefn {} {} __varval__ (@var{name})
+@deftypefn {} {@var{value} =} __varval__ (@var{name})
 Return the value of the variable @var{name} directly from the symbol table.
+
+If @var{name} does not exist then nothing is returned, not even an empty matrix
+(@code{[]}), since there would be no way to distinguish between a variable
+not found in the symbol table and a variable who's value was @code{[]}.
+
+A standard usage pattern is to code a @code{try}/@code{catch} block around a
+call to @code{__varval__}.
+
+Example Code
+
+@example
+@group
+try
+  @var{val} = __varval__ (@var{name});
+catch
+  ## No variable @var{name} found in symbol table
+  @var{val} = NA;                  # Substitute Not Available (NA)
+  error ("@var{name} not found");  # or, throw an error.
+end_try_catch
+@end group
+@end example
+
+Programming Note: The magic @var{name} @qcode{".argn."} will retrieve the text
+of input arguments to a function and is used by @code{inputname} internally.
+@seealso{inputname}
 @end deftypefn */)
 {
   if (args.length () != 1)
     print_usage ();
 
-  std::string name = args(0).xstring_value ("__varval__: first argument must be a variable name");
-
-  std::string nm = args(0).string_value ();
+  std::string name = args(0).xstring_value ("__varval__: NAME must be a string");
 
-  // FIXME: we need this kluge to implement inputname in a .m file.
-
-  if (nm == ".argn.")
+  // We need this kluge to implement inputname in a .m file.
+  if (name == ".argn.")
     {
       octave::tree_evaluator& tw = interp.get_evaluator ();
 
       return tw.get_auto_fcn_var (octave::stack_frame::ARG_NAMES);
     }
 
-  return interp.varval (nm);
+  return interp.varval (name);
 }
 
 static std::string Vmissing_component_hook;
@@ -1520,42 +1542,3 @@
 {
   return SET_INTERNAL_VARIABLE (missing_component_hook);
 }
-
-// The following function is deprecated.
-
-string_vector
-get_struct_elts (const std::string& text)
-{
-  int n = 1;
-
-  size_t pos = 0;
-
-  size_t len = text.length ();
-
-  while ((pos = text.find ('.', pos)) != std::string::npos)
-    {
-      if (++pos == len)
-        break;
-
-      n++;
-    }
-
-  string_vector retval (n);
-
-  pos = 0;
-
-  for (int i = 0; i < n; i++)
-    {
-      len = text.find ('.', pos);
-
-      if (len != std::string::npos)
-        len -= pos;
-
-      retval[i] = text.substr (pos, len);
-
-      if (len != std::string::npos)
-        pos += len + 1;
-    }
-
-  return retval;
-}
--- a/libinterp/corefcn/variables.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/variables.h	Thu Nov 19 13:08:00 2020 -0800
@@ -116,8 +116,4 @@
 extern OCTINTERP_API std::string
 maybe_missing_function_hook (const std::string& name);
 
-OCTAVE_DEPRECATED (5, "this function will be removed in a future version of Octave")
-extern OCTINTERP_API string_vector
-get_struct_elts (const std::string& text);
-
 #endif
--- a/libinterp/corefcn/xpow.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/xpow.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -711,7 +711,7 @@
 }
 
 octave_value
-elem_xpow (double a, const Range& r)
+elem_xpow (double a, const octave::range<double>& r)
 {
   octave_value retval;
 
@@ -722,19 +722,18 @@
     {
       octave_idx_type n = r.numel ();
       Matrix result (1, n);
-      if (same_sign (r.base (), r.inc ()))
+      if (same_sign (r.base (), r.increment ()))
         {
           double base = std::pow (a, r.base ());
-          double inc = std::pow (a, r.inc ());
+          double inc = std::pow (a, r.increment ());
           result(0) = base;
           for (octave_idx_type i = 1; i < n; i++)
             result(i) = (base *= inc);
         }
       else
         {
-          // Don't use Range::limit () here.
-          double limit = std::pow (a, r.base () + (n-1) * r.inc ());
-          double inc = std::pow (a, -r.inc ());
+          double limit = std::pow (a, r.final_value ());
+          double inc = std::pow (a, -r.increment ());
           result(n-1) = limit;
           for (octave_idx_type i = n-2; i >= 0; i--)
             result(i) = (limit *= inc);
@@ -743,7 +742,10 @@
       retval = result;
     }
   else
-    retval = elem_xpow (a, r.matrix_value ());
+    {
+      Matrix tmp = r.array_value ();
+      retval = elem_xpow (a, tmp);
+    }
 
   return retval;
 }
@@ -940,7 +942,7 @@
 }
 
 octave_value
-elem_xpow (const Complex& a, const Range& r)
+elem_xpow (const Complex& a, const octave::range<double>& r)
 {
   octave_value retval;
 
@@ -952,19 +954,18 @@
       octave_idx_type n = r.numel ();
       ComplexMatrix result (1, n);
 
-      if (same_sign (r.base (), r.inc ()))
+      if (same_sign (r.base (), r.increment ()))
         {
           Complex base = std::pow (a, r.base ());
-          Complex inc = std::pow (a, r.inc ());
+          Complex inc = std::pow (a, r.increment ());
           result(0) = base;
           for (octave_idx_type i = 1; i < n; i++)
             result(i) = (base *= inc);
         }
       else
         {
-          // Don't use Range::limit () here.
-          Complex limit = std::pow (a, r.base () + (n-1) * r.inc ());
-          Complex inc = std::pow (a, -r.inc ());
+          Complex limit = std::pow (a, r.final_value ());
+          Complex inc = std::pow (a, -r.increment ());
           result(n-1) = limit;
           for (octave_idx_type i = n-2; i >= 0; i--)
             result(i) = (limit *= inc);
@@ -973,7 +974,10 @@
       retval = result;
     }
   else
-    retval = elem_xpow (a, r.matrix_value ());
+    {
+      Matrix tmp = r.array_value ();
+      retval = elem_xpow (a, tmp);
+    }
 
   return retval;
 }
--- a/libinterp/corefcn/xpow.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/corefcn/xpow.h	Thu Nov 19 13:08:00 2020 -0800
@@ -75,7 +75,7 @@
 
 extern OCTINTERP_API octave_value elem_xpow (double a, const Matrix& b);
 extern OCTINTERP_API octave_value elem_xpow (double a, const ComplexMatrix& b);
-extern OCTINTERP_API octave_value elem_xpow (double a, const Range& r);
+extern OCTINTERP_API octave_value elem_xpow (double a, const octave::range<double>& r);
 
 extern OCTINTERP_API octave_value elem_xpow (const Matrix& a, double b);
 extern OCTINTERP_API octave_value elem_xpow (const Matrix& a, const Matrix& b);
@@ -86,7 +86,7 @@
 extern OCTINTERP_API octave_value elem_xpow (const Complex& a, const Matrix& b);
 extern OCTINTERP_API octave_value elem_xpow (const Complex& a,
                                              const ComplexMatrix& b);
-extern OCTINTERP_API octave_value elem_xpow (const Complex& a, const Range& r);
+extern OCTINTERP_API octave_value elem_xpow (const Complex& a, const octave::range<double>& r);
 
 extern OCTINTERP_API octave_value elem_xpow (const ComplexMatrix& a, double b);
 extern OCTINTERP_API octave_value elem_xpow (const ComplexMatrix& a,
--- a/libinterp/dldfcn/__delaunayn__.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/dldfcn/__delaunayn__.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -70,12 +70,6 @@
 #  endif
 
 static void
-close_fcn (FILE *f)
-{
-  std::fclose (f);
-}
-
-static void
 free_qhull_memory ()
 {
   qh_freeqhull (! qh_ALL);
@@ -166,8 +160,6 @@
 
       sprintf (flags, "qhull d %s", options.c_str ());
 
-      octave::unwind_protect frame;
-
       // Replace the outfile pointer with stdout for debugging information.
 #if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM)
       FILE *outfile = std::fopen ("NUL", "w");
@@ -179,12 +171,13 @@
       if (! outfile)
         error ("__delaunayn__: unable to create temporary file for output");
 
-      frame.add_fcn (close_fcn, outfile);
+      octave::unwind_action close_outfile
+        ([outfile] () { std::fclose (outfile); });
 
       int exitcode = qh_new_qhull (dim, n, pt_array,
                                    ismalloc, flags, outfile, errfile);
 
-      frame.add_fcn (free_qhull_memory);
+      octave::unwind_action free_memory ([] () { free_qhull_memory (); });
 
       if (exitcode)
         error ("__delaunayn__: qhull failed");
--- a/libinterp/dldfcn/__init_fltk__.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/dldfcn/__init_fltk__.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -2490,22 +2490,21 @@
 // autoloaded functions in the PKG_ADD file and will not be visible to
 // the interpreter.
 
+#if defined (HAVE_FLTK)
 static octave_value_list
 F__fltk_check__ (octave::interpreter& interp, const octave_value_list&, int)
 {
-#if defined (HAVE_FLTK)
   Fl::check ();
 
   if (Vdrawnow_requested)
     Fdrawnow (interp);
 
   return octave_value_list ();
-#else
   octave_unused_parameter (interp);
 
   err_disabled_feature ("__fltk_check__", "OpenGL and FLTK");
+}
 #endif
-}
 
 // Initialize the fltk graphics toolkit.
 
--- a/libinterp/dldfcn/__init_gnuplot__.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/dldfcn/__init_gnuplot__.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -113,10 +113,8 @@
     // Prevent recursion
     if (! drawnow_executing)
       {
-        octave::unwind_protect frame;
-        frame.protect_var (drawnow_executing);
+        octave::unwind_protect_var<bool> restore_var (drawnow_executing, true);
 
-        drawnow_executing = true;
         octave_value_list args;
         args(0) = go.get_handle ().as_octave_value ();
         octave::feval ("__gnuplot_drawnow__", args);
--- a/libinterp/dldfcn/__ode15__.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/dldfcn/__ode15__.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -30,6 +30,8 @@
 #include "dColVector.h"
 #include "dMatrix.h"
 #include "dSparse.h"
+#include "f77-fcn.h"
+#include "lo-utils.h"
 
 #include "Cell.h"
 #include "defun-dld.h"
@@ -117,20 +119,20 @@
   static inline realtype *
   nv_data_s (N_Vector& v)
   {
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
+#  if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
     // Disable warning from GCC about old-style casts in Sundials
     // macro expansions.  Do this in a function so that this
     // diagnostic may still be enabled for the rest of the file.
-#  pragma GCC diagnostic push
-#  pragma GCC diagnostic ignored "-Wold-style-cast"
-#endif
+#   pragma GCC diagnostic push
+#   pragma GCC diagnostic ignored "-Wold-style-cast"
+#  endif
 
     return NV_DATA_S (v);
 
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
+#  if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
     // Restore prevailing warning state for remainder of the file.
-#  pragma GCC diagnostic pop
-#endif
+#   pragma GCC diagnostic pop
+#  endif
   }
 
   class IDA
@@ -166,8 +168,8 @@
       : m_t0 (0.0), m_y0 (), m_yp0 (), m_havejac (false), m_havejacfun (false),
         m_havejacsparse (false), m_mem (nullptr), m_num (), m_ida_fun (),
         m_ida_jac (), m_dfdy (nullptr), m_dfdyp (nullptr), m_spdfdy (nullptr),
-        m_spdfdyp (nullptr), m_fun (nullptr), m_jacfun (nullptr), m_jacspfun (nullptr),
-        m_jacdcell (nullptr), m_jacspcell (nullptr),
+        m_spdfdyp (nullptr), m_fun (nullptr), m_jacfun (nullptr),
+        m_jacspfun (nullptr), m_jacdcell (nullptr), m_jacspcell (nullptr),
         m_sunJacMatrix (nullptr), m_sunLinearSolver (nullptr)
     { }
 
@@ -177,8 +179,8 @@
       : m_t0 (t), m_y0 (y), m_yp0 (yp), m_havejac (false), m_havejacfun (false),
         m_havejacsparse (false), m_mem (nullptr), m_num (), m_ida_fun (ida_fcn),
         m_ida_jac (), m_dfdy (nullptr), m_dfdyp (nullptr), m_spdfdy (nullptr),
-        m_spdfdyp (nullptr), m_fun (daefun), m_jacfun (nullptr), m_jacspfun (nullptr),
-        m_jacdcell (nullptr), m_jacspcell (nullptr),
+        m_spdfdyp (nullptr), m_fun (daefun), m_jacfun (nullptr),
+        m_jacspfun (nullptr), m_jacdcell (nullptr), m_jacspcell (nullptr),
         m_sunJacMatrix (nullptr), m_sunLinearSolver (nullptr)
     { }
 
@@ -245,9 +247,9 @@
 
     void initialize (void);
 
-    static ColumnVector NVecToCol (N_Vector& v, long int n);
+    static ColumnVector NVecToCol (N_Vector& v, octave_f77_int_type n);
 
-    static N_Vector ColToNVec (const ColumnVector& data, long int n);
+    static N_Vector ColToNVec (const ColumnVector& data, octave_f77_int_type n);
 
     void
     set_up (const ColumnVector& y);
@@ -266,9 +268,9 @@
     resfun_impl (realtype t, N_Vector& yy,
                  N_Vector& yyp, N_Vector& rr);
     static int
-    jacdense (realtype t, realtype cj, N_Vector yy,
-              N_Vector yyp, N_Vector, SUNMatrix JJ, void *user_data,
-              N_Vector, N_Vector, N_Vector)
+    jacdense (realtype t, realtype cj, N_Vector yy, N_Vector yyp,
+              N_Vector, SUNMatrix JJ, void *user_data, N_Vector,
+              N_Vector, N_Vector)
     {
       IDA *self = static_cast <IDA *> (user_data);
       self->jacdense_impl (t, cj, yy, yyp, JJ);
@@ -291,8 +293,8 @@
     }
 
     void
-    jacsparse_impl (realtype t, realtype cj, N_Vector& yy,
-                    N_Vector& yyp, SUNMatrix& Jac);
+    jacsparse_impl (realtype t, realtype cj,
+                    N_Vector& yy, N_Vector& yyp, SUNMatrix& Jac);
 #  endif
 
     void set_maxstep (realtype maxstep);
@@ -300,14 +302,14 @@
     void set_initialstep (realtype initialstep);
 
     bool
-    interpolate (int& cont, Matrix& output, ColumnVector& tout,
+    interpolate (octave_idx_type& cont, Matrix& output, ColumnVector& tout,
                  int refine, realtype tend, bool haveoutputfcn,
                  bool haveoutputsel, const octave_value& output_fcn,
                  ColumnVector& outputsel, bool haveeventfunction,
                  const octave_value& event_fcn, ColumnVector& te,
                  Matrix& ye, ColumnVector& ie, ColumnVector& oldval,
                  ColumnVector& oldisterminal, ColumnVector& olddir,
-                 int& temp, ColumnVector& yold);
+                 octave_idx_type& temp, ColumnVector& yold);
 
     bool
     outputfun (const octave_value& output_fcn, bool haveoutputsel,
@@ -321,12 +323,13 @@
            realtype tsol, const ColumnVector& y, const std::string& flag,
            const ColumnVector& yp, ColumnVector& oldval,
            ColumnVector& oldisterminal, ColumnVector& olddir,
-           int cont, int& temp, realtype told, ColumnVector& yold);
+           octave_idx_type cont, octave_idx_type& temp, realtype told,
+           ColumnVector& yold);
 
     void set_maxorder (int maxorder);
 
     octave_value_list
-    integrate (const int numt, const ColumnVector& tt,
+    integrate (const octave_idx_type numt, const ColumnVector& tt,
                const ColumnVector& y0, const ColumnVector& yp0,
                const int refine, bool haverefine, bool haveoutputfcn,
                const octave_value& output_fcn, bool haveoutputsel,
@@ -344,7 +347,7 @@
     bool m_havejacfun;
     bool m_havejacsparse;
     void *m_mem;
-    int m_num;
+    octave_f77_int_type m_num;
     octave_value m_ida_fun;
     octave_value m_ida_jac;
     Matrix *m_dfdy;
@@ -388,15 +391,22 @@
   void
   IDA::set_up (const ColumnVector& y)
   {
-    N_Vector yy = ColToNVec(y, m_num);
+    N_Vector yy = ColToNVec (y, m_num);
 
     if (m_havejacsparse)
       {
 #  if defined (HAVE_SUNDIALS_SUNLINSOL_KLU)
-        // FIXME : one should not allocate space for a full Jacobian
-        // when using a sparse format.  Consider allocating less space
-        // then possibly using SUNSparseMatrixReallocate to increase it.
+#    if defined (HAVE_SUNSPARSEMATRIX_REALLOCATE)
+        // Initially allocate memory for 0 entries. We will reallocate when we
+        // get the Jacobian matrix from the user and know the actual number of
+        // entries.
+        m_sunJacMatrix = SUNSparseMatrix (m_num, m_num, 0, CSC_MAT);
+#    else
+        if (math::int_multiply_overflow (m_num, m_num))
+          error ("Unable to allocate memory for sparse Jacobian");
+
         m_sunJacMatrix = SUNSparseMatrix (m_num, m_num, m_num*m_num, CSC_MAT);
+#    endif
         if (! m_sunJacMatrix)
           error ("Unable to create sparse Jacobian for Sundials");
 
@@ -410,7 +420,9 @@
         IDASetJacFn (m_mem, IDA::jacsparse);
 
 #  else
-        error ("SUNDIALS SUNLINSOL KLU is not available in this version of Octave");
+        error ("SUNDIALS SUNLINSOL KLU was unavailable or disabled when "
+               "Octave was built");
+
 #  endif
 
       }
@@ -439,7 +451,7 @@
                       N_Vector& yy, N_Vector& yyp, SUNMatrix& JJ)
 
   {
-    long int Neq = NV_LENGTH_S(yy);
+    octave_f77_int_type Neq = NV_LENGTH_S (yy);
 
     ColumnVector y = NVecToCol (yy, Neq);
 
@@ -452,8 +464,9 @@
     else
       jac = (*m_jacdcell) (m_dfdy, m_dfdyp, cj);
 
+    octave_f77_int_type num_jac = to_f77_int (jac.numel ());
     std::copy (jac.fortran_vec (),
-               jac.fortran_vec () + jac.numel (),
+               jac.fortran_vec () + num_jac,
                SUNDenseMatrix_Data (JJ));
   }
 
@@ -474,42 +487,56 @@
     else
       jac = (*m_jacspcell) (m_spdfdy, m_spdfdyp, cj);
 
+#     if defined (HAVE_SUNSPARSEMATRIX_REALLOCATE)
+    octave_f77_int_type nnz = to_f77_int (jac.nnz ());
+    if (nnz > SUNSparseMatrix_NNZ (Jac))
+      {
+        // Allocate memory for sparse Jacobian defined in user function.
+        // This will always be required at least once since we set the number
+        // of non-zero elements to zero initially.
+        if (SUNSparseMatrix_Reallocate (Jac, nnz))
+          error ("Unable to allocate sufficient memory for IDA sparse matrix");
+      }
+#     endif
+
     SUNMatZero_Sparse (Jac);
+    // We have to use "sunindextype *" here but still need to check that
+    // conversion of each element to "octave_f77_int_type" is save.
     sunindextype *colptrs = SUNSparseMatrix_IndexPointers (Jac);
     sunindextype *rowvals = SUNSparseMatrix_IndexValues (Jac);
 
-    for (int i = 0; i < m_num + 1; i++)
-      colptrs[i] = jac.cidx(i);
+    for (octave_f77_int_type i = 0; i < m_num + 1; i++)
+      colptrs[i] = to_f77_int (jac.cidx (i));
 
     double *d = SUNSparseMatrix_Data (Jac);
-    for (int i = 0; i < jac.nnz (); i++)
+    for (octave_f77_int_type i = 0; i < to_f77_int (jac.nnz ()); i++)
       {
-        rowvals[i] = jac.ridx(i);
-        d[i] = jac.data(i);
+        rowvals[i] = to_f77_int (jac.ridx (i));
+        d[i] = jac.data (i);
       }
   }
 #  endif
 
   ColumnVector
-  IDA::NVecToCol (N_Vector& v, long int n)
+  IDA::NVecToCol (N_Vector& v, octave_f77_int_type n)
   {
     ColumnVector data (n);
     realtype *punt = nv_data_s (v);
 
-    for (octave_idx_type i = 0; i < n; i++)
+    for (octave_f77_int_type i = 0; i < n; i++)
       data(i) = punt[i];
 
     return data;
   }
 
   N_Vector
-  IDA::ColToNVec (const ColumnVector& data, long int n)
+  IDA::ColToNVec (const ColumnVector& data, octave_f77_int_type n)
   {
     N_Vector v = N_VNew_Serial (n);
 
     realtype *punt = nv_data_s (v);
 
-    for (octave_idx_type i = 0; i < n; i++)
+    for (octave_f77_int_type i = 0; i < n; i++)
       punt[i] = data(i);
 
     return v;
@@ -527,7 +554,7 @@
   void
   IDA::initialize (void)
   {
-    m_num = m_y0.numel ();
+    m_num = to_f77_int (m_y0.numel ());
     m_mem = IDACreate ();
 
     N_Vector yy = ColToNVec (m_y0, m_num);
@@ -559,7 +586,7 @@
   }
 
   octave_value_list
-  IDA::integrate (const int numt, const ColumnVector& tspan,
+  IDA::integrate (const octave_idx_type numt, const ColumnVector& tspan,
                   const ColumnVector& y, const ColumnVector& yp,
                   const int refine, bool haverefine, bool haveoutputfcn,
                   const octave_value& output_fcn, bool haveoutputsel,
@@ -570,7 +597,7 @@
     ColumnVector tout, yout (m_num), ypout (m_num), ysel (outputsel.numel ());
     ColumnVector ie, te, oldval, oldisterminal, olddir;
     Matrix output, ye;
-    int cont = 0, temp = 0;
+    octave_idx_type cont = 0, temp = 0;
     bool status = 0;
     std::string string = "";
     ColumnVector yold = y;
@@ -721,16 +748,18 @@
 
       }
 
-    return ovl (tout, output, te, ye, ie);
+    // Index of Events (ie) variable must use 1-based indexing
+    return ovl (tout, output, te, ye, ie + 1.0);
   }
 
   bool
   IDA::event (const octave_value& event_fcn,
-              ColumnVector& te, Matrix& ye, ColumnVector& ie,
-              realtype tsol, const ColumnVector& y, const std::string& flag,
+              ColumnVector& te, Matrix& ye, ColumnVector& ie, realtype tsol,
+              const ColumnVector& y, const std::string& flag,
               const ColumnVector& yp, ColumnVector& oldval,
-              ColumnVector& oldisterminal, ColumnVector& olddir, int cont,
-              int& temp, realtype told, ColumnVector& yold)
+              ColumnVector& oldisterminal, ColumnVector& olddir,
+              octave_idx_type cont, octave_idx_type& temp, realtype told,
+              ColumnVector& yold)
   {
     bool status = 0;
 
@@ -757,8 +786,14 @@
         // Get the index of the changed values
         for (octave_idx_type i = 0; i < val.numel (); i++)
           {
-            if ((val(i) > 0 && oldval(i) < 0 && dir(i) != -1) // increasing
-                || (val(i) < 0 && oldval(i) > 0 && dir(i) != 1)) // decreasing
+            // Check for sign change and whether a rising / falling edge
+            // either passes through zero or detaches from zero (bug #59063)
+            if ((dir(i) != -1
+                 && ((val(i) >= 0 && oldval(i) < 0)
+                     || (val(i) > 0 && oldval(i) <= 0))) // increasing
+                || (dir(i) != 1
+                    && ((val(i) <= 0 && oldval(i) > 0)
+                        || (val(i) < 0 && oldval(i) >= 0)))) // decreasing
               {
                 index.resize (index.numel () + 1);
                 index (index.numel () - 1) = i;
@@ -825,14 +860,14 @@
   }
 
   bool
-  IDA::interpolate (int& cont, Matrix& output, ColumnVector& tout,
+  IDA::interpolate (octave_idx_type& cont, Matrix& output, ColumnVector& tout,
                     int refine, realtype tend, bool haveoutputfcn,
                     bool haveoutputsel, const octave_value& output_fcn,
                     ColumnVector& outputsel, bool haveeventfunction,
                     const octave_value& event_fcn, ColumnVector& te,
                     Matrix& ye, ColumnVector& ie, ColumnVector& oldval,
                     ColumnVector& oldisterminal, ColumnVector& olddir,
-                    int& temp, ColumnVector& yold)
+                    octave_idx_type& temp, ColumnVector& yold)
   {
     realtype h = 0, tcur = 0;
     bool status = 0;
@@ -916,7 +951,7 @@
 
     if (flag == "init")
       {
-        ColumnVector toutput(2);
+        ColumnVector toutput (2);
         toutput(0) = tsol;
         toutput(1) = tend;
         output(0) = toutput;
@@ -1052,7 +1087,7 @@
   octave_value_list
   do_ode15 (const octave_value& ida_fcn,
             const ColumnVector& tspan,
-            const int numt,
+            const octave_idx_type numt,
             const realtype t0,
             const ColumnVector& y0,
             const ColumnVector& yp0,
@@ -1110,43 +1145,43 @@
     dae.initialize ();
 
     // Set tolerances
-    realtype rel_tol = options.getfield("RelTol").double_value ();
+    realtype rel_tol = options.getfield ("RelTol").double_value ();
 
     bool haveabstolvec = options.getfield ("haveabstolvec").bool_value ();
 
     if (haveabstolvec)
       {
-        ColumnVector abs_tol = options.getfield("AbsTol").vector_value ();
+        ColumnVector abs_tol = options.getfield ("AbsTol").vector_value ();
 
         dae.set_tolerance (abs_tol, rel_tol);
       }
     else
       {
-        realtype abs_tol = options.getfield("AbsTol").double_value ();
+        realtype abs_tol = options.getfield ("AbsTol").double_value ();
 
         dae.set_tolerance (abs_tol, rel_tol);
       }
 
     //Set max step
-    realtype maxstep = options.getfield("MaxStep").double_value ();
+    realtype maxstep = options.getfield ("MaxStep").double_value ();
 
     dae.set_maxstep (maxstep);
 
     //Set initial step
-    if (! options.getfield("InitialStep").isempty ())
+    if (! options.getfield ("InitialStep").isempty ())
       {
-        realtype initialstep = options.getfield("InitialStep").double_value ();
+        realtype initialstep = options.getfield ("InitialStep").double_value ();
 
         dae.set_initialstep (initialstep);
       }
 
     //Set max order FIXME: it doesn't work
-    int maxorder = options.getfield("MaxOrder").int_value ();
+    int maxorder = options.getfield ("MaxOrder").int_value ();
 
     dae.set_maxorder (maxorder);
 
     //Set Refine
-    const int refine = options.getfield("Refine").int_value ();
+    const int refine = options.getfield ("Refine").int_value ();
 
     bool haverefine = (refine > 1);
 
@@ -1155,25 +1190,25 @@
 
     // OutputFcn
     bool haveoutputfunction
-      = options.getfield("haveoutputfunction").bool_value ();
+      = options.getfield ("haveoutputfunction").bool_value ();
 
     if (haveoutputfunction)
-      output_fcn = options.getfield("OutputFcn");
+      output_fcn = options.getfield ("OutputFcn");
 
     // OutputSel
-    bool haveoutputsel = options.getfield("haveoutputselection").bool_value ();
+    bool haveoutputsel = options.getfield ("haveoutputselection").bool_value ();
 
     if (haveoutputsel)
-      outputsel = options.getfield("OutputSel").vector_value ();
+      outputsel = options.getfield ("OutputSel").vector_value ();
 
     octave_value event_fcn;
 
     // Events
     bool haveeventfunction
-      = options.getfield("haveeventfunction").bool_value ();
+      = options.getfield ("haveeventfunction").bool_value ();
 
     if (haveeventfunction)
-      event_fcn = options.getfield("Events");
+      event_fcn = options.getfield ("Events");
 
     // Set up linear solver
     dae.set_up (y0);
@@ -1185,7 +1220,7 @@
                             haveeventfunction, event_fcn);
 
     // Statistics
-    bool havestats = options.getfield("havestats").bool_value ();
+    bool havestats = options.getfield ("havestats").bool_value ();
 
     if (havestats)
       dae.print_stat ();
@@ -1206,9 +1241,7 @@
 #if defined (HAVE_SUNDIALS)
 
   // Check number of parameters
-  int nargin = args.length ();
-
-  if (nargin != 5)
+  if (args.length () != 5)
     print_usage ();
 
   // Check odefun
@@ -1221,7 +1254,7 @@
   ColumnVector tspan
     = args(1).xvector_value ("__ode15__: TRANGE must be a vector of numbers");
 
-  int numt = tspan.numel ();
+  octave_idx_type numt = tspan.numel ();
 
   realtype t0 = tspan (0);
 
--- a/libinterp/dldfcn/__voronoi__.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/dldfcn/__voronoi__.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -65,12 +65,6 @@
 #  endif
 
 static void
-close_fcn (FILE *f)
-{
-  std::fclose (f);
-}
-
-static void
 free_qhull_memory ()
 {
   qh_freeqhull (! qh_ALL);
@@ -158,8 +152,6 @@
 
   boolT ismalloc = false;
 
-  octave::unwind_protect frame;
-
   // Replace the outfile pointer with stdout for debugging information.
 #if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM)
   FILE *outfile = std::fopen ("NUL", "w");
@@ -171,7 +163,7 @@
   if (! outfile)
     error ("__voronoi__: unable to create temporary file for output");
 
-  frame.add_fcn (close_fcn, outfile);
+  octave::unwind_action close_outfile ([outfile] () { std::fclose (outfile); });
 
   // qh_new_qhull command and points arguments are not const...
 
@@ -184,7 +176,7 @@
   int exitcode = qh_new_qhull (dim, num_points, points.fortran_vec (),
                                ismalloc, cmd_str, outfile, errfile);
 
-  frame.add_fcn (free_qhull_memory);
+  octave::unwind_action free_memory ([] () { free_qhull_memory (); });
 
   if (exitcode)
     error ("%s: qhull failed", caller.c_str ());
--- a/libinterp/dldfcn/audiodevinfo.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/dldfcn/audiodevinfo.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -304,7 +304,7 @@
       std::string arg3 = args(2).string_value ();
       std::transform (arg3.begin (), arg3.end (), arg3.begin (), tolower);
       if (arg3 != "driverversion")
-        error ("audiodevinfo: third argument must be \"DriverVersion\"");
+        error (R"(audiodevinfo: third argument must be "DriverVersion")");
 
       if (outin == 0)
         {
@@ -489,7 +489,7 @@
 %!   assert (devinfo.output(i).Name, audiodevinfo (0, devinfo.output(i).ID));
 %! endfor
 %! for i=1:nin
-%!   assert (devinfo.input(i).Name, audiodevinfo (1, devinfo.input(i).ID));
+%!   assert (devinfo.input (i).Name, audiodevinfo (1, devinfo.input (i).ID));
 %! endfor
 
 %!testif HAVE_PORTAUDIO
@@ -500,7 +500,7 @@
 %!   assert (devinfo.output(i).ID, audiodevinfo (0, devinfo.output(i).Name));
 %! endfor
 %! for i = 1:nin
-%!   assert (devinfo.input(i).ID, audiodevinfo (1, devinfo.input(i).Name));
+%!   assert (devinfo.input (i).ID, audiodevinfo (1, devinfo.input (i).Name));
 %! endfor
 */
 
@@ -592,21 +592,21 @@
   audioplayer *player = static_cast<audioplayer *> (data);
 
   if (! player)
-    error ("audio player callback function called without player");
+    error ("audioplayer callback function called without player");
 
   octave_value_list retval
     = octave::feval (player->octave_callback_function,
                      ovl (static_cast<double> (frames)), 1);
 
   if (retval.length () < 2)
-    error ("audio player callback function failed");
+    error ("audioplayer callback function failed");
 
   const Matrix sound = retval(0).matrix_value ();
   int return_status = retval(1).int_value ();
 
   if (frames - sound.rows () != 0 || sound.columns () < 1
       || sound.columns () > 2)
-    error ("audio player callback function failed");
+    error ("audioplayer callback function failed");
 
   // Don't multiply the audio data by scale_factor here.  Although it
   // does move the operation outside of the loops below, it also causes
@@ -682,7 +682,7 @@
       break;
 
     default:
-      error ("invalid player bit depth in callback function");
+      error ("invalid bit depth in audioplayer callback function");
     }
 
   return return_status;
@@ -696,7 +696,7 @@
   audioplayer *player = static_cast<audioplayer *> (data);
 
   if (! player)
-    error ("audio player callback function called without player");
+    error ("audioplayer callback function called without player");
 
   // Don't multiply the audio data by scale_factor here.  Although it would
   // move the operation outside of the loops below, it also causes a second
@@ -799,7 +799,7 @@
           break;
 
         default:
-          error ("invalid player bit depth in callback function");
+          error ("invalid bit depth in audioplayer callback function");
         }
     }
   else if (player->get_type () == TYPE_INT8)
@@ -863,12 +863,6 @@
   return paContinue;
 }
 
-static void
-safe_audioplayer_stop (audioplayer *player)
-{
-  player->stop ();
-}
-
 audioplayer::audioplayer (void)
   : octave_callback_function (nullptr),
     id (-1), fs (0), nbits (16), channels (0), sample_number (0),
@@ -1156,9 +1150,7 @@
   start = get_sample_number ();
   end = get_end_sample ();
 
-  octave::unwind_protect frame;
-
-  frame.add_fcn (safe_audioplayer_stop, this);
+  octave::unwind_action stop_audioplayer ([=] () { stop (); });
 
   for (unsigned int i = start; i < end; i += buffer_size)
     {
@@ -1349,7 +1341,7 @@
   audiorecorder *recorder = static_cast<audiorecorder *> (data);
 
   if (! recorder)
-    error ("audio recorder callback function called without recorder");
+    error ("audiorecorder callback function called without recorder");
 
   int channels = recorder->get_channels ();
 
@@ -1453,7 +1445,7 @@
   audiorecorder *recorder = static_cast<audiorecorder *> (data);
 
   if (! recorder)
-    error ("audio recorder callback function called without recorder");
+    error ("audiorecorder callback function called without recorder");
 
   int channels = recorder->get_channels ();
 
@@ -1543,12 +1535,6 @@
   return paContinue;
 }
 
-static void
-safe_audiorecorder_stop (audiorecorder *recorder)
-{
-  recorder->stop ();
-}
-
 audiorecorder::audiorecorder (void)
   : octave_callback_function (nullptr),
     id (-1), fs (8000), nbits (8), channels (1), sample_number (0),
@@ -1836,9 +1822,7 @@
 
   unsigned int frames = seconds * get_fs ();
 
-  octave::unwind_protect frame;
-
-  frame.add_fcn (safe_audiorecorder_stop, this);
+  octave::unwind_action stop_audiorecorder ([=] () { stop (); });
 
   for (unsigned int i = 0; i < frames; i += buffer_size)
     {
@@ -2429,7 +2413,7 @@
 
   audioplayer *pl = dynamic_cast<audioplayer *> (ncrep);
   if (! pl)
-    error ("audiodevinfo.cc get_player: dynamic_cast to audioplayer failed");
+    error ("audiodevinfo.cc (get_player): dynamic_cast to audioplayer failed");
 
   return pl;
 }
--- a/libinterp/dldfcn/audioread.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/dldfcn/audioread.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -49,14 +49,6 @@
 #  include <sndfile.h>
 #endif
 
-#if defined (HAVE_SNDFILE)
-static void
-safe_close (SNDFILE *file)
-{
-  sf_close (file);
-}
-#endif
-
 DEFUN_DLD (audioread, args, ,
            doc: /* -*- texinfo -*-
 @deftypefn  {} {[@var{y}, @var{fs}] =} audioread (@var{filename})
@@ -96,9 +88,7 @@
     error ("audioread: failed to open input file '%s': %s",
            filename.c_str (), sf_strerror (file));
 
-  octave::unwind_protect frame;
-
-  frame.add_fcn (safe_close, file);
+  octave::unwind_action close_open_file ([=] () { sf_close (file); });
 
   OCTAVE_LOCAL_BUFFER (double, data, info.frames * info.channels);
 
@@ -431,9 +421,7 @@
     error ("audiowrite: failed to open output file '%s': %s",
            filename.c_str (), sf_strerror (file));
 
-  octave::unwind_protect frame;
-
-  frame.add_fcn (safe_close, file);
+  octave::unwind_action close_open_file ([=] () { sf_close (file); });
 
   sf_command (file, SFC_SET_NORM_DOUBLE, nullptr, SF_TRUE);
   sf_command (file, SFC_SET_CLIPPING, nullptr, SF_TRUE) ;
@@ -626,9 +614,7 @@
     error ("audioinfo: failed to open input file '%s': %s",
            filename.c_str (), sf_strerror (file));
 
-  octave::unwind_protect frame;
-
-  frame.add_fcn (safe_close, file);
+  octave::unwind_action close_open_file ([=] () { sf_close (file); });
 
   octave_scalar_map result;
 
--- a/libinterp/dldfcn/convhulln.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/dldfcn/convhulln.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -58,12 +58,6 @@
 #  endif
 
 static void
-close_fcn (FILE *f)
-{
-  std::fclose (f);
-}
-
-static void
 free_qhull_memory ()
 {
   qh_freeqhull (! qh_ALL);
@@ -173,8 +167,6 @@
 
   boolT ismalloc = false;
 
-  octave::unwind_protect frame;
-
   // Replace the outfile pointer with stdout for debugging information.
 #if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM)
   FILE *outfile = std::fopen ("NUL", "w");
@@ -186,7 +178,7 @@
   if (! outfile)
     error ("convhulln: unable to create temporary file for output");
 
-  frame.add_fcn (close_fcn, outfile);
+  octave::unwind_action close_outfile ([=] () { std::fclose (outfile); });
 
   // qh_new_qhull command and points arguments are not const...
 
@@ -199,7 +191,7 @@
   int exitcode = qh_new_qhull (dim, num_points, points.fortran_vec (),
                                ismalloc, cmd_str, outfile, errfile);
 
-  frame.add_fcn (free_qhull_memory);
+  octave::unwind_action free_memory ([] () { free_qhull_memory (); });
 
   if (exitcode)
     error ("convhulln: qhull failed");
--- a/libinterp/dldfcn/gzip.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/dldfcn/gzip.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -703,7 +703,7 @@
 %!      test_function (test_dir, z)
 %!    unwind_protect_cleanup
 %!      confirm_recursive_rmdir (false, "local");
-%!      rmdir (test_dir, "s");
+%!      sts = rmdir (test_dir, "s");
 %!    end_unwind_protect
 %!  endfor
 %!endfunction
@@ -783,7 +783,7 @@
 %!function test_xzip_dir (test_dir, z) # bug #43431
 %!  fpaths = fullfile (test_dir, {"test1", "test2", "test3"});
 %!  md5s = cell (1, 3);
-%!  for idx = 1:numel(fpaths)
+%!  for idx = 1:numel (fpaths)
 %!    create_file (fpaths{idx}, rand (100, 1));
 %!    md5s(idx) = hash ("md5", fileread (fpaths{idx}));
 %!  endfor
@@ -793,7 +793,7 @@
 %!  z_files = strcat (fpaths, z.ext);
 %!  z_filelist = z.zip (test_dir);
 %!  assert (sort (z_filelist), z_files(:))
-%!  for idx = 1:numel(fpaths)
+%!  for idx = 1:numel (fpaths)
 %!    assert (exist (z_files{idx}), 2)
 %!    unlink_or_error (fpaths{idx});
 %!  endfor
@@ -803,12 +803,12 @@
 %!    uz_filelist = z.unzip (test_dir);
 %!  else
 %!    uz_filelist = cell (1, numel (z_filelist));
-%!    for idx = 1:numel(z_filelist)
+%!    for idx = 1:numel (z_filelist)
 %!      uz_filelist(idx) = z.unzip (z_filelist{idx});
 %!    endfor
 %!  endif
 %!  assert (sort (uz_filelist), fpaths(:)) # bug #48598
-%!  for idx = 1:numel(fpaths)
+%!  for idx = 1:numel (fpaths)
 %!    assert (hash ("md5", fileread (fpaths{idx})), md5s{idx})
 %!  endfor
 %!endfunction
@@ -826,7 +826,7 @@
 %!    error ("unable to create directory for test");
 %!  endif
 %!  unwind_protect
-%!    for idx = 1:numel(out_dirs)
+%!    for idx = 1:numel (out_dirs)
 %!      out_dir = out_dirs{idx};
 %!      uz_file = fullfile (out_dir, filename);
 %!      z_file = [uz_file z.ext];
@@ -842,8 +842,8 @@
 %!    endfor
 %!  unwind_protect_cleanup
 %!    confirm_recursive_rmdir (false, "local");
-%!    for idx = 1:numel(out_dirs)
-%!      rmdir (out_dirs{idx}, "s");
+%!    for idx = 1:numel (out_dirs)
+%!      sts = rmdir (out_dirs{idx}, "s");
 %!    endfor
 %!  end_unwind_protect
 %!endfunction
--- a/libinterp/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -33,7 +33,7 @@
   %reldir%/corefcn/default-defs.h \
   %reldir%/corefcn/graphics-props.cc \
   %reldir%/corefcn/graphics.h \
-  %reldir%/corefcn/mxarray.h \
+  %reldir%/corefcn/mxtypes.h \
   %reldir%/corefcn/oct-tex-parser.h \
   %reldir%/corefcn/oct-tex-symbols.cc \
   %reldir%/parse-tree/oct-gperf.h \
@@ -66,7 +66,7 @@
   %reldir%/corefcn/default-defs.h \
   %reldir%/corefcn/graphics-props.cc \
   %reldir%/corefcn/graphics.h \
-  %reldir%/corefcn/mxarray.h \
+  %reldir%/corefcn/mxtypes.h \
   %reldir%/corefcn/oct-errno.cc \
   %reldir%/liboctinterp-build-info.cc \
   %reldir%/operators/ops.cc
@@ -99,7 +99,7 @@
   %reldir%/builtin-defun-decls.h \
   %reldir%/corefcn/graphics-props.cc \
   %reldir%/corefcn/graphics.h \
-  %reldir%/corefcn/mxarray.h
+  %reldir%/corefcn/mxtypes.h
 
 DIST_SRC += \
   %reldir%/octave.cc \
@@ -129,7 +129,7 @@
   %reldir%/builtins.cc \
   %reldir%/corefcn/default-defs.h \
   %reldir%/corefcn/graphics.h \
-  %reldir%/corefcn/mxarray.h \
+  %reldir%/corefcn/mxtypes.h \
   %reldir%/corefcn/oct-errno.cc \
   %reldir%/liboctinterp-build-info.cc \
   %reldir%/operators/ops.cc
--- a/libinterp/octave-value/cdef-class.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/cdef-class.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -869,7 +869,7 @@
     tree_evaluator& tw = interp.get_evaluator ();
 
     tw.push_dummy_scope (full_class_name);
-    frame.add_method (tw, &octave::tree_evaluator::pop_scope);
+    frame.add_method (tw, &tree_evaluator::pop_scope);
 
     std::list<cdef_class> slist;
 
--- a/libinterp/octave-value/cdef-object.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/cdef-object.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -326,7 +326,7 @@
             cdef_object rhs_obj = to_cdef (rhs);
 
             if (rhs_obj.get_class () != get_class ())
-              error ("can't assign %s object into array of %s objects.",
+              error ("can't assign %s object into array of %s objects",
                      rhs_obj.class_name ().c_str (),
                      class_name ().c_str ());
 
--- a/libinterp/octave-value/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -52,10 +52,12 @@
   %reldir%/ov-flt-re-mat.h \
   %reldir%/ov-java.h \
   %reldir%/ov-lazy-idx.h \
+  %reldir%/ov-magic-int.h \
   %reldir%/ov-mex-fcn.h \
   %reldir%/ov-null-mat.h \
   %reldir%/ov-oncleanup.h \
   %reldir%/ov-perm.h \
+  %reldir%/ov-range-traits.h \
   %reldir%/ov-range.h \
   %reldir%/ov-re-diag.h \
   %reldir%/ov-re-mat.h \
@@ -116,6 +118,7 @@
   %reldir%/ov-flt-re-mat.cc \
   %reldir%/ov-java.cc \
   %reldir%/ov-lazy-idx.cc \
+  %reldir%/ov-magic-int.cc \
   %reldir%/ov-mex-fcn.cc \
   %reldir%/ov-null-mat.cc \
   %reldir%/ov-oncleanup.cc \
--- a/libinterp/octave-value/ov-base-diag.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-base-diag.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -130,7 +130,7 @@
                   retval = rm;
                 }
               else
-                retval = to_dense ().do_index_op (idx, resize_ok);
+                retval = to_dense ().index_op (idx, resize_ok);
             }
         }
       catch (octave::index_exception& e)
@@ -141,7 +141,7 @@
         }
     }
   else
-    retval = to_dense ().do_index_op (idx, resize_ok);
+    retval = to_dense ().index_op (idx, resize_ok);
 
   return retval;
 }
@@ -543,9 +543,9 @@
 
 template <typename DMT, typename MT>
 mxArray *
-octave_base_diag<DMT, MT>::as_mxArray (void) const
+octave_base_diag<DMT, MT>::as_mxArray (bool interleaved) const
 {
-  return to_dense ().as_mxArray ();
+  return to_dense ().as_mxArray (interleaved);
 }
 
 template <typename DMT, typename MT>
--- a/libinterp/octave-value/ov-base-diag.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-base-diag.h	Thu Nov 19 13:08:00 2020 -0800
@@ -224,7 +224,7 @@
              oct_data_conv::data_type output_type, int skip,
              octave::mach_info::float_format flt_fmt) const;
 
-  mxArray * as_mxArray (void) const;
+  mxArray * as_mxArray (bool interleaved) const;
 
   bool print_as_scalar (void) const;
 
--- a/libinterp/octave-value/ov-base-mat.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-base-mat.h	Thu Nov 19 13:08:00 2020 -0800
@@ -50,6 +50,8 @@
 {
 public:
 
+  typedef MT object_type;
+
   octave_base_matrix (void)
     : octave_base_value (), matrix (), typ (), idx_cache () { }
 
--- a/libinterp/octave-value/ov-base-scalar.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-base-scalar.h	Thu Nov 19 13:08:00 2020 -0800
@@ -49,6 +49,8 @@
 {
 public:
 
+  typedef ST scalar_type;
+
   octave_base_scalar (void)
     : octave_base_value (), scalar () { }
 
--- a/libinterp/octave-value/ov-base.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-base.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -86,13 +86,13 @@
   return retval;
 }
 
-std::string btyp_class_name[btyp_num_types] =
+std::string btyp_class_name[btyp_num_types+1] =
 {
   "double", "single", "double", "single",
   "int8", "int16", "int32", "int64",
   "uint8", "uint16", "uint32", "uint64",
   "logical", "char",
-  "struct", "cell", "function_handle"
+  "struct", "cell", "function_handle", "unknown"
 };
 
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_base_value,
@@ -811,12 +811,66 @@
   err_wrong_type_arg ("octave_base_value::cellstr_value()", type_name ());
 }
 
-Range
+octave::range<float>
+octave_base_value::float_range_value (void) const
+{
+  err_wrong_type_arg ("octave_base_value::float_range_value()", type_name ());
+}
+
+octave::range<double>
 octave_base_value::range_value (void) const
 {
   err_wrong_type_arg ("octave_base_value::range_value()", type_name ());
 }
 
+octave::range<octave_int8>
+octave_base_value::int8_range_value (void) const
+{
+  err_wrong_type_arg ("octave_base_value::int8_range_value()", type_name ());
+}
+
+octave::range<octave_int16>
+octave_base_value::int16_range_value (void) const
+{
+  err_wrong_type_arg ("octave_base_value::int16_range_value()", type_name ());
+}
+
+octave::range<octave_int32>
+octave_base_value::int32_range_value (void) const
+{
+  err_wrong_type_arg ("octave_base_value::int32_range_value()", type_name ());
+}
+
+octave::range<octave_int64>
+octave_base_value::int64_range_value (void) const
+{
+  err_wrong_type_arg ("octave_base_value::int64_range_value()", type_name ());
+}
+
+octave::range<octave_uint8>
+octave_base_value::uint8_range_value (void) const
+{
+  err_wrong_type_arg ("octave_base_value::uint8_range_value()", type_name ());
+}
+
+octave::range<octave_uint16>
+octave_base_value::uint16_range_value (void) const
+{
+  err_wrong_type_arg ("octave_base_value::uint16_range_value()", type_name ());
+}
+
+octave::range<octave_uint32>
+octave_base_value::uint32_range_value (void) const
+{
+  err_wrong_type_arg ("octave_base_value::uint32_range_value()", type_name ());
+}
+
+octave::range<octave_uint64>
+octave_base_value::uint64_range_value (void) const
+{
+  err_wrong_type_arg ("octave_base_value::uint64_range_value()", type_name ());
+}
+
 octave_map
 octave_base_value::map_value (void) const
 {
@@ -965,7 +1019,7 @@
 }
 
 mxArray *
-octave_base_value::as_mxArray (void) const
+octave_base_value::as_mxArray (bool) const
 {
   return nullptr;
 }
--- a/libinterp/octave-value/ov-base.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-base.h	Thu Nov 19 13:08:00 2020 -0800
@@ -91,8 +91,7 @@
   btyp_num_types = btyp_unknown
 };
 
-extern OCTINTERP_API std::string
-btyp_class_name [btyp_num_types];
+extern OCTINTERP_API std::string btyp_class_name [];
 
 inline bool btyp_isnumeric (builtin_type_t btyp)
 { return btyp <= btyp_uint64; }
@@ -128,27 +127,40 @@
   static const builtin_type_t btyp = btyp_unknown;
 };
 
-#define DEF_CLASS_TO_BTYP(CLASS,BTYP)           \
+template <builtin_type_t BTYP>
+struct btyp_to_class
+{
+  typedef void type;
+};
+
+#define DEF_BTYP_TRAITS(BTYP, CLASS)            \
   template <>                                   \
   struct class_to_btyp<CLASS>                   \
   {                                             \
     static const builtin_type_t btyp = BTYP;    \
+  };                                            \
+                                                \
+  template <>                                   \
+  struct btyp_to_class<BTYP>                    \
+  {                                             \
+    typedef CLASS type;                         \
   }
 
-DEF_CLASS_TO_BTYP (double, btyp_double);
-DEF_CLASS_TO_BTYP (float, btyp_float);
-DEF_CLASS_TO_BTYP (Complex, btyp_complex);
-DEF_CLASS_TO_BTYP (FloatComplex, btyp_float_complex);
-DEF_CLASS_TO_BTYP (octave_int8, btyp_int8);
-DEF_CLASS_TO_BTYP (octave_int16, btyp_int16);
-DEF_CLASS_TO_BTYP (octave_int32, btyp_int32);
-DEF_CLASS_TO_BTYP (octave_int64, btyp_int64);
-DEF_CLASS_TO_BTYP (octave_uint8, btyp_uint8);
-DEF_CLASS_TO_BTYP (octave_uint16, btyp_uint16);
-DEF_CLASS_TO_BTYP (octave_uint32, btyp_uint32);
-DEF_CLASS_TO_BTYP (octave_uint64, btyp_uint64);
-DEF_CLASS_TO_BTYP (bool, btyp_bool);
-DEF_CLASS_TO_BTYP (char, btyp_char);
+DEF_BTYP_TRAITS (btyp_double, double);
+DEF_BTYP_TRAITS (btyp_float, float);
+DEF_BTYP_TRAITS (btyp_complex, Complex);
+DEF_BTYP_TRAITS (btyp_float_complex, FloatComplex);
+DEF_BTYP_TRAITS (btyp_int8, octave_int8);
+DEF_BTYP_TRAITS (btyp_int16, octave_int16);
+DEF_BTYP_TRAITS (btyp_int32, octave_int32);
+DEF_BTYP_TRAITS (btyp_int64, octave_int64);
+DEF_BTYP_TRAITS (btyp_uint8, octave_uint8);
+DEF_BTYP_TRAITS (btyp_uint16, octave_uint16);
+DEF_BTYP_TRAITS (btyp_uint32, octave_uint32);
+DEF_BTYP_TRAITS (btyp_uint64, octave_uint64);
+DEF_BTYP_TRAITS (btyp_bool, bool);
+DEF_BTYP_TRAITS (btyp_char, char);
+
 
 // T_ID is the type id of struct objects, set by register_type().
 // T_NAME is the type name of struct objects.
@@ -177,22 +189,35 @@
     static const std::string t_name;                                    \
     static const std::string c_name;
 
+#define DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS(cls, type)           \
+  template <> void cls<type>::register_type (void);                     \
+  template <> void cls<type>::register_type (octave::type_info&);       \
+  template <> int cls<type>::t_id;                                      \
+  template <> const std::string cls<type>::t_name;                      \
+  template <> const std::string cls<type>::c_name;
+
+#define DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA_INTERNAL(tspec, t, n, c)    \
+  tspec int t::t_id (-1);                                               \
+  tspec const std::string t::t_name (n);                                \
+  tspec const std::string t::c_name (c);                                \
+  tspec void t::register_type (void)                                    \
+  {                                                                     \
+    octave::type_info& type_info                                        \
+      = octave::__get_type_info__ (#t "::register_type");               \
+                                                                        \
+    register_type (type_info);                                          \
+  }                                                                     \
+  tspec void t::register_type (octave::type_info& ti)                   \
+  {                                                                     \
+    octave_value v (new t ());                                          \
+    t_id = ti.register_type (t::t_name, t::c_name, v);                  \
+  }
+
+#define DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA(t, n, c)           \
+  DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA_INTERNAL (template <>, t, n, c)
+
 #define DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(t, n, c)            \
-  int t::t_id (-1);                                             \
-  const std::string t::t_name (n);                              \
-  const std::string t::c_name (c);                              \
-  void t::register_type (void)                                  \
-  {                                                             \
-    octave::type_info& type_info                                \
-      = octave::__get_type_info__ (#t "::register_type");       \
-                                                                \
-    register_type (type_info);                                  \
-  }                                                             \
-  void t::register_type (octave::type_info& ti)                 \
-  {                                                             \
-    octave_value v (new t ());                                  \
-    t_id = ti.register_type (t::t_name, t::c_name, v);          \
-  }
+  DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA_INTERNAL ( , t, n, c)
 
 // A base value type, so that derived types only have to redefine what
 // they need (if they are derived from octave_base_value instead of
@@ -454,6 +479,8 @@
 
   virtual bool is_true (void) const { return false; }
 
+  virtual bool is_magic_int (void) const { return false; }
+
   virtual bool isnull (void) const { return false; }
 
   virtual bool is_constant (void) const { return false; }
@@ -595,7 +622,25 @@
 
   virtual Array<std::string> cellstr_value (void) const;
 
-  virtual Range range_value (void) const;
+  virtual octave::range<float> float_range_value (void) const;
+
+  virtual octave::range<double> range_value (void) const;
+
+  virtual octave::range<octave_int8> int8_range_value (void) const;
+
+  virtual octave::range<octave_int16> int16_range_value (void) const;
+
+  virtual octave::range<octave_int32> int32_range_value (void) const;
+
+  virtual octave::range<octave_int64> int64_range_value (void) const;
+
+  virtual octave::range<octave_uint8> uint8_range_value (void) const;
+
+  virtual octave::range<octave_uint16> uint16_range_value (void) const;
+
+  virtual octave::range<octave_uint32> uint32_range_value (void) const;
+
+  virtual octave::range<octave_uint64> uint64_range_value (void) const;
 
   virtual octave_map map_value (void) const;
 
@@ -694,7 +739,7 @@
 
   virtual octave_idx_type * mex_get_jc (void) const { return nullptr; }
 
-  virtual mxArray * as_mxArray (void) const;
+  virtual mxArray * as_mxArray (bool interleaved) const;
 
   virtual octave_value diag (octave_idx_type k = 0) const;
 
--- a/libinterp/octave-value/ov-bool-mat.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-bool-mat.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -566,18 +566,18 @@
 }
 
 mxArray *
-octave_bool_matrix::as_mxArray (void) const
+octave_bool_matrix::as_mxArray (bool interleaved) const
 {
-  mxArray *retval = new mxArray (mxLOGICAL_CLASS, dims (), mxREAL);
+  mxArray *retval = new mxArray (interleaved, mxLOGICAL_CLASS, dims (), mxREAL);
 
-  bool *pr = static_cast<bool *> (retval->get_data ());
+  mxLogical *pd = static_cast<mxLogical *> (retval->get_data ());
 
   mwSize nel = numel ();
 
-  const bool *p = matrix.data ();
+  const bool *pdata = matrix.data ();
 
   for (mwIndex i = 0; i < nel; i++)
-    pr[i] = p[i];
+    pd[i] = pdata[i];
 
   return retval;
 }
--- a/libinterp/octave-value/ov-bool-mat.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-bool-mat.h	Thu Nov 19 13:08:00 2020 -0800
@@ -233,7 +233,7 @@
   // You should not use it anywhere else.
   void * mex_get_data (void) const { return matrix.mex_get_data (); }
 
-  mxArray * as_mxArray (void) const;
+  mxArray * as_mxArray (bool interleaved) const;
 
   // Mapper functions are converted to double for treatment
   octave_value map (unary_mapper_t umap) const
--- a/libinterp/octave-value/ov-bool-sparse.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-bool-sparse.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -802,23 +802,34 @@
 }
 
 mxArray *
-octave_sparse_bool_matrix::as_mxArray (void) const
+octave_sparse_bool_matrix::as_mxArray (bool interleaved) const
 {
   mwSize nz = nzmax ();
-  mxArray *retval = new mxArray (mxLOGICAL_CLASS, rows (), columns (),
-                                 nz, mxREAL);
-  bool *pr = static_cast<bool *> (retval->get_data ());
+  mwSize nr = rows ();
+  mwSize nc = columns ();
+
+  mxArray *retval = new mxArray (interleaved, mxLOGICAL_CLASS, nr, nc, nz,
+                                 mxREAL);
+
+  mxLogical *pd = static_cast<mxLogical *> (retval->get_data ());
   mwIndex *ir = retval->get_ir ();
-  mwIndex *jc = retval->get_jc ();
+
+  const bool *pdata = matrix.data ();
+  const octave_idx_type *pridx = matrix.ridx ();
 
   for (mwIndex i = 0; i < nz; i++)
     {
-      pr[i] = matrix.data (i);
-      ir[i] = matrix.ridx (i);
+      pd[i] = pdata[i];
+
+      ir[i] = pridx[i];
     }
 
-  for (mwIndex i = 0; i < columns () + 1; i++)
-    jc[i] = matrix.cidx (i);
+  mwIndex *jc = retval->get_jc ();
+
+  const octave_idx_type *pcidx = matrix.cidx ();
+
+  for (mwIndex i = 0; i < nc + 1; i++)
+    jc[i] = pcidx[i];
 
   return retval;
 }
--- a/libinterp/octave-value/ov-bool-sparse.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-bool-sparse.h	Thu Nov 19 13:08:00 2020 -0800
@@ -143,7 +143,7 @@
 
   bool load_hdf5 (octave_hdf5_id loc_id, const char *name);
 
-  mxArray * as_mxArray (void) const;
+  mxArray * as_mxArray (bool interleaved) const;
 
   // Mapper functions are converted to double for treatment
   octave_value map (unary_mapper_t umap) const
--- a/libinterp/octave-value/ov-bool.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-bool.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -91,7 +91,7 @@
 
   octave_value tmp (new octave_bool_matrix (bool_matrix_value ()));
 
-  return tmp.do_index_op (idx, resize_ok);
+  return tmp.index_op (idx, resize_ok);
 }
 
 octave_value
@@ -188,7 +188,7 @@
 {
   double d = double_value ();
 
-  octave_write_double (os, d);
+  octave::write_value<double> (os, d);
   os << "\n";
 
   return true;
@@ -197,7 +197,7 @@
 bool
 octave_bool::load_ascii (std::istream& is)
 {
-  scalar = (octave_read_value<double> (is) != 0.0);
+  scalar = (octave::read_value<double> (is) != 0.0);
 
   if (! is)
     error ("load: failed to load scalar constant");
@@ -312,13 +312,13 @@
 }
 
 mxArray *
-octave_bool::as_mxArray (void) const
+octave_bool::as_mxArray (bool interleaved) const
 {
-  mxArray *retval = new mxArray (mxLOGICAL_CLASS, 1, 1, mxREAL);
+  mxArray *retval = new mxArray (interleaved, mxLOGICAL_CLASS, 1, 1, mxREAL);
 
-  bool *pr = static_cast<bool *> (retval->get_data ());
+  mxLogical *pd = static_cast<mxLogical *> (retval->get_data ());
 
-  pr[0] = scalar;
+  pd[0] = scalar;
 
   return retval;
 }
--- a/libinterp/octave-value/ov-bool.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-bool.h	Thu Nov 19 13:08:00 2020 -0800
@@ -246,7 +246,7 @@
                      skip, flt_fmt);
   }
 
-  mxArray * as_mxArray (void) const;
+  mxArray * as_mxArray (bool interleaved) const;
 
   // Mapper functions are converted to double for treatment
   octave_value map (unary_mapper_t umap) const
--- a/libinterp/octave-value/ov-cell.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-cell.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -1275,7 +1275,7 @@
 /*
 ## This might work on some system someday, but for now, who has a system
 ## where a 16 yottabyte array can be allocated?  See bug #50934.
-%!error <out of memory> cell (1e24, 1);
+%!error <out of memory> cell (1e24, 1)
 */
 
 DEFUN (iscellstr, args, ,
@@ -1406,9 +1406,9 @@
 */
 
 mxArray *
-octave_cell::as_mxArray (void) const
+octave_cell::as_mxArray (bool interleaved) const
 {
-  mxArray *retval = new mxArray (dims ());
+  mxArray *retval = new mxArray (interleaved, dims ());
 
   mxArray **elts = static_cast<mxArray **> (retval->get_data ());
 
@@ -1417,7 +1417,7 @@
   const octave_value *p = matrix.data ();
 
   for (mwIndex i = 0; i < nel; i++)
-    elts[i] = new mxArray (p[i]);
+    elts[i] = new mxArray (interleaved, p[i]);
 
   return retval;
 }
--- a/libinterp/octave-value/ov-cell.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-cell.h	Thu Nov 19 13:08:00 2020 -0800
@@ -172,7 +172,7 @@
 
   octave_value map (unary_mapper_t umap) const;
 
-  mxArray * as_mxArray (void) const;
+  mxArray * as_mxArray (bool interleaved) const;
 
   // Unsafe.  This function exists to support the MEX interface.
   // You should not use it anywhere else.
--- a/libinterp/octave-value/ov-ch-mat.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-ch-mat.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -222,18 +222,18 @@
 }
 
 mxArray *
-octave_char_matrix::as_mxArray (void) const
+octave_char_matrix::as_mxArray (bool interleaved) const
 {
-  mxArray *retval = new mxArray (mxCHAR_CLASS, dims (), mxREAL);
+  mxArray *retval = new mxArray (interleaved, mxCHAR_CLASS, dims (), mxREAL);
 
-  mxChar *pr = static_cast<mxChar *> (retval->get_data ());
+  mxChar *pd = static_cast<mxChar *> (retval->get_data ());
 
   mwSize nel = numel ();
 
-  const char *p = matrix.data ();
+  const char *pdata = matrix.data ();
 
   for (mwIndex i = 0; i < nel; i++)
-    pr[i] = p[i];
+    pd[i] = pdata[i];
 
   return retval;
 }
--- a/libinterp/octave-value/ov-ch-mat.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-ch-mat.h	Thu Nov 19 13:08:00 2020 -0800
@@ -167,7 +167,7 @@
   // You should not use it anywhere else.
   void * mex_get_data (void) const { return matrix.mex_get_data (); }
 
-  mxArray * as_mxArray (void) const;
+  mxArray * as_mxArray (bool interleaved) const;
 
   octave_value map (unary_mapper_t umap) const;
 };
--- a/libinterp/octave-value/ov-class.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-class.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -579,8 +579,7 @@
           if (obsolete_copies == 0 && meth.is_user_function ()
               && meth.user_function_value ()->subsasgn_optimization_ok ())
             {
-              octave::unwind_protect frame;
-              frame.protect_var (obsolete_copies);
+              octave::unwind_protect_var<int> restore_var (obsolete_copies);
               obsolete_copies = 2;
 
               tmp = octave::feval (meth.function_value (), args);
@@ -838,8 +837,8 @@
   // (why this inconsistency Mathworks?), and so we must
   // add one to the value returned as the index_vector method
   // expects it to be one based.
-  return do_binary_op (octave_value::op_add, tmp (0),
-                       octave_value (1.0)).index_vector (require_integers);
+  return octave::binary_op (octave_value::op_add, tmp (0),
+                               octave_value (1.0)).index_vector (require_integers);
 }
 
 size_t
@@ -1018,8 +1017,6 @@
 void
 octave_class::print_raw (std::ostream& os, bool) const
 {
-  octave::unwind_protect frame;
-
   indent (os);
   os << "  <class " << class_name () << '>';
   newline (os);
@@ -1638,7 +1635,7 @@
 }
 
 mxArray *
-octave_class::as_mxArray (void) const
+octave_class::as_mxArray (bool) const
 {
   err_wrong_type_arg ("octave_class::as_mxArray ()", type_name ());
 }
--- a/libinterp/octave-value/ov-class.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-class.h	Thu Nov 19 13:08:00 2020 -0800
@@ -205,7 +205,7 @@
 
   bool load_hdf5 (octave_hdf5_id loc_id, const char *name);
 
-  mxArray * as_mxArray (void) const;
+  mxArray * as_mxArray (bool interleaved) const;
 
 private:
   octave_map map;
--- a/libinterp/octave-value/ov-complex.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-complex.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -140,7 +140,7 @@
 
   octave_value tmp (new octave_complex_matrix (complex_matrix_value ()));
 
-  return tmp.do_index_op (idx, resize_ok);
+  return tmp.index_op (idx, resize_ok);
 }
 
 // Can't make an index_vector from a complex number.  Throw an error.
@@ -313,7 +313,7 @@
 {
   Complex c = complex_value ();
 
-  octave_write_complex (os, c);
+  octave::write_value<Complex> (os, c);
 
   os << "\n";
 
@@ -323,7 +323,7 @@
 bool
 octave_complex::load_ascii (std::istream& is)
 {
-  scalar = octave_read_value<Complex> (is);
+  scalar = octave::read_value<Complex> (is);
 
   if (! is)
     error ("load: failed to load complex scalar constant");
@@ -472,15 +472,26 @@
 }
 
 mxArray *
-octave_complex::as_mxArray (void) const
+octave_complex::as_mxArray (bool interleaved) const
 {
-  mxArray *retval = new mxArray (mxDOUBLE_CLASS, 1, 1, mxCOMPLEX);
+  mxArray *retval = new mxArray (interleaved, mxDOUBLE_CLASS, 1, 1, mxCOMPLEX);
+
+  if (interleaved)
+    {
+      mxComplexDouble *pd
+        = reinterpret_cast<mxComplexDouble *> (retval->get_complex_doubles ());
 
-  double *pr = static_cast<double *> (retval->get_data ());
-  double *pi = static_cast<double *> (retval->get_imag_data ());
+      pd[0].real = scalar.real ();
+      pd[0].imag = scalar.imag ();
+    }
+  else
+    {
+      mxDouble *pr = static_cast<mxDouble *> (retval->get_data ());
+      mxDouble *pi = static_cast<mxDouble *> (retval->get_imag_data ());
 
-  pr[0] = scalar.real ();
-  pi[0] = scalar.imag ();
+      pr[0] = scalar.real ();
+      pi[0] = scalar.imag ();
+    }
 
   return retval;
 }
--- a/libinterp/octave-value/ov-complex.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-complex.h	Thu Nov 19 13:08:00 2020 -0800
@@ -195,7 +195,7 @@
                      skip, flt_fmt);
   }
 
-  mxArray * as_mxArray (void) const;
+  mxArray * as_mxArray (bool interleaved) const;
 
   octave_value map (unary_mapper_t umap) const;
 
--- a/libinterp/octave-value/ov-cx-mat.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-cx-mat.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -724,21 +724,36 @@
 }
 
 mxArray *
-octave_complex_matrix::as_mxArray (void) const
+octave_complex_matrix::as_mxArray (bool interleaved) const
 {
-  mxArray *retval = new mxArray (mxDOUBLE_CLASS, dims (), mxCOMPLEX);
-
-  double *pr = static_cast<double *> (retval->get_data ());
-  double *pi = static_cast<double *> (retval->get_imag_data ());
+  mxArray *retval = new mxArray (interleaved, mxDOUBLE_CLASS, dims (),
+                                 mxCOMPLEX);
 
   mwSize nel = numel ();
 
-  const Complex *p = matrix.data ();
+  const Complex *pdata = matrix.data ();
+
+  if (interleaved)
+    {
+      mxComplexDouble *pd
+        = static_cast<mxComplexDouble *> (retval->get_data ());
 
-  for (mwIndex i = 0; i < nel; i++)
+      for (mwIndex i = 0; i < nel; i++)
+        {
+          pd[i].real = pdata[i].real ();
+          pd[i].imag = pdata[i].imag ();
+        }
+    }
+  else
     {
-      pr[i] = std::real (p[i]);
-      pi[i] = std::imag (p[i]);
+      mxDouble *pr = static_cast<mxDouble *> (retval->get_data ());
+      mxDouble *pi = static_cast<mxDouble *> (retval->get_imag_data ());
+
+      for (mwIndex i = 0; i < nel; i++)
+        {
+          pr[i] = pdata[i].real ();
+          pi[i] = pdata[i].imag ();
+        }
     }
 
   return retval;
--- a/libinterp/octave-value/ov-cx-mat.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-cx-mat.h	Thu Nov 19 13:08:00 2020 -0800
@@ -175,7 +175,7 @@
 
   void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
 
-  mxArray * as_mxArray (void) const;
+  mxArray * as_mxArray (bool interleaved) const;
 
   octave_value map (unary_mapper_t umap) const;
 
--- a/libinterp/octave-value/ov-cx-sparse.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-cx-sparse.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -874,26 +874,53 @@
 }
 
 mxArray *
-octave_sparse_complex_matrix::as_mxArray (void) const
+octave_sparse_complex_matrix::as_mxArray (bool interleaved) const
 {
   mwSize nz = nzmax ();
-  mxArray *retval = new mxArray (mxDOUBLE_CLASS, rows (), columns (),
-                                 nz, mxCOMPLEX);
-  double *pr = static_cast<double *> (retval->get_data ());
-  double *pi = static_cast<double *> (retval->get_imag_data ());
+  mwSize nr = rows ();
+  mwSize nc = columns ();
+
+  mxArray *retval = new mxArray (interleaved, mxDOUBLE_CLASS, nr, nc, nz,
+                                 mxCOMPLEX);
+
   mwIndex *ir = retval->get_ir ();
+
+  const Complex *pdata = matrix.data ();
+  const octave_idx_type *pridx = matrix.ridx ();
+
+  if (interleaved)
+    {
+      mxComplexDouble *pd
+        = static_cast<mxComplexDouble *> (retval->get_data ());
+
+      for (mwIndex i = 0; i < nz; i++)
+        {
+          pd[i].real = pdata[i].real ();
+          pd[i].imag = pdata[i].imag ();
+
+          ir[i] = pridx[i];
+        }
+    }
+  else
+    {
+      mxDouble *pr = static_cast<mxDouble *> (retval->get_data ());
+      mxDouble *pi = static_cast<mxDouble *> (retval->get_imag_data ());
+
+      for (mwIndex i = 0; i < nz; i++)
+        {
+          pr[i] = pdata[i].real ();
+          pi[i] = pdata[i].imag ();
+
+          ir[i] = pridx[i];
+        }
+    }
+
   mwIndex *jc = retval->get_jc ();
 
-  for (mwIndex i = 0; i < nz; i++)
-    {
-      Complex val = matrix.data (i);
-      pr[i] = val.real ();
-      pi[i] = val.imag ();
-      ir[i] = matrix.ridx (i);
-    }
+  const octave_idx_type *pcidx = matrix.cidx ();
 
-  for (mwIndex i = 0; i < columns () + 1; i++)
-    jc[i] = matrix.cidx (i);
+  for (mwIndex i = 0; i < nc + 1; i++)
+    jc[i] = pcidx[i];
 
   return retval;
 }
--- a/libinterp/octave-value/ov-cx-sparse.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-cx-sparse.h	Thu Nov 19 13:08:00 2020 -0800
@@ -149,7 +149,7 @@
 
   bool load_hdf5 (octave_hdf5_id loc_id, const char *name);
 
-  mxArray * as_mxArray (void) const;
+  mxArray * as_mxArray (bool interleaved) const;
 
   octave_value map (unary_mapper_t umap) const;
 
--- a/libinterp/octave-value/ov-fcn-handle.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-fcn-handle.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -598,7 +598,6 @@
       case '{':
       case '.':
         error ("function handle cannot be indexed with %c", type[0]);
-        break;
 
       default:
         panic_impossible ();
@@ -1031,7 +1030,7 @@
   }
 
   bool simple_fcn_handle::load_binary (std::istream& is, bool,
-                                       octave::mach_info::float_format)
+                                       mach_info::float_format)
   {
     return is.good ();
   }
@@ -1337,7 +1336,7 @@
   }
 
   bool scoped_fcn_handle::load_binary (std::istream& is, bool swap,
-                                       octave::mach_info::float_format fmt)
+                                       mach_info::float_format fmt)
   {
     octave_cell ov_cell;
     ov_cell.load_binary (is, swap, fmt);
--- a/libinterp/octave-value/ov-float.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-float.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -79,7 +79,7 @@
 
   octave_value tmp (new octave_float_matrix (float_matrix_value ()));
 
-  return tmp.do_index_op (idx, resize_ok);
+  return tmp.index_op (idx, resize_ok);
 }
 
 octave_value
@@ -200,7 +200,7 @@
 {
   float d = float_value ();
 
-  octave_write_float (os, d);
+  octave::write_value<float> (os, d);
 
   os << "\n";
 
@@ -210,7 +210,7 @@
 bool
 octave_float_scalar::load_ascii (std::istream& is)
 {
-  scalar = octave_read_value<float> (is);
+  scalar = octave::read_value<float> (is);
   if (! is)
     error ("load: failed to load scalar constant");
 
@@ -335,13 +335,13 @@
 }
 
 mxArray *
-octave_float_scalar::as_mxArray (void) const
+octave_float_scalar::as_mxArray (bool interleaved) const
 {
-  mxArray *retval = new mxArray (mxSINGLE_CLASS, 1, 1, mxREAL);
+  mxArray *retval = new mxArray (interleaved, mxSINGLE_CLASS, 1, 1, mxREAL);
 
-  float *pr = static_cast<float *> (retval->get_data ());
+  mxSingle *pd = static_cast<mxSingle *> (retval->get_data ());
 
-  pr[0] = scalar;
+  pd[0] = scalar;
 
   return retval;
 }
--- a/libinterp/octave-value/ov-float.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-float.h	Thu Nov 19 13:08:00 2020 -0800
@@ -266,7 +266,7 @@
                      skip, flt_fmt);
   }
 
-  mxArray * as_mxArray (void) const;
+  mxArray * as_mxArray (bool interleaved) const;
 
   octave_value map (unary_mapper_t umap) const;
 
--- a/libinterp/octave-value/ov-flt-complex.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-flt-complex.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -91,7 +91,7 @@
 
   octave_value tmp (new octave_float_complex_matrix (float_complex_matrix_value ()));
 
-  return tmp.do_index_op (idx, resize_ok);
+  return tmp.index_op (idx, resize_ok);
 }
 
 double
@@ -254,7 +254,7 @@
 {
   FloatComplex c = float_complex_value ();
 
-  octave_write_float_complex (os, c);
+  octave::write_value<FloatComplex> (os, c);
 
   os << "\n";
 
@@ -264,7 +264,7 @@
 bool
 octave_float_complex::load_ascii (std::istream& is)
 {
-  scalar = octave_read_value<FloatComplex> (is);
+  scalar = octave::read_value<FloatComplex> (is);
 
   if (! is)
     error ("load: failed to load complex scalar constant");
@@ -414,15 +414,26 @@
 }
 
 mxArray *
-octave_float_complex::as_mxArray (void) const
+octave_float_complex::as_mxArray (bool interleaved) const
 {
-  mxArray *retval = new mxArray (mxSINGLE_CLASS, 1, 1, mxCOMPLEX);
+  mxArray *retval = new mxArray (interleaved, mxSINGLE_CLASS, 1, 1, mxCOMPLEX);
+
+  if (interleaved)
+    {
+      mxComplexSingle *pd
+        = static_cast<mxComplexSingle *> (retval->get_data ());
 
-  float *pr = static_cast<float *> (retval->get_data ());
-  float *pi = static_cast<float *> (retval->get_imag_data ());
+      pd[0].real = scalar.real ();
+      pd[0].imag = scalar.imag ();
+    }
+  else
+    {
+      mxSingle *pr = static_cast<mxSingle *> (retval->get_data ());
+      mxSingle *pi = static_cast<mxSingle *> (retval->get_imag_data ());
 
-  pr[0] = scalar.real ();
-  pi[0] = scalar.imag ();
+      pr[0] = scalar.real ();
+      pi[0] = scalar.imag ();
+    }
 
   return retval;
 }
--- a/libinterp/octave-value/ov-flt-complex.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-flt-complex.h	Thu Nov 19 13:08:00 2020 -0800
@@ -191,7 +191,7 @@
                      skip, flt_fmt);
   }
 
-  mxArray * as_mxArray (void) const;
+  mxArray * as_mxArray (bool interleaved) const;
 
   octave_value map (unary_mapper_t umap) const;
 
--- a/libinterp/octave-value/ov-flt-cx-mat.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-flt-cx-mat.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -676,21 +676,36 @@
 }
 
 mxArray *
-octave_float_complex_matrix::as_mxArray (void) const
+octave_float_complex_matrix::as_mxArray (bool interleaved) const
 {
-  mxArray *retval = new mxArray (mxSINGLE_CLASS, dims (), mxCOMPLEX);
-
-  float *pr = static_cast<float *> (retval->get_data ());
-  float *pi = static_cast<float *> (retval->get_imag_data ());
+  mxArray *retval = new mxArray (interleaved, mxSINGLE_CLASS, dims (),
+                                 mxCOMPLEX);
 
   mwSize nel = numel ();
 
-  const FloatComplex *p = matrix.data ();
+  const FloatComplex *pdata = matrix.data ();
+
+  if (interleaved)
+    {
+      mxComplexSingle *pd
+        = static_cast<mxComplexSingle *> (retval->get_data ());
 
-  for (mwIndex i = 0; i < nel; i++)
+      for (mwIndex i = 0; i < nel; i++)
+        {
+          pd[i].real = pdata[i].real ();
+          pd[i].imag = pdata[i].imag ();
+        }
+    }
+  else
     {
-      pr[i] = std::real (p[i]);
-      pi[i] = std::imag (p[i]);
+      mxSingle *pr = static_cast<mxSingle *> (retval->get_data ());
+      mxSingle *pi = static_cast<mxSingle *> (retval->get_imag_data ());
+
+      for (mwIndex i = 0; i < nel; i++)
+        {
+          pr[i] = pdata[i].real ();
+          pi[i] = pdata[i].imag ();
+        }
     }
 
   return retval;
--- a/libinterp/octave-value/ov-flt-cx-mat.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-flt-cx-mat.h	Thu Nov 19 13:08:00 2020 -0800
@@ -171,7 +171,7 @@
 
   void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
 
-  mxArray * as_mxArray (void) const;
+  mxArray * as_mxArray (bool interleaved) const;
 
   octave_value map (unary_mapper_t umap) const;
 
--- a/libinterp/octave-value/ov-flt-re-mat.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-flt-re-mat.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -717,18 +717,18 @@
 }
 
 mxArray *
-octave_float_matrix::as_mxArray (void) const
+octave_float_matrix::as_mxArray (bool interleaved) const
 {
-  mxArray *retval = new mxArray (mxSINGLE_CLASS, dims (), mxREAL);
+  mxArray *retval = new mxArray (interleaved, mxSINGLE_CLASS, dims (), mxREAL);
 
-  float *pr = static_cast<float *> (retval->get_data ());
+  mxSingle *pd = static_cast<mxSingle *> (retval->get_data ());
 
   mwSize nel = numel ();
 
-  const float *p = matrix.data ();
+  const float *pdata = matrix.data ();
 
   for (mwIndex i = 0; i < nel; i++)
-    pr[i] = p[i];
+    pd[i] = pdata[i];
 
   return retval;
 }
--- a/libinterp/octave-value/ov-flt-re-mat.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-flt-re-mat.h	Thu Nov 19 13:08:00 2020 -0800
@@ -217,7 +217,7 @@
   // You should not use it anywhere else.
   void * mex_get_data (void) const { return matrix.mex_get_data (); }
 
-  mxArray * as_mxArray (void) const;
+  mxArray * as_mxArray (bool interleaved) const;
 
   octave_value map (unary_mapper_t umap) const;
 
--- a/libinterp/octave-value/ov-intx.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-intx.h	Thu Nov 19 13:08:00 2020 -0800
@@ -315,19 +315,20 @@
   // You should not use it anywhere else.
   void * mex_get_data (void) const { return matrix.mex_get_data (); }
 
-  mxArray * as_mxArray (void) const
+  mxArray * as_mxArray (bool interleaved) const
   {
-    mxArray *retval = new mxArray (OCTAVE_INT_MX_CLASS, dims (), mxREAL);
+    mxArray *retval = new mxArray (interleaved, OCTAVE_INT_MX_CLASS, dims (),
+                                   mxREAL);
 
-    OCTAVE_INT_T::val_type *pr = static_cast<OCTAVE_INT_T::val_type *>
-                                 (retval->get_data ());
+    OCTAVE_INT_T::val_type *pd
+      = static_cast<OCTAVE_INT_T::val_type *> (retval->get_data ());
 
     mwSize nel = numel ();
 
-    const OCTAVE_INT_T *p = matrix.data ();
+    const OCTAVE_INT_T *pdata = matrix.data ();
 
     for (mwIndex i = 0; i < nel; i++)
-      pr[i] = p[i].value ();
+      pd[i] = pdata[i].value ();
 
     return retval;
   }
@@ -426,7 +427,7 @@
     (new OCTAVE_VALUE_INT_MATRIX_T
      (OCTAVE_VALUE_INT_NDARRAY_EXTRACTOR_FUNCTION ()));
 
-    return tmp.do_index_op (idx, resize_ok);
+    return tmp.index_op (idx, resize_ok);
   }
 
   bool OCTAVE_TYPE_PREDICATE_FUNCTION (void) const { return true; }
@@ -637,14 +638,15 @@
   // You should not use it anywhere else.
   void * mex_get_data (void) const { return scalar.mex_get_data (); }
 
-  mxArray * as_mxArray (void) const
+  mxArray * as_mxArray (bool interleaved) const
   {
-    mxArray *retval = new mxArray (OCTAVE_INT_MX_CLASS, 1, 1, mxREAL);
+    mxArray *retval = new mxArray (interleaved, OCTAVE_INT_MX_CLASS, 1, 1,
+                                   mxREAL);
 
-    OCTAVE_INT_T::val_type *pr = static_cast<OCTAVE_INT_T::val_type *>
-                                 (retval->get_data ());
+    OCTAVE_INT_T::val_type *pd
+      = static_cast<OCTAVE_INT_T::val_type *> (retval->get_data ());
 
-    pr[0] = scalar.value ();
+    pd[0] = scalar.value ();
 
     return retval;
   }
--- a/libinterp/octave-value/ov-java.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-java.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -37,6 +37,7 @@
 #endif
 
 #include <algorithm>
+#include <array>
 #include <fstream>
 #include <map>
 #include <string>
@@ -513,16 +514,16 @@
   // This assumes that whatever architectures are installed are appropriate for
   // this machine
 #if defined (OCTAVE_USE_WINDOWS_API)
-  std::string subdirs[] = {"bin/client", "bin/server"};
+  const std::array<const std::string, 2> subdirs = {"bin/client", "bin/server"};
 #else
-  std::string subdirs[] = {"jre/lib/server", "jre/lib",
-                           "lib/client", "lib/server",
-                           "jre/lib/amd64/client", "jre/lib/amd64/server",
-                           "jre/lib/i386/client", "jre/lib/i386/server"
-                          };
+  const std::array<const std::string, 8> subdirs =
+    {"jre/lib/server", "jre/lib", "lib/client", "lib/server",
+     "jre/lib/amd64/client", "jre/lib/amd64/server",
+     "jre/lib/i386/client", "jre/lib/i386/server"
+    };
 #endif
 
-  for (size_t i = 0; i < sizeof (subdirs) / sizeof (subdirs[0]); i++)
+  for (size_t i = 0; i < subdirs.size (); i++)
     {
       std::string candidate = java_home_path + "/" + subdirs[i]
                               + "/" LIBJVM_FILE_NAME;
@@ -786,7 +787,6 @@
 
         case JNI_EVERSION:
           error ("JVM internal error, the required JNI version is not supported");
-          break;
 
         case JNI_OK:
           // Don't do anything, the current thread is already attached to JVM
--- a/libinterp/octave-value/ov-lazy-idx.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-lazy-idx.h	Thu Nov 19 13:08:00 2020 -0800
@@ -93,7 +93,7 @@
 
   octave_value do_index_op (const octave_value_list& idx,
                             bool resize_ok = false)
-  { return make_value ().do_index_op (idx, resize_ok); }
+  { return make_value ().index_op (idx, resize_ok); }
 
   dim_vector dims (void) const { return index.orig_dimensions (); }
 
@@ -241,9 +241,9 @@
     return make_value ().mex_get_data ();
   }
 
-  mxArray * as_mxArray (void) const
+  mxArray * as_mxArray (bool interleaved) const
   {
-    return make_value ().as_mxArray ();
+    return make_value ().as_mxArray (interleaved);
   }
 
   octave_value map (unary_mapper_t umap) const
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/octave-value/ov-magic-int.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,323 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include <istream>
+#include <ostream>
+
+#include "oct-inttypes.h"
+
+#include "data-conv.h"
+#include "mach-info.h"
+#include "lo-specfun.h"
+#include "lo-mappers.h"
+
+#include "defun.h"
+#include "errwarn.h"
+#include "mxarray.h"
+#include "ovl.h"
+#include "oct-hdf5.h"
+#include "oct-stream.h"
+#include "ov-scalar.h"
+#include "ov-float.h"
+#include "ov-base.h"
+#include "ov-magic-int.h"
+#include "ov-base-scalar.h"
+#include "ov-re-mat.h"
+#include "ov-typeinfo.h"
+#include "pr-output.h"
+#include "xdiv.h"
+#include "xpow.h"
+#include "ops.h"
+
+#include "ls-oct-text.h"
+#include "ls-hdf5.h"
+
+// NOTE: Although there is some additional overhead, for all but the
+// simplest data type extraction operations, we convert to an
+// octave_scalar object and forward the operation to avoid code
+// duplication and ensure that operations on magic_int objects are
+// identical to operations on octave_scalar objects.  We could also
+// avoid code duplication by deriving octave_magic_int from
+// octave_scalar, but then we would need to store both the double and
+// octave_uint64 or octave_int64 values, doubling the storage
+// requirement.
+
+static octave_base_value *
+default_numeric_conv_fcn (const octave_base_value& a)
+{
+  return new octave_scalar (a.double_value ());
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::do_index_op (const octave_value_list& idx,
+                                       bool resize_ok)
+{
+  octave_value tmp (double_value ());
+
+  return tmp.index_op (idx, resize_ok);
+}
+
+template <typename T>
+idx_vector
+octave_base_magic_int<T>::index_vector (bool require_integers) const
+{
+  octave_value tmp (double_value ());
+
+  return tmp.index_vector (require_integers);
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::resize (const dim_vector& dv, bool fill) const
+{
+  octave_value tmp (double_value ());
+
+  return tmp.resize (dv, fill);
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::as_double (void) const
+{
+  return static_cast<double> (scalar_ref ());
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::as_single (void) const
+{
+  return static_cast<float> (scalar_ref ());
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::as_int8 (void) const
+{
+  return octave_int8 (scalar_ref ());
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::as_int16 (void) const
+{
+  return octave_int16 (scalar_ref ());
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::as_int32 (void) const
+{
+  return octave_int32 (scalar_ref ());
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::as_int64 (void) const
+{
+  return octave_int64 (scalar_ref ());
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::as_uint8 (void) const
+{
+  return octave_uint8 (scalar_ref ());
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::as_uint16 (void) const
+{
+  return octave_uint16 (scalar_ref ());
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::as_uint32 (void) const
+{
+  return octave_uint32 (scalar_ref ());
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::as_uint64 (void) const
+{
+  return octave_uint64 (scalar_ref ());
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::diag (octave_idx_type m, octave_idx_type n) const
+{
+  octave_value tmp (double_value ());
+
+  return tmp.diag (m, n);
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::convert_to_str_internal (bool, bool, char type) const
+{
+  octave_value retval;
+
+  int ival;
+
+  if (scalar_ref ().value () > std::numeric_limits<unsigned char>::max ())
+    {
+      // FIXME: is there something better we could do?
+
+      ival = 0;
+
+      ::warning ("range error for conversion to character value");
+    }
+  else
+    ival = scalar_ref ().value ();
+
+  retval = octave_value (std::string (1, static_cast<char> (ival)), type);
+
+  return retval;
+}
+
+
+template <typename T>
+bool
+octave_base_magic_int<T>::save_ascii (std::ostream& os)
+{
+  octave_value tmp (double_value ());
+
+  return tmp.save_ascii (os);
+}
+
+template <typename T>
+OCTAVE_NORETURN bool
+octave_base_magic_int<T>::load_ascii (std::istream&)
+{
+  error ("octave_base_magic_int<T>::load_ascii: internal error");
+}
+
+template <typename T>
+bool
+octave_base_magic_int<T>::save_binary (std::ostream& os, bool save_as_floats)
+{
+  octave_value tmp (double_value ());
+
+  return tmp.save_binary (os, save_as_floats);
+}
+
+template <typename T>
+OCTAVE_NORETURN bool
+octave_base_magic_int<T>::load_binary (std::istream&, bool,
+                                       octave::mach_info::float_format)
+{
+  error ("octave_base_magic_int<T>::load_binary: internal error");
+}
+
+template <typename T>
+bool
+octave_base_magic_int<T>::save_hdf5 (octave_hdf5_id loc_id, const char *name,
+                                     bool save_as_floats)
+{
+  bool retval = false;
+
+#if defined (HAVE_HDF5)
+
+  octave_value tmp (double_value ());
+
+  return tmp.save_hdf5 (loc_id, name, save_as_floats);
+
+#else
+
+  octave_unused_parameter (loc_id);
+  octave_unused_parameter (name);
+  octave_unused_parameter (save_as_floats);
+
+  octave_base_value::warn_save ("hdf5");
+
+#endif
+
+  return retval;
+}
+
+template <typename T>
+bool
+octave_base_magic_int<T>::load_hdf5 (octave_hdf5_id, const char *)
+{
+#if defined (HAVE_HDF5)
+
+  error ("octave_base_magic_int<T>::load_binary: internal error");
+
+  return false;
+
+#else
+
+  octave_base_value::warn_load ("hdf5");
+
+  return false;
+
+#endif
+}
+
+template <typename T>
+mxArray *
+octave_base_magic_int<T>::as_mxArray (bool interleaved) const
+{
+  octave_value tmp (double_value ());
+
+  return tmp.as_mxArray (interleaved);
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::map (octave_base_value::unary_mapper_t umap) const
+{
+  octave_value tmp (double_value ());
+
+  return tmp.map (umap);
+}
+
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_magic_uint, "magic_uint",
+                                     "double");
+
+octave_base_value::type_conv_info
+octave_magic_uint::numeric_conversion_function (void) const
+{
+  return octave_base_value::type_conv_info (default_numeric_conv_fcn,
+                                            octave_scalar::static_type_id ());
+}
+
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_magic_int, "magic_int",
+                                     "double");
+
+octave_base_value::type_conv_info
+octave_magic_int::numeric_conversion_function (void) const
+{
+  return octave_base_value::type_conv_info (default_numeric_conv_fcn,
+                                            octave_scalar::static_type_id ());
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/octave-value/ov-magic-int.h	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,326 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if ! defined (octave_ov_magic_int_h)
+#define octave_ov_magic_int_h 1
+
+#include "octave-config.h"
+
+#include <iosfwd>
+#include <string>
+
+#include "oct-inttypes.h"
+
+#include "ov-base.h"
+#include "ov-re-mat.h"
+#include "ov-base-scalar.h"
+#include "ov-typeinfo.h"
+
+class octave_value_list;
+
+// Large integer scalar values.  The uint64 or int64 value they contain may be
+// accessed without loss of precision when needed (for example, when
+// directly converted to a uint64 or int64 value).  Otherwise, they
+// behave like real scalars, so any operation on them will result in
+// type conversion.
+
+template <typename T>
+class
+octave_base_magic_int : public octave_base_scalar<T>
+{
+public:
+
+  octave_base_magic_int (void)
+    : octave_base_scalar<T> (0) { }
+
+  octave_base_magic_int (const T& val)
+    : octave_base_scalar<T> (val) { }
+
+  ~octave_base_magic_int (void) = default;
+
+  // We return an octave_matrix here instead of an octave_scalar so
+  // that in expressions like A(2,2,2) = 2 (for A previously
+  // undefined), A will be empty instead of a 1x1 object.
+  octave_base_value * empty_clone (void) const { return new octave_matrix (); }
+
+  // Although SCALAR is a protected member of the base class, it is not
+  // directly visible here without the explicit octave_base_slalar<T>::
+  // qualification.  Why not?
+
+  const T& scalar_ref (void) const { return octave_base_scalar<T>::scalar; }
+
+  T& scalar_ref (void) { return octave_base_scalar<T>::scalar; }
+
+  octave_value do_index_op (const octave_value_list& idx,
+                            bool resize_ok = false);
+
+  idx_vector index_vector (bool require_integers = false) const;
+
+  octave_value any (int = 0) const { return scalar_ref () != T (0); }
+
+  builtin_type_t builtin_type (void) const { return btyp_double; }
+
+  bool is_magic_int (void) const { return true; }
+
+  bool is_real_scalar (void) const { return true; }
+
+  bool isreal (void) const { return true; }
+
+  bool is_double_type (void) const { return true; }
+
+  bool isfloat (void) const { return true; }
+
+  int8NDArray int8_array_value (void) const
+  { return int8NDArray (dim_vector (1, 1), double_value ()); }
+
+  int16NDArray int16_array_value (void) const
+  { return int16NDArray (dim_vector (1, 1), double_value ()); }
+
+  int32NDArray int32_array_value (void) const
+  { return int32NDArray (dim_vector (1, 1), double_value ()); }
+
+  int64NDArray int64_array_value (void) const
+  { return int64NDArray (dim_vector (1, 1), double_value ()); }
+
+  uint8NDArray uint8_array_value (void) const
+  { return uint8NDArray (dim_vector (1, 1), double_value ()); }
+
+  uint16NDArray uint16_array_value (void) const
+  { return uint16NDArray (dim_vector (1, 1), double_value ()); }
+
+  uint32NDArray uint32_array_value (void) const
+  { return uint32NDArray (dim_vector (1, 1), double_value ()); }
+
+  uint64NDArray uint64_array_value (void) const
+  { return uint64NDArray (dim_vector (1, 1), double_value ()); }
+
+  octave_int8 int8_scalar_value (void) const
+  { return octave_int8 (double_value ()); }
+
+  octave_int16 int16_scalar_value (void) const
+  { return octave_int16 (double_value ()); }
+
+  octave_int32 int32_scalar_value (void) const
+  { return octave_int32 (double_value ()); }
+
+  octave_int64 int64_scalar_value (void) const
+  { return octave_int64 (double_value ()); }
+
+  octave_uint8 uint8_scalar_value (void) const
+  { return octave_uint8 (double_value ()); }
+
+  octave_uint16 uint16_scalar_value (void) const
+  { return octave_uint16 (double_value ()); }
+
+  octave_uint32 uint32_scalar_value (void) const
+  { return octave_uint32 (double_value ()); }
+
+  octave_uint64 uint64_scalar_value (void) const
+  { return octave_uint64 (double_value ()); }
+
+  double double_value (bool = false) const
+  {
+    return scalar_ref ().double_value ();
+  }
+
+  float float_value (bool = false) const
+  { return static_cast<float> (double_value ()); }
+
+  double scalar_value (bool = false) const
+  { return double_value (); }
+
+  float float_scalar_value (bool = false) const
+  { return float_value (); }
+
+  Matrix matrix_value (bool = false) const
+  { return Matrix (1, 1, double_value ()); }
+
+  FloatMatrix float_matrix_value (bool = false) const
+  { return FloatMatrix (1, 1, float_value ()); }
+
+  NDArray array_value (bool = false) const
+  { return NDArray (dim_vector (1, 1), double_value ()); }
+
+  FloatNDArray float_array_value (bool = false) const
+  { return FloatNDArray (dim_vector (1, 1), float_value ()); }
+
+  SparseMatrix sparse_matrix_value (bool = false) const
+  { return SparseMatrix (Matrix (1, 1, double_value ())); }
+
+  // FIXME: Need SparseComplexMatrix (Matrix) constructor!
+  SparseComplexMatrix sparse_complex_matrix_value (bool = false) const
+  { return SparseComplexMatrix (sparse_matrix_value ()); }
+
+  octave_value resize (const dim_vector& dv, bool fill = false) const;
+
+  Complex complex_value (bool = false) const { return double_value (); }
+
+  FloatComplex float_complex_value (bool = false) const
+  { return FloatComplex (float_value ()); }
+
+  ComplexMatrix complex_matrix_value (bool = false) const
+  { return ComplexMatrix (1, 1, Complex (double_value ())); }
+
+  FloatComplexMatrix float_complex_matrix_value (bool = false) const
+  { return FloatComplexMatrix (1, 1, FloatComplex (float_value ())); }
+
+  ComplexNDArray complex_array_value (bool = false) const
+  { return ComplexNDArray (dim_vector (1, 1), Complex (double_value ())); }
+
+  FloatComplexNDArray float_complex_array_value (bool = false) const
+  {
+    return FloatComplexNDArray (dim_vector (1, 1),
+                                FloatComplex (float_value ()));
+  }
+
+  charNDArray
+  char_array_value (bool = false) const
+  {
+    charNDArray retval (dim_vector (1, 1));
+    retval(0) = static_cast<char> (double_value ());
+    return retval;
+  }
+
+  bool bool_value (bool warn = false) const
+  {
+    if (warn && scalar_ref () != T (0) && scalar_ref () != T (1))
+      warn_logical_conversion ();
+
+    return double_value ();
+  }
+
+  boolNDArray bool_array_value (bool warn = false) const
+  {
+    if (warn && scalar_ref () != T (0) && scalar_ref () != T (1))
+      warn_logical_conversion ();
+
+    return boolNDArray (dim_vector (1, 1), double_value ());
+  }
+
+  octave_value as_double (void) const;
+  octave_value as_single (void) const;
+
+  octave_value as_int8 (void) const;
+  octave_value as_int16 (void) const;
+  octave_value as_int32 (void) const;
+  octave_value as_int64 (void) const;
+
+  octave_value as_uint8 (void) const;
+  octave_value as_uint16 (void) const;
+  octave_value as_uint32 (void) const;
+  octave_value as_uint64 (void) const;
+
+  // We don't need to override both forms of the diag method.  The using
+  // declaration will avoid warnings about partially-overloaded virtual
+  // functions.
+  using octave_base_scalar<T>::diag;
+
+  octave_value diag (octave_idx_type m, octave_idx_type n) const;
+
+  octave_value convert_to_str_internal (bool pad, bool force, char type) const;
+
+  void increment (void) { scalar_ref () += T (1); }
+
+  void decrement (void) { scalar_ref () -= T (1); }
+
+  bool save_ascii (std::ostream& os);
+
+  bool load_ascii (std::istream& is);
+
+  bool save_binary (std::ostream& os, bool save_as_floats);
+
+  bool load_binary (std::istream& is, bool swap,
+                    octave::mach_info::float_format fmt);
+
+  bool save_hdf5 (octave_hdf5_id loc_id, const char *name, bool save_as_floats);
+
+  bool load_hdf5 (octave_hdf5_id loc_id, const char *name);
+
+  int write (octave::stream& os, int block_size,
+             oct_data_conv::data_type output_type, int skip,
+             octave::mach_info::float_format flt_fmt) const
+  {
+    return os.write (array_value (), block_size, output_type,
+                     skip, flt_fmt);
+  }
+
+  mxArray * as_mxArray (bool interleaved) const;
+
+  octave_value map (octave_base_value::unary_mapper_t umap) const;
+};
+
+class
+OCTINTERP_API
+octave_magic_uint : public octave_base_magic_int<octave_uint64>
+{
+public:
+
+  octave_magic_uint (void)
+    : octave_base_magic_int<octave_uint64> (0) { }
+
+  octave_magic_uint (const octave_uint64& val)
+    : octave_base_magic_int<octave_uint64> (val) { }
+
+  ~octave_magic_uint (void) = default;
+
+  octave_base_value * clone (void) const
+  {
+    return new octave_magic_uint (*this);
+  }
+
+  type_conv_info numeric_conversion_function (void) const;
+
+private:
+
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
+};
+
+class
+OCTINTERP_API
+octave_magic_int : public octave_base_magic_int<octave_int64>
+{
+public:
+
+  octave_magic_int (void)
+    : octave_base_magic_int<octave_int64> (0) { }
+
+  octave_magic_int (const octave_int64& val)
+    : octave_base_magic_int<octave_int64> (val) { }
+
+  ~octave_magic_int (void) = default;
+
+  octave_base_value * clone (void) const
+  {
+    return new octave_magic_int (*this);
+  }
+
+  type_conv_info numeric_conversion_function (void) const;
+
+private:
+
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
+};
+
+#endif
--- a/libinterp/octave-value/ov-mex-fcn.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-mex-fcn.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -46,10 +46,11 @@
                                      "mex function", "mex function");
 
 octave_mex_function::octave_mex_function
-  (void *fptr, bool fmex, const octave::dynamic_library& shl,
+  (void *fptr, bool interleaved, bool fmex, const octave::dynamic_library& shl,
    const std::string& nm)
   : octave_function (nm), m_mex_fcn_ptr (fptr), m_exit_fcn_ptr (nullptr),
-    m_is_fmex (fmex), m_sh_lib (shl)
+    m_sh_lib (shl), m_interleaved (interleaved), m_is_fmex (fmex),
+    m_is_system_fcn_file (false)
 {
   mark_fcn_file_up_to_date (time_parsed ());
 
--- a/libinterp/octave-value/ov-mex-fcn.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-mex-fcn.h	Thu Nov 19 13:08:00 2020 -0800
@@ -52,10 +52,12 @@
 public:
 
   octave_mex_function (void)
-    : m_mex_fcn_ptr (), m_exit_fcn_ptr (), m_is_fmex (), m_sh_lib (),
-      m_time_checked (), m_is_system_fcn_file () { }
+    : m_mex_fcn_ptr (nullptr), m_exit_fcn_ptr (nullptr), m_sh_lib (),
+      m_time_checked (), m_interleaved (false), m_is_fmex (false),
+      m_is_system_fcn_file (false)
+  { }
 
-  octave_mex_function (void *fptr, bool fmex,
+  octave_mex_function (void *fptr, bool interleaved, bool fmex,
                        const octave::dynamic_library& shl,
                        const std::string& nm = "");
 
@@ -88,6 +90,8 @@
 
   bool is_mex_function (void) const { return true; }
 
+  bool use_interleaved_complex (void) const { return m_interleaved; }
+
   octave_value_list
   execute (octave::tree_evaluator& tw, int nargout = 0,
            const octave_value_list& args = octave_value_list ());
@@ -106,14 +110,16 @@
 
   void (*m_exit_fcn_ptr) (void);
 
-  bool m_is_fmex;
-
   octave::dynamic_library m_sh_lib;
 
   // The time the file was last checked to see if it needs to be
   // parsed again.
   mutable octave::sys::time m_time_checked;
 
+  bool m_interleaved;
+
+  bool m_is_fmex;
+
   // True if this function came from a file that is considered to be a
   // system function.  This affects whether we check the time stamp
   // on the file to see if it has changed.
--- a/libinterp/octave-value/ov-perm.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-perm.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -128,7 +128,7 @@
       if (nidx == 2 && ! resize_ok && idx0.is_scalar () && idx1.is_scalar ())
         retval = matrix.checkelem (idx0(0), idx1(0));
       else
-        retval = to_dense ().do_index_op (idx, resize_ok);
+        retval = to_dense ().index_op (idx, resize_ok);
     }
 
   return retval;
@@ -434,9 +434,9 @@
 }
 
 mxArray *
-octave_perm_matrix::as_mxArray (void) const
+octave_perm_matrix::as_mxArray (bool interleaved) const
 {
-  return to_dense ().as_mxArray ();
+  return to_dense ().as_mxArray (interleaved);
 }
 
 bool
--- a/libinterp/octave-value/ov-perm.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-perm.h	Thu Nov 19 13:08:00 2020 -0800
@@ -240,7 +240,7 @@
              oct_data_conv::data_type output_type, int skip,
              octave::mach_info::float_format flt_fmt) const;
 
-  mxArray * as_mxArray (void) const;
+  mxArray * as_mxArray (bool interleaved) const;
 
   bool print_as_scalar (void) const;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/octave-value/ov-range-traits.h	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,154 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if ! defined (octave_ov_range_traits_h)
+#define octave_ov_range_traits_h 1
+
+#include "octave-config.h"
+
+#include "ov-bool-mat.h"
+#include "ov-bool.h"
+#include "ov-float.h"
+#include "ov-flt-re-mat.h"
+#include "ov-int16.h"
+#include "ov-int32.h"
+#include "ov-int64.h"
+#include "ov-int8.h"
+#include "ov-re-mat.h"
+#include "ov-scalar.h"
+#include "ov-uint16.h"
+#include "ov-uint32.h"
+#include "ov-uint64.h"
+#include "ov-uint8.h"
+
+template <typename T>
+class
+octave_value_range_traits
+{
+public:
+  typedef T scalar_type;
+  typedef T matrix_type;
+};
+
+template <>
+class
+octave_value_range_traits<bool>
+{
+public:
+  typedef octave_bool scalar_type;
+  typedef octave_bool_matrix matrix_type;
+};
+
+template <>
+class
+octave_value_range_traits<float>
+{
+public:
+  typedef octave_float_scalar scalar_type;
+  typedef octave_float_matrix matrix_type;
+};
+
+template <>
+class
+octave_value_range_traits<double>
+{
+public:
+  typedef octave_scalar scalar_type;
+  typedef octave_matrix matrix_type;
+};
+
+template <>
+class
+octave_value_range_traits<octave_int8>
+{
+public:
+  typedef octave_int8_scalar scalar_type;
+  typedef octave_int8_matrix matrix_type;
+};
+
+template <>
+class
+octave_value_range_traits<octave_int16>
+{
+public:
+  typedef octave_int16_scalar scalar_type;
+  typedef octave_int16_matrix matrix_type;
+};
+
+template <>
+class
+octave_value_range_traits<octave_int32>
+{
+public:
+  typedef octave_int32_scalar scalar_type;
+  typedef octave_int32_matrix matrix_type;
+};
+
+template <>
+class
+octave_value_range_traits<octave_int64>
+{
+public:
+  typedef octave_int64_scalar scalar_type;
+  typedef octave_int64_matrix matrix_type;
+};
+
+template <>
+class
+octave_value_range_traits<octave_uint8>
+{
+public:
+  typedef octave_uint8_scalar scalar_type;
+  typedef octave_uint8_matrix matrix_type;
+};
+
+template <>
+class
+octave_value_range_traits<octave_uint16>
+{
+public:
+  typedef octave_uint16_scalar scalar_type;
+  typedef octave_uint16_matrix matrix_type;
+};
+
+template <>
+class
+octave_value_range_traits<octave_uint32>
+{
+public:
+  typedef octave_uint32_scalar scalar_type;
+  typedef octave_uint32_matrix matrix_type;
+};
+
+template <>
+class
+octave_value_range_traits<octave_uint64>
+{
+public:
+  typedef octave_uint64_scalar scalar_type;
+  typedef octave_uint64_matrix matrix_type;
+};
+
+#endif
--- a/libinterp/octave-value/ov-range.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-range.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -23,9 +23,9 @@
 //
 ////////////////////////////////////////////////////////////////////////
 
-#if defined (HAVE_CONFIG_H)
-#  include "config.h"
-#endif
+// This file should not include config.h.  It is only included in other
+// C++ source files that should have included config.h before including
+// this file.
 
 #include <istream>
 #include <ostream>
@@ -49,9 +49,11 @@
 #include "variables.h"
 #include "errwarn.h"
 #include "mxarray.h"
+#include "mx-type-traits.h"
 #include "ops.h"
 #include "ovl.h"
 #include "oct-hdf5.h"
+#include "ov-range-traits.h"
 #include "ov-range.h"
 #include "ov-re-mat.h"
 #include "ov-scalar.h"
@@ -62,41 +64,148 @@
 #include "ls-hdf5.h"
 #include "ls-utils.h"
 
+#if defined (HAVE_HDF5)
 
-DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_range, "range", "double");
+template <>
+octave_hdf5_id ov_range<float>::hdf5_save_type = H5T_NATIVE_FLOAT;
+
+template <>
+octave_hdf5_id ov_range<double>::hdf5_save_type = H5T_NATIVE_DOUBLE;
+
+template <>
+octave_hdf5_id ov_range<octave_int8>::hdf5_save_type = H5T_NATIVE_INT8;
+
+template <>
+octave_hdf5_id ov_range<octave_int16>::hdf5_save_type = H5T_NATIVE_INT16;
+
+template <>
+octave_hdf5_id ov_range<octave_int32>::hdf5_save_type = H5T_NATIVE_INT32;
+
+template <>
+octave_hdf5_id ov_range<octave_int64>::hdf5_save_type = H5T_NATIVE_INT64;
+
+template <>
+octave_hdf5_id ov_range<octave_uint8>::hdf5_save_type = H5T_NATIVE_UINT8;
+
+template <>
+octave_hdf5_id ov_range<octave_uint16>::hdf5_save_type = H5T_NATIVE_UINT16;
+
+template <>
+octave_hdf5_id ov_range<octave_uint32>::hdf5_save_type = H5T_NATIVE_UINT32;
+
+template <>
+octave_hdf5_id ov_range<octave_uint64>::hdf5_save_type = H5T_NATIVE_UINT64;
+
+#else
+
+template <>
+octave_hdf5_id ov_range<float>::hdf5_save_type = 0;
+
+template <>
+octave_hdf5_id ov_range<double>::hdf5_save_type = 0;
+
+template <>
+octave_hdf5_id ov_range<octave_int8>::hdf5_save_type = 0;
+
+template <>
+octave_hdf5_id ov_range<octave_int16>::hdf5_save_type = 0;
+
+template <>
+octave_hdf5_id ov_range<octave_int32>::hdf5_save_type = 0;
 
+template <>
+octave_hdf5_id ov_range<octave_int64>::hdf5_save_type = 0;
+
+template <>
+octave_hdf5_id ov_range<octave_uint8>::hdf5_save_type = 0;
+
+template <>
+octave_hdf5_id ov_range<octave_uint16>::hdf5_save_type = 0;
+
+template <>
+octave_hdf5_id ov_range<octave_uint32>::hdf5_save_type = 0;
+
+template <>
+octave_hdf5_id ov_range<octave_uint64>::hdf5_save_type = 0;
+
+#endif
+
+DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<float>,
+                                              "float_range", "single");
+
+DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<double>,
+                                              "range", "double");
+
+DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<octave_int8>,
+                                              "int8_range", "int8");
+
+DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<octave_int16>,
+                                              "int16_range", "int16");
+
+DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<octave_int32>,
+                                              "int32_range", "int32");
+
+DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<octave_int64>,
+                                              "int64_range", "int64");
+
+DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<octave_uint8>,
+                                              "uint8_range", "uint8");
+
+DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<octave_uint16>,
+                                              "uint16_range", "uint16");
+
+DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<octave_uint32>,
+                                              "uint32_range", "uint32");
+
+DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<octave_uint64>,
+                                              "uint64_range", "uint64");
+
+template <typename T>
 static octave_base_value *
 default_numeric_conversion_function (const octave_base_value& a)
 {
-  const octave_range& v = dynamic_cast<const octave_range&> (a);
+  typedef typename octave_value_range_traits<T>::matrix_type ov_mx_type;
 
-  return new octave_matrix (v.matrix_value ());
+  const ov_range<T>& v = dynamic_cast<const ov_range<T>&> (a);
+
+  return new ov_mx_type (v.raw_array_value ());
 }
 
+template <typename T>
 octave_base_value::type_conv_info
-octave_range::numeric_conversion_function (void) const
+ov_range<T>::numeric_conversion_function (void) const
 {
-  return octave_base_value::type_conv_info (default_numeric_conversion_function,
-                                            octave_matrix::static_type_id ());
+  typedef typename octave_value_range_traits<T>::matrix_type ov_mx_type;
+
+  return octave_base_value::type_conv_info
+    (default_numeric_conversion_function<T>, ov_mx_type::static_type_id ());
 }
 
+template <typename T>
 octave_base_value *
-octave_range::try_narrowing_conversion (void)
+ov_range<T>::try_narrowing_conversion (void)
 {
   octave_base_value *retval = nullptr;
 
-  switch (range.numel ())
+  switch (numel ())
     {
     case 1:
-      retval = new octave_scalar (range.base ());
+      retval = new typename octave_value_range_traits<T>::scalar_type (m_range.elem (0));
       break;
 
     case 0:
-      retval = new octave_matrix (Matrix (1, 0));
+      {
+        typedef typename octave_value_range_traits<T>::matrix_type ov_mx_type;
+        typename ov_mx_type::object_type m (dim_vector (1, 0));
+        retval = new ov_mx_type (m);
+      }
       break;
 
     case -2:
-      retval = new octave_matrix (range.matrix_value ());
+      // FIXME: is this case possible now?  It would have to be due to
+      // conversion from Range to range<double>, but even in that case,
+      // is the invalid numel value preserved?
+      retval = new typename octave_value_range_traits<T>::matrix_type (raw_array_value ());
       break;
 
     default:
@@ -106,9 +215,10 @@
   return retval;
 }
 
+template <typename T>
 octave_value
-octave_range::subsref (const std::string& type,
-                       const std::list<octave_value_list>& idx)
+ov_range<T>::subsref (const std::string& type,
+                      const std::list<octave_value_list>& idx)
 {
   octave_value retval;
 
@@ -133,8 +243,10 @@
   return retval.next_subsref (type, idx);
 }
 
+template <typename T>
 octave_value
-octave_range::do_index_op (const octave_value_list& idx, bool resize_ok)
+ov_range<T>::do_index_op (const octave_value_list& idx,
+                                   bool resize_ok)
 {
   if (idx.length () == 1 && ! resize_ok)
     {
@@ -146,10 +258,10 @@
         {
           idx_vector i = idx(0).index_vector ();
 
-          if (i.is_scalar () && i(0) < range.numel ())
-            retval = range.elem (i(0));
+          if (i.is_scalar () && i(0) < numel ())
+            retval = m_range.elem (i(0));
           else
-            retval = range.index (i);
+            retval = m_range.index (i);
         }
       catch (octave::index_exception& e)
         {
@@ -163,35 +275,25 @@
     }
   else
     {
-      octave_value tmp (new octave_matrix (range.matrix_value ()));
+      octave_value tmp (new typename octave_value_range_traits<T>::matrix_type (raw_array_value ()));
 
-      return tmp.do_index_op (idx, resize_ok);
+      return tmp.index_op (idx, resize_ok);
     }
 }
 
+template <typename T>
 idx_vector
-octave_range::index_vector (bool require_integers) const
+ov_range<T>::index_vector (bool require_integers) const
 {
-  if (idx_cache)
-    return *idx_cache;
-  else
-    {
-      if (require_integers || range.all_elements_are_ints ())
-        return set_idx_cache (idx_vector (range));
-      else
-        {
-          warning_with_id ("Octave:noninteger-range-as-index",
-                           "non-integer range used as index");
-
-          return octave_value (matrix_value ()).round ().index_vector ();
-        }
-    }
+  octave_value tmp (raw_array_value ());
+  return tmp.index_vector (require_integers);
 }
 
+template <typename T>
 double
-octave_range::double_value (bool) const
+ov_range<T>::double_value (bool) const
 {
-  octave_idx_type nel = range.numel ();
+  octave_idx_type nel = numel ();
 
   if (nel == 0)
     err_invalid_conversion ("range", "real scalar");
@@ -199,13 +301,14 @@
   warn_implicit_conversion ("Octave:array-to-scalar",
                             "range", "real scalar");
 
-  return range.base ();
+  return m_range.base ();
 }
 
+template <typename T>
 float
-octave_range::float_value (bool) const
+ov_range<T>::float_value (bool) const
 {
-  octave_idx_type nel = range.numel ();
+  octave_idx_type nel = numel ();
 
   if (nel == 0)
     err_invalid_conversion ("range", "real scalar");
@@ -213,13 +316,14 @@
   warn_implicit_conversion ("Octave:array-to-scalar",
                             "range", "real scalar");
 
-  return range.base ();
+  return m_range.base ();
 }
 
+template <typename T>
 charNDArray
-octave_range::char_array_value (bool) const
+ov_range<T>::char_array_value (bool) const
 {
-  const Matrix matrix = range.matrix_value ();
+  const Array<T> matrix = raw_array_value ();
   charNDArray retval (dims ());
 
   octave_idx_type nel = numel ();
@@ -230,85 +334,11 @@
   return retval;
 }
 
-octave_value
-octave_range::all (int dim) const
-{
-  // FIXME: this is a potential waste of memory.
-
-  Matrix m = range.matrix_value ();
-
-  return m.all (dim);
-}
-
-octave_value
-octave_range::any (int dim) const
-{
-  // FIXME: this is a potential waste of memory.
-
-  Matrix m = range.matrix_value ();
-
-  return m.any (dim);
-}
-
-octave_value
-octave_range::diag (octave_idx_type k) const
-{
-  return
-    (k == 0
-       ? octave_value (DiagMatrix (DiagArray2<double> (range.matrix_value ())))
-       : octave_value (range.diag (k)));
-}
-
-octave_value
-octave_range::diag (octave_idx_type m, octave_idx_type n) const
+template <typename T>
+Complex
+ov_range<T>::complex_value (bool) const
 {
-  Matrix mat = range.matrix_value ();
-
-  return mat.diag (m, n);
-}
-
-// Return true if this range has all true elements (non-zero, not NaN/NA).
-// A range cannot have NaN/NA.
-bool
-octave_range::is_true (void) const
-{
-  bool retval = false;
-
-  if (! range.isempty ())
-    {
-      if (dims ().numel () > 1)
-        warn_array_as_logical (dims ());
-
-      Range r = range_value ();
-      double base = r.base ();
-      double limit = r.limit ();
-
-      // Can't be zero if we start and finish on the same size of 0
-      if (((base > 0 && limit > 0) || (base < 0 && limit < 0)) && numel () > 0)
-        retval = true;
-      else
-        {
-          /*
-          // This tells us whether one element is 0, if arithmetic is exact.
-          double steps_to_zero = base / r.inc ();
-
-          retval = (steps_to_zero != floor (steps_to_zero));
-          */
-
-          // FIXME: this is a waste of memory.
-          Matrix m ((range.matrix_value ().all ()).all ());
-
-          retval = ! m.isempty () && m(0, 0) != 0.0;
-        }
-    }
-
-  return retval;
-}
-
-Complex
-octave_range::complex_value (bool) const
-{
-  octave_idx_type nel = range.numel ();
+  octave_idx_type nel = numel ();
 
   if (nel == 0)
     err_invalid_conversion ("range", "complex scalar");
@@ -316,17 +346,18 @@
   warn_implicit_conversion ("Octave:array-to-scalar",
                             "range", "complex scalar");
 
-  return Complex (range.base (), 0);
+  return Complex (m_range.base (), 0);
 }
 
+template <typename T>
 FloatComplex
-octave_range::float_complex_value (bool) const
+ov_range<T>::float_complex_value (bool) const
 {
   float tmp = lo_ieee_float_nan_value ();
 
   FloatComplex retval (tmp, tmp);
 
-  octave_idx_type nel = range.numel ();
+  octave_idx_type nel = numel ();
 
   if (nel == 0)
     err_invalid_conversion ("range", "complex scalar");
@@ -334,28 +365,28 @@
   warn_implicit_conversion ("Octave:array-to-scalar",
                             "range", "complex scalar");
 
-  retval = range.base ();
+  retval = m_range.base ();
 
   return retval;
 }
 
+template <typename T>
 boolNDArray
-octave_range::bool_array_value (bool warn) const
+ov_range<T>::bool_array_value (bool warn) const
 {
-  Matrix m = range.matrix_value ();
+  Array<T> matrix = raw_array_value ();
 
-  if (m.any_element_is_nan ())
-    octave::err_nan_to_logical_conversion ();
-  if (warn && m.any_element_not_one_or_zero ())
+  if (warn && ! matrix.test_all (xis_one_or_zero<T>))
     warn_logical_conversion ();
 
-  return boolNDArray (m);
+  return boolNDArray (matrix);
 }
 
+template <typename T>
 octave_value
-octave_range::resize (const dim_vector& dv, bool fill) const
+ov_range<T>::resize (const dim_vector& dv, bool fill) const
 {
-  NDArray retval = array_value ();
+  Array<T> retval = raw_array_value ();
   if (fill)
     retval.resize (dv, 0);
   else
@@ -363,93 +394,184 @@
   return retval;
 }
 
+template <typename T>
+octave::range<float>
+ov_range<T>::float_range_value (void) const
+{
+  err_wrong_type_arg ("ov_range<T>::float_range_value ()", type_name ());
+}
+
+template <typename T>
+octave::range<double>
+ov_range<T>::range_value (void) const
+{
+  err_wrong_type_arg ("ov_range<T>::range_value()", type_name ());
+}
+
+template <typename T>
+octave::range<octave_int8>
+ov_range<T>::int8_range_value (void) const
+{
+  err_wrong_type_arg ("ov_range<T>::int8_range_value ()", type_name ());
+}
+
+template <typename T>
+octave::range<octave_int16>
+ov_range<T>::int16_range_value (void) const
+{
+  err_wrong_type_arg ("ov_range<T>::int16_range_value ()", type_name ());
+}
+
+template <typename T>
+octave::range<octave_int32>
+ov_range<T>::int32_range_value (void) const
+{
+  err_wrong_type_arg ("ov_range<T>::int32_range_value ()", type_name ());
+}
+
+template <typename T>
+octave::range<octave_int64>
+ov_range<T>::int64_range_value (void) const
+{
+  err_wrong_type_arg ("ov_range<T>::int64_range_value ()", type_name ());
+}
+
+template <typename T>
+octave::range<octave_uint8>
+ov_range<T>::uint8_range_value (void) const
+{
+  err_wrong_type_arg ("ov_range<T>::uint8_range_value ()", type_name ());
+}
+
+template <typename T>
+octave::range<octave_uint16>
+ov_range<T>::uint16_range_value (void) const
+{
+  err_wrong_type_arg ("ov_range<T>::uint16_range_value ()", type_name ());
+}
+
+template <typename T>
+octave::range<octave_uint32>
+ov_range<T>::uint32_range_value (void) const
+{
+  err_wrong_type_arg ("ov_range<T>::uint32_range_value ()", type_name ());
+}
+
+template <typename T>
+octave::range<octave_uint64>
+ov_range<T>::uint64_range_value (void) const
+{
+  err_wrong_type_arg ("ov_range<T>::uint64_range_value ()", type_name ());
+}
+
+template <typename T>
 octave_value
-octave_range::convert_to_str_internal (bool pad, bool force, char type) const
+ov_range<T>::convert_to_str_internal (bool pad, bool force, char type) const
 {
-  octave_value tmp (range.matrix_value ());
+  octave_value tmp (raw_array_value ());
   return tmp.convert_to_str (pad, force, type);
 }
 
+// FIXME: could most of these fucntions preserve range type now?
+
+template <typename T>
 octave_value
-octave_range::as_double (void) const
+ov_range<T>::as_double (void) const
 {
-  return range;
+  return NDArray (raw_array_value ());
 }
 
+template <typename T>
 octave_value
-octave_range::as_single (void) const
+ov_range<T>::as_single (void) const
 {
-  return FloatMatrix (range.matrix_value ());
+  return FloatMatrix (raw_array_value ());
 }
 
+template <typename T>
 octave_value
-octave_range::as_int8 (void) const
+ov_range<T>::as_int8 (void) const
 {
-  return int8NDArray (range.matrix_value ());
+  return int8NDArray (raw_array_value ());
 }
 
+template <typename T>
 octave_value
-octave_range::as_int16 (void) const
+ov_range<T>::as_int16 (void) const
 {
-  return int16NDArray (range.matrix_value ());
+  return int16NDArray (raw_array_value ());
 }
 
+template <typename T>
 octave_value
-octave_range::as_int32 (void) const
+ov_range<T>::as_int32 (void) const
 {
-  return int32NDArray (range.matrix_value ());
+  return int32NDArray (raw_array_value ());
 }
 
+template <typename T>
 octave_value
-octave_range::as_int64 (void) const
+ov_range<T>::as_int64 (void) const
 {
-  return int64NDArray (range.matrix_value ());
+  return int64NDArray (raw_array_value ());
 }
 
+template <typename T>
 octave_value
-octave_range::as_uint8 (void) const
+ov_range<T>::as_uint8 (void) const
 {
-  return uint8NDArray (range.matrix_value ());
+  return uint8NDArray (raw_array_value ());
 }
 
+template <typename T>
 octave_value
-octave_range::as_uint16 (void) const
+ov_range<T>::as_uint16 (void) const
 {
-  return uint16NDArray (range.matrix_value ());
+  return uint16NDArray (raw_array_value ());
 }
 
+template <typename T>
 octave_value
-octave_range::as_uint32 (void) const
+ov_range<T>::as_uint32 (void) const
 {
-  return uint32NDArray (range.matrix_value ());
+  return uint32NDArray (raw_array_value ());
 }
 
+template <typename T>
 octave_value
-octave_range::as_uint64 (void) const
+ov_range<T>::as_uint64 (void) const
 {
-  return uint64NDArray (range.matrix_value ());
+  return uint64NDArray (raw_array_value ());
 }
 
+template <typename T>
 void
-octave_range::print (std::ostream& os, bool pr_as_read_syntax)
+ov_range<T>::print (std::ostream& os, bool pr_as_read_syntax)
 {
   print_raw (os, pr_as_read_syntax);
   newline (os);
 }
 
+template <typename T>
 void
-octave_range::print_raw (std::ostream& os, bool pr_as_read_syntax) const
+ov_range<T>::print_raw (std::ostream& os, bool pr_as_read_syntax) const
 {
-  octave_print_internal (os, range, pr_as_read_syntax,
+  // FIXME: this is a potential waste of memory.
+
+  typedef typename octave_value_range_traits<T>::matrix_type ov_mx_type;
+  typename ov_mx_type::object_type tmp (raw_array_value ());
+
+  octave_print_internal (os, tmp, pr_as_read_syntax,
                          current_print_indent_level ());
 }
 
+template <typename T>
 bool
-octave_range::print_name_tag (std::ostream& os, const std::string& name) const
+ov_range<T>::print_name_tag (std::ostream& os, const std::string& name) const
 {
   bool retval = false;
 
-  octave_idx_type n = range.numel ();
+  octave_idx_type n = numel ();
 
   indent (os);
 
@@ -468,23 +590,24 @@
   return retval;
 }
 
+template <typename T>
 void
-octave_range::short_disp (std::ostream& os) const
+ov_range<T>::short_disp (std::ostream& os) const
 {
-  octave_idx_type len = range.numel ();
+  octave_idx_type len = numel ();
 
   if (len == 0)
     os << "[]";
   else
     {
-      os << range.base () << ':';
+      os << m_range.base () << ':';
 
       if (len > 1)
         {
-          if (range.inc () != 1)
-            os << range.inc () << ':';
+          if (m_range.increment () != T (1))
+            os << m_range.increment () << ':';
 
-          os << range.limit ();
+          os << m_range.limit ();
         }
     }
 }
@@ -506,111 +629,127 @@
   skip_until_newline (is, false);
 }
 
+template <typename T>
 float_display_format
-octave_range::get_edit_display_format (void) const
+ov_range<T>::get_edit_display_format (void) const
 {
-  return make_format (range_value ());
+  return make_format (m_range);
 }
 
+template <typename T>
 std::string
-octave_range::edit_display (const float_display_format& fmt,
-                            octave_idx_type, octave_idx_type j) const
+ov_range<T>::edit_display (const float_display_format& fmt,
+                           octave_idx_type, octave_idx_type j) const
 {
   std::ostringstream buf;
-  octave_print_internal (buf, fmt, range.elem (j));
+  octave_print_internal (buf, fmt, m_range.elem (j));
   return buf.str ();
 }
 
+template <typename T>
 bool
-octave_range::save_ascii (std::ostream& os)
+ov_range<T>::save_ascii (std::ostream& os)
 {
-  Range r = range_value ();
-  double base = r.base ();
-  double limit = r.limit ();
-  double inc = r.inc ();
+  octave::range<T> r = m_range;
+  T base = r.base ();
+  T limit = r.limit ();
+  T inc = r.increment ();
   octave_idx_type len = r.numel ();
 
-  if (inc != 0)
+  if (inc != T (0))
     os << "# base, limit, increment\n";
   else
     os << "# base, length, increment\n";
 
-  octave_write_double (os, base);
+  octave::write_value<T> (os, base);
   os << ' ';
-  if (inc != 0)
-    octave_write_double (os, limit);
+  if (inc != T (0))
+    octave::write_value<T> (os, limit);
   else
     os << len;
   os << ' ';
-  octave_write_double (os, inc);
+  octave::write_value<T> (os, inc);
   os << "\n";
 
   return true;
 }
 
+template <typename T>
 bool
-octave_range::load_ascii (std::istream& is)
+ov_range<T>::load_ascii (std::istream& is)
 {
   // # base, limit, range comment added by save ().
   skip_comments (is);
 
-  double base, limit, inc;
+  T base, limit, inc;
   is >> base >> limit >> inc;
 
   if (! is)
     error ("load: failed to load range constant");
 
-  if (inc != 0)
-    range = Range (base, limit, inc);
+  if (inc != T (0))
+    m_range = octave::range<T> (base, limit, inc);
   else
-    range = Range (base, inc, static_cast<octave_idx_type> (limit));
+    {
+      octave_idx_type numel = static_cast<octave_idx_type> (limit);
+      m_range = octave::range<T>::make_constant (base, numel);
+    }
 
   return true;
 }
 
+template <typename T>
 bool
-octave_range::save_binary (std::ostream& os, bool /* save_as_floats */)
+ov_range<T>::save_binary (std::ostream& os, bool /* save_as_floats */)
 {
+  // FIXME: Not always double!
+
   char tmp = LS_DOUBLE;
   os.write (reinterpret_cast<char *> (&tmp), 1);
-  Range r = range_value ();
-  double bas = r.base ();
-  double lim = r.limit ();
-  double inc = r.inc ();
-  if (inc == 0)
+  octave::range<T> r = m_range;
+  T bas = r.base ();
+  T lim = r.limit ();
+  T inc = r.increment ();
+  if (inc == T (0))
     lim = r.numel ();
 
-  os.write (reinterpret_cast<char *> (&bas), 8);
-  os.write (reinterpret_cast<char *> (&lim), 8);
-  os.write (reinterpret_cast<char *> (&inc), 8);
+  os.write (reinterpret_cast<char *> (&bas), sizeof (T));
+  os.write (reinterpret_cast<char *> (&lim), sizeof (T));
+  os.write (reinterpret_cast<char *> (&inc), sizeof (T));
 
   return true;
 }
 
+template <typename T>
 bool
-octave_range::load_binary (std::istream& is, bool swap,
-                           octave::mach_info::float_format /* fmt */)
+ov_range<T>::load_binary (std::istream& is, bool swap,
+                                   octave::mach_info::float_format /* fmt */)
 {
+  // FIXME: Not always double!
+
   char tmp;
   if (! is.read (reinterpret_cast<char *> (&tmp), 1))
     return false;
-  double bas, lim, inc;
-  if (! is.read (reinterpret_cast<char *> (&bas), 8))
+  T bas, lim, inc;
+  if (! is.read (reinterpret_cast<char *> (&bas), sizeof (T)))
     return false;
   if (swap)
-    swap_bytes<8> (&bas);
-  if (! is.read (reinterpret_cast<char *> (&lim), 8))
+    swap_bytes<sizeof (T)> (&bas);
+  if (! is.read (reinterpret_cast<char *> (&lim), sizeof (T)))
     return false;
   if (swap)
-    swap_bytes<8> (&lim);
-  if (! is.read (reinterpret_cast<char *> (&inc), 8))
+    swap_bytes<sizeof (T)> (&lim);
+  if (! is.read (reinterpret_cast<char *> (&inc), sizeof (T)))
     return false;
   if (swap)
-    swap_bytes<8> (&inc);
-  if (inc != 0)
-    range = Range (bas, lim, inc);
+    swap_bytes<sizeof (T)> (&inc);
+  if (inc != T (0))
+    m_range = octave::range<T> (bas, lim, inc);
   else
-    range = Range (bas, inc, static_cast<octave_idx_type> (lim));
+    {
+      octave_idx_type numel = static_cast<octave_idx_type> (lim);
+      m_range = octave::range<T>::make_constant (bas, numel);
+    }
 
   return true;
 }
@@ -623,23 +762,25 @@
 // H5T_NATIVE_DOUBLE to save as 'double').  Note that any necessary
 // conversions are handled automatically by HDF5.
 
+template <typename T>
 static hid_t
 hdf5_make_range_type (hid_t num_type)
 {
-  hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (double) * 3);
+  hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (T) * 3);
 
-  H5Tinsert (type_id, "base", 0 * sizeof (double), num_type);
-  H5Tinsert (type_id, "limit", 1 * sizeof (double), num_type);
-  H5Tinsert (type_id, "increment", 2 * sizeof (double), num_type);
+  H5Tinsert (type_id, "base", 0 * sizeof (T), num_type);
+  H5Tinsert (type_id, "limit", 1 * sizeof (T), num_type);
+  H5Tinsert (type_id, "increment", 2 * sizeof (T), num_type);
 
   return type_id;
 }
 
 #endif
 
+template <typename T>
 bool
-octave_range::save_hdf5 (octave_hdf5_id loc_id, const char *name,
-                         bool /* save_as_floats */)
+ov_range<T>::save_hdf5 (octave_hdf5_id loc_id, const char *name,
+                        bool /* save_as_floats */)
 {
   bool retval = false;
 
@@ -652,7 +793,7 @@
   space_hid = H5Screate_simple (0, dimens, nullptr);
   if (space_hid < 0) return false;
 
-  type_hid = hdf5_make_range_type (H5T_NATIVE_DOUBLE);
+  type_hid = hdf5_make_range_type<T> (hdf5_save_type);
   if (type_hid < 0)
     {
       H5Sclose (space_hid);
@@ -671,11 +812,11 @@
       return false;
     }
 
-  Range r = range_value ();
-  double range_vals[3];
+  octave::range<T> r = m_range;
+  T range_vals[3];
   range_vals[0] = r.base ();
-  range_vals[1] = (r.inc () != 0 ? r.limit () : r.numel ());
-  range_vals[2] = r.inc ();
+  range_vals[1] = (r.increment () != T (0) ? r.limit () : r.numel ());
+  range_vals[2] = r.increment ();
 
   if (H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL,
                 octave_H5P_DEFAULT, range_vals)
@@ -702,8 +843,9 @@
   return retval;
 }
 
+template <typename T>
 bool
-octave_range::load_hdf5 (octave_hdf5_id loc_id, const char *name)
+ov_range<T>::load_hdf5 (octave_hdf5_id loc_id, const char *name)
 {
   bool retval = false;
 
@@ -716,7 +858,7 @@
 #endif
   hid_t type_hid = H5Dget_type (data_hid);
 
-  hid_t range_type = hdf5_make_range_type (H5T_NATIVE_DOUBLE);
+  hid_t range_type = hdf5_make_range_type<T> (hdf5_save_type);
 
   if (! hdf5_types_compatible (type_hid, range_type))
     {
@@ -736,23 +878,21 @@
       return false;
     }
 
-  double rangevals[3];
+  T rangevals[3];
   if (H5Dread (data_hid, range_type, octave_H5S_ALL, octave_H5S_ALL,
                octave_H5P_DEFAULT, rangevals)
       >= 0)
     {
       retval = true;
-      octave_idx_type nel;
-      if (hdf5_get_scalar_attr (data_hid, H5T_NATIVE_IDX,
-                                "OCTAVE_RANGE_NELEM", &nel))
-        range = Range (rangevals[0], rangevals[2], nel);
+
+      // Don't use OCTAVE_RANGE_NELEM attribute, just reconstruct the range.
+
+      if (rangevals[2] != T (0))
+        m_range = octave::range<T> (rangevals[0], rangevals[1], rangevals[2]);
       else
         {
-          if (rangevals[2] != 0)
-            range = Range (rangevals[0], rangevals[1], rangevals[2]);
-          else
-            range = Range (rangevals[0], rangevals[2],
-                           static_cast<octave_idx_type> (rangevals[1]));
+          octave_idx_type numel = static_cast<octave_idx_type> (rangevals[1]);
+          m_range = octave::range<T>::make_constant (rangevals[0], numel);
         }
     }
 
@@ -770,28 +910,161 @@
   return retval;
 }
 
+template <typename T>
 mxArray *
-octave_range::as_mxArray (void) const
+ov_range<T>::as_mxArray (bool interleaved) const
 {
-  mxArray *retval = new mxArray (mxDOUBLE_CLASS, dims (), mxREAL);
+  mxClassID mx_class = mx_type_traits<T>::mx_class;
 
-  double *pr = static_cast<double *> (retval->get_data ());
+  mxArray *retval = new mxArray (interleaved, mx_class, dims (), mxREAL);
+
+  typedef typename mx_type_traits<T>::mx_type mx_type;
+  mx_type *pd = static_cast<mx_type *> (retval->get_data ());
 
   mwSize nel = numel ();
 
-  Matrix m = matrix_value ();
+  Array<T> matrix = raw_array_value ();
 
-  const double *p = m.data ();
+  const T *pdata = matrix.data ();
 
   for (mwSize i = 0; i < nel; i++)
-    pr[i] = p[i];
+    pd[i] = pdata[i];
 
   return retval;
 }
 
+template <typename T>
 octave_value
-octave_range::fast_elem_extract (octave_idx_type n) const
+ov_range<T>::fast_elem_extract (octave_idx_type n) const
+{
+  return (n < numel () ? octave_value (m_range.elem (n)) : octave_value ());
+}
+
+// Specializations.
+
+template <>
+octave::range<float>
+ov_range<float>::float_range_value (void) const
+{
+  return m_range;
+}
+
+template <>
+octave::range<double>
+ov_range<double>::range_value (void) const
+{
+  return m_range;
+}
+
+template <>
+octave::range<octave_int8>
+ov_range<octave_int8>::int8_range_value (void) const
+{
+  return m_range;
+}
+
+template <>
+octave::range<octave_int16>
+ov_range<octave_int16>::int16_range_value (void) const
+{
+  return m_range;
+}
+
+template <>
+octave::range<octave_int32>
+ov_range<octave_int32>::int32_range_value (void) const
+{
+  return m_range;
+}
+
+template <>
+octave::range<octave_int64>
+ov_range<octave_int64>::int64_range_value (void) const
+{
+  return m_range;
+}
+
+template <>
+octave::range<octave_uint8>
+ov_range<octave_uint8>::uint8_range_value (void) const
+{
+  return m_range;
+}
+
+template <>
+octave::range<octave_uint16>
+ov_range<octave_uint16>::uint16_range_value (void) const
 {
-  return (n < range.numel ()) ? octave_value (range.elem (n))
-                              : octave_value ();
+  return m_range;
+}
+
+template <>
+octave::range<octave_uint32>
+ov_range<octave_uint32>::uint32_range_value (void) const
+{
+  return m_range;
+}
+
+template <>
+octave::range<octave_uint64>
+ov_range<octave_uint64>::uint64_range_value (void) const
+{
+  return m_range;
+}
+
+template <>
+idx_vector
+ov_range<double>::index_vector (bool require_integers) const
+{
+  if (m_idx_cache)
+    return *m_idx_cache;
+
+  if (require_integers || m_range.all_elements_are_ints ())
+    return set_idx_cache (idx_vector (m_range));
+
+  warning_with_id ("Octave:noninteger-range-as-index",
+                   "non-integer range used as index");
+
+  return octave_value (matrix_value ()).round ().index_vector ();
 }
+
+template <>
+octave_idx_type
+ov_range<double>::nnz (void) const
+{
+  return m_range.nnz ();
+}
+
+// The following specialization is also historical baggage.  For double
+// ranges, we can produce special double-valued diagnoal matrix objects
+// but Octave currently provides only double and Complex diagonal matrix
+// objects.
+
+template <>
+octave_value
+ov_range<double>::diag (octave_idx_type k) const
+{
+  // FIXME: this is a potential waste of memory.
+
+  return
+    (k == 0
+     ? octave_value (DiagMatrix (DiagArray2<double> (matrix_value ())))
+     : octave_value (m_range.diag (k)));
+}
+
+template <>
+octave_value
+ov_range<double>::diag (octave_idx_type nr, octave_idx_type nc) const
+{
+  Matrix mat = matrix_value ();
+
+  return mat.diag (nr, nc);
+}
+
+template <>
+void
+ov_range<double>::print_raw (std::ostream& os, bool pr_as_read_syntax) const
+{
+  octave_print_internal (os, m_range, pr_as_read_syntax,
+                         current_print_indent_level ());
+}
--- a/libinterp/octave-value/ov-range.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-range.h	Thu Nov 19 13:08:00 2020 -0800
@@ -43,6 +43,7 @@
 #include "error.h"
 #include "oct-stream.h"
 #include "ov-base.h"
+#include "ov-range-traits.h"
 #include "ov-re-mat.h"
 #include "ov-typeinfo.h"
 
@@ -50,52 +51,58 @@
 
 // Range values.
 
+template <typename T>
 class
-octave_range : public octave_base_value
+ov_range : public octave_base_value
 {
 public:
 
-  octave_range (void)
-    : octave_base_value (), range (), idx_cache () { }
+  ov_range (void)
+    : octave_base_value (), m_range (), m_idx_cache () { }
 
-  octave_range (double base, double limit, double inc)
-    : octave_base_value (), range (base, limit, inc), idx_cache ()
+  ov_range (const octave::range<T>& r)
+    : octave_base_value (), m_range (r), m_idx_cache ()
   {
-    if (range.numel () < 0)
+    if (numel () < 0 && numel () != -2)
       error ("invalid range");
   }
 
-  octave_range (const Range& r)
-    : octave_base_value (), range (r), idx_cache ()
-  {
-    if (range.numel () < 0 && range.numel () != -2)
-      error ("invalid range");
-  }
-
-  octave_range (const octave_range& r)
-    : octave_base_value (), range (r.range),
-      idx_cache (r.idx_cache ? new idx_vector (*r.idx_cache) : nullptr)
+  ov_range (const ov_range<T>& r)
+    : octave_base_value (), m_range (r.m_range),
+      m_idx_cache (r.m_idx_cache ? new idx_vector (*r.m_idx_cache) : nullptr)
   { }
 
-  octave_range (const Range& r, const idx_vector& cache)
-    : octave_base_value (), range (r), idx_cache ()
+  ov_range (const octave::range<T>& r, const idx_vector& cache)
+    : octave_base_value (), m_range (r), m_idx_cache ()
   {
     set_idx_cache (cache);
   }
 
-  ~octave_range (void) { clear_cached_info (); }
+  // No assignment.
+  ov_range& operator = (const ov_range&) = delete;
+
+  ~ov_range (void) { clear_cached_info (); }
 
-  octave_base_value * clone (void) const { return new octave_range (*this); }
+  octave_base_value * clone (void) const
+  {
+    return new ov_range (*this);
+  }
 
   // A range is really just a special kind of real matrix object.  In
   // the places where we need to call empty_clone, it makes more sense
   // to create an empty matrix (0x0) instead of an empty range (1x0).
-  octave_base_value * empty_clone (void) const { return new octave_matrix (); }
+
+  octave_base_value * empty_clone (void) const
+  {
+    return new typename octave_value_range_traits<T>::matrix_type ();
+  }
 
   type_conv_info numeric_conversion_function (void) const;
 
   octave_base_value * try_narrowing_conversion (void);
 
+  builtin_type_t builtin_type (void) const { return class_to_btyp<T>::btyp; }
+
   // We don't need to override all three forms of subsref.  The using
   // declaration will avoid warnings about partially-overloaded virtual
   // functions.
@@ -115,25 +122,37 @@
 
   dim_vector dims (void) const
   {
-    octave_idx_type n = range.numel ();
+    octave_idx_type n = numel ();
     return dim_vector (n > 0, n);
   }
 
-  octave_idx_type nnz (void) const { return range.nnz (); }
+  octave_idx_type numel (void) const { return m_range.numel (); }
+
+  octave_idx_type nnz (void) const
+  {
+    // FIXME: this is a potential waste of memory.
+
+    octave_value tmp (raw_array_value ());
+    return tmp.nnz ();
+  }
 
   octave_value resize (const dim_vector& dv, bool fill = false) const;
 
-  size_t byte_size (void) const { return 3 * sizeof (double); }
+  size_t byte_size (void) const { return 3 * sizeof (T); }
 
   octave_value reshape (const dim_vector& new_dims) const
-  { return NDArray (array_value ().reshape (new_dims)); }
+  {
+    return raw_array_value ().reshape (new_dims);
+  }
 
   octave_value permute (const Array<int>& vec, bool inv = false) const
-  { return NDArray (array_value ().permute (vec, inv)); }
+  {
+    return raw_array_value ().permute (vec, inv);
+  }
 
-  octave_value squeeze (void) const { return range; }
+  octave_value squeeze (void) const { return m_range; }
 
-  octave_value full_value (void) const { return range.matrix_value (); }
+  octave_value full_value (void) const { return raw_array_value (); }
 
   bool is_defined (void) const { return true; }
 
@@ -141,63 +160,142 @@
 
   bool is_range (void) const { return true; }
 
-  octave_value all (int dim = 0) const;
+  bool is_double_type (void) const { return builtin_type () == btyp_double; }
+
+  bool is_single_type (void) const { return builtin_type () == btyp_float; }
+
+  bool isfloat (void) const { return btyp_isfloat (builtin_type ()); }
+
+  bool is_int8_type (void) const { return builtin_type () == btyp_int8; }
+
+  bool is_int16_type (void) const { return builtin_type () == btyp_int16; }
+
+  bool is_int32_type (void) const { return builtin_type () == btyp_int32; }
+
+  bool is_int64_type (void) const { return builtin_type () == btyp_int64; }
+
+  bool is_uint8_type (void) const { return builtin_type () == btyp_uint8; }
+
+  bool is_uint16_type (void) const { return builtin_type () == btyp_uint16; }
 
-  octave_value any (int dim = 0) const;
+  bool is_uint32_type (void) const { return builtin_type () == btyp_uint32; }
+
+  bool is_uint64_type (void) const { return builtin_type () == btyp_uint64; }
+
+  bool isinteger (void) const
+  {
+    return btyp_isinteger (builtin_type ());
+  }
+
+  bool isreal (void) const { return isfloat (); }
+
+  bool isnumeric (void) const
+  {
+    return btyp_isnumeric (builtin_type ());
+  }
+
+  bool is_true (void) const { return nnz () == numel (); }
 
-  octave_value diag (octave_idx_type k = 0) const;
+  octave_value all (int dim = 0) const
+  {
+    // FIXME: this is a potential waste of memory.
+
+    typedef typename octave_value_range_traits<T>::matrix_type ov_mx_type;
+    typename ov_mx_type::object_type m (raw_array_value ());
+
+    return m.all (dim);
+  }
+
+  octave_value any (int dim = 0) const
+  {
+    // FIXME: this is a potential waste of memory.
+
+    typedef typename octave_value_range_traits<T>::matrix_type ov_mx_type;
+    typename ov_mx_type::object_type m (raw_array_value ());
 
-  octave_value diag (octave_idx_type m, octave_idx_type n) const;
+    return m.any (dim);
+  }
+
+  octave_value diag (octave_idx_type k = 0) const
+  {
+    // FIXME: this is a potential waste of memory.
+
+    return m_range.diag (k);
+  }
+
+  octave_value diag (octave_idx_type nr, octave_idx_type nc) const
+  {
+    // FIXME: this is a potential waste of memory.
+
+    typedef typename octave_value_range_traits<T>::matrix_type ov_mx_type;
+    typename ov_mx_type::object_type m (raw_array_value ());
+
+    return m.diag (nr, nc);
+  }
 
   octave_value sort (octave_idx_type dim = 0, sortmode mode = ASCENDING) const
-  { return range.sort (dim, mode); }
+  {
+    Array<T> tmp = raw_array_value ();
+    return tmp.sort (dim, mode);
+  }
 
   octave_value sort (Array<octave_idx_type>& sidx, octave_idx_type dim = 0,
                      sortmode mode = ASCENDING) const
-  { return range.sort (sidx, dim, mode); }
+  {
+    Array<T> tmp = raw_array_value ();
+    return tmp.sort (sidx, dim, mode);
+  }
 
   sortmode issorted (sortmode mode = UNSORTED) const
-  { return range.issorted (mode); }
+  {
+    return m_range.issorted (mode);
+  }
 
   Array<octave_idx_type> sort_rows_idx (sortmode) const
-  { return Array<octave_idx_type> (dim_vector (1, 0)); }
+  {
+    return Array<octave_idx_type> (dim_vector (1, 0));
+  }
 
   sortmode is_sorted_rows (sortmode mode = UNSORTED) const
-  { return (mode == UNSORTED) ? ASCENDING : mode; }
-
-  builtin_type_t builtin_type (void) const { return btyp_double; }
-
-  bool isreal (void) const { return true; }
+  {
+    return (mode == UNSORTED) ? ASCENDING : mode;
+  }
 
-  bool is_double_type (void) const { return true; }
-
-  bool isfloat (void) const { return true; }
-
-  bool isnumeric (void) const { return true; }
-
-  bool is_true (void) const;
+  Array<T> raw_array_value (void) const { return m_range.array_value (); }
 
   double double_value (bool = false) const;
 
   float float_value (bool = false) const;
 
   double scalar_value (bool frc_str_conv = false) const
-  { return double_value (frc_str_conv); }
+  {
+    return double_value (frc_str_conv);
+  }
 
   float float_scalar_value (bool frc_str_conv = false) const
-  { return float_value (frc_str_conv); }
+  {
+    return float_value (frc_str_conv);
+  }
 
   Matrix matrix_value (bool = false) const
-  { return range.matrix_value (); }
+  {
+    return raw_array_value ();
+  }
 
   FloatMatrix float_matrix_value (bool = false) const
-  { return range.matrix_value (); }
+  {
+    return raw_array_value ();
+  }
 
   NDArray array_value (bool = false) const
-  { return range.matrix_value (); }
+  {
+    return raw_array_value ();
+  }
 
   FloatNDArray float_array_value (bool = false) const
-  { return FloatMatrix (range.matrix_value ()); }
+  {
+    return raw_array_value ();
+  }
 
   charNDArray char_array_value (bool = false) const;
 
@@ -205,35 +303,55 @@
   // functions to avoid the intermediate conversion to a matrix
   // object.
 
-  int8NDArray
-  int8_array_value (void) const { return int8NDArray (array_value ()); }
+  int8NDArray int8_array_value (void) const
+  {
+    return raw_array_value ();
+  }
 
-  int16NDArray
-  int16_array_value (void) const { return int16NDArray (array_value ()); }
+  int16NDArray int16_array_value (void) const
+  {
+    return raw_array_value ();
+  }
 
-  int32NDArray
-  int32_array_value (void) const { return int32NDArray (array_value ()); }
+  int32NDArray int32_array_value (void) const
+  {
+    return raw_array_value ();
+  }
 
-  int64NDArray
-  int64_array_value (void) const { return int64NDArray (array_value ()); }
+  int64NDArray int64_array_value (void) const
+  {
+    return raw_array_value ();
+  }
 
-  uint8NDArray
-  uint8_array_value (void) const { return uint8NDArray (array_value ()); }
+  uint8NDArray uint8_array_value (void) const
+  {
+    return raw_array_value ();
+  }
 
-  uint16NDArray
-  uint16_array_value (void) const { return uint16NDArray (array_value ()); }
+  uint16NDArray uint16_array_value (void) const
+  {
+    return raw_array_value ();
+  }
 
-  uint32NDArray
-  uint32_array_value (void) const { return uint32NDArray (array_value ()); }
+  uint32NDArray uint32_array_value (void) const
+  {
+    return raw_array_value ();
+  }
 
-  uint64NDArray
-  uint64_array_value (void) const { return uint64NDArray (array_value ()); }
+  uint64NDArray uint64_array_value (void) const
+  {
+    return raw_array_value ();
+  }
 
   SparseMatrix sparse_matrix_value (bool = false) const
-  { return SparseMatrix (range.matrix_value ()); }
+  {
+    return SparseMatrix (matrix_value ());
+  }
 
   SparseComplexMatrix sparse_complex_matrix_value (bool = false) const
-  { return SparseComplexMatrix (sparse_matrix_value ()); }
+  {
+    return SparseComplexMatrix (complex_matrix_value ());
+  }
 
   Complex complex_value (bool = false) const;
 
@@ -242,18 +360,44 @@
   boolNDArray bool_array_value (bool warn = false) const;
 
   ComplexMatrix complex_matrix_value (bool = false) const
-  { return ComplexMatrix (range.matrix_value ()); }
+  {
+    return raw_array_value ();
+  }
 
   FloatComplexMatrix float_complex_matrix_value (bool = false) const
-  { return FloatComplexMatrix (range.matrix_value ()); }
+  {
+    return raw_array_value ();
+  }
 
   ComplexNDArray complex_array_value (bool = false) const
-  { return ComplexMatrix (range.matrix_value ()); }
+  {
+    return raw_array_value ();
+  }
 
   FloatComplexNDArray float_complex_array_value (bool = false) const
-  { return FloatComplexMatrix (range.matrix_value ()); }
+  {
+    return raw_array_value ();
+  }
+
+  octave::range<float> float_range_value (void) const;
+
+  octave::range<double> range_value (void) const;
+
+  octave::range<octave_int8> int8_range_value (void) const;
+
+  octave::range<octave_int16> int16_range_value (void) const;
 
-  Range range_value (void) const { return range; }
+  octave::range<octave_int32> int32_range_value (void) const;
+
+  octave::range<octave_int64> int64_range_value (void) const;
+
+  octave::range<octave_uint8> uint8_range_value (void) const;
+
+  octave::range<octave_uint16> uint16_range_value (void) const;
+
+  octave::range<octave_uint32> uint32_range_value (void) const;
+
+  octave::range<octave_uint64> uint64_range_value (void) const;
 
   octave_value convert_to_str_internal (bool pad, bool force, char type) const;
 
@@ -292,7 +436,7 @@
   bool load_binary (std::istream& is, bool swap,
                     octave::mach_info::float_format fmt);
 
-  bool save_hdf5 (octave_hdf5_id loc_id, const char *name, bool save_as_floats);
+  bool save_hdf5 (octave_hdf5_id loc_id, const char *name, bool flag);
 
   bool load_hdf5 (octave_hdf5_id loc_id, const char *name);
 
@@ -306,39 +450,134 @@
     return os.write (matrix_value (), block_size, output_type, skip, flt_fmt);
   }
 
-  mxArray * as_mxArray (void) const;
+  mxArray * as_mxArray (bool interleaved) const;
 
   octave_value map (unary_mapper_t umap) const
   {
-    octave_matrix m (matrix_value ());
-    return m.map (umap);
+    octave_value tmp (raw_array_value ());
+    return tmp.map (umap);
   }
 
   octave_value fast_elem_extract (octave_idx_type n) const;
 
-private:
+protected:
 
-  Range range;
+  octave::range<T> m_range;
 
   idx_vector set_idx_cache (const idx_vector& idx) const
   {
-    delete idx_cache;
-    idx_cache = (idx ? new idx_vector (idx) : nullptr);
+    delete m_idx_cache;
+    m_idx_cache = (idx ? new idx_vector (idx) : nullptr);
     return idx;
   }
 
   void clear_cached_info (void) const
   {
-    delete idx_cache; idx_cache = nullptr;
+    delete m_idx_cache; m_idx_cache = nullptr;
   }
 
-  mutable idx_vector *idx_cache;
+  mutable idx_vector *m_idx_cache;
 
-  // No assignment.
-
-  octave_range& operator = (const octave_range&);
+  static octave_hdf5_id hdf5_save_type;
 
   DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
 };
 
+DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, float)
+DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, double)
+DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, octave_int8)
+DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, octave_int16)
+DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, octave_int32)
+DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, octave_int64)
+DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, octave_uint8)
+DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, octave_uint16)
+DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, octave_uint32)
+DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, octave_uint64)
+
+// Specializations.
+
+template <>
+octave::range<float>
+ov_range<float>::float_range_value (void) const;
+
+template <>
+octave::range<double>
+ov_range<double>::range_value (void) const;
+
+template <>
+octave::range<octave_int8>
+ov_range<octave_int8>::int8_range_value (void) const;
+
+template <>
+octave::range<octave_int16>
+ov_range<octave_int16>::int16_range_value (void) const;
+
+template <>
+octave::range<octave_int32>
+ov_range<octave_int32>::int32_range_value (void) const;
+
+template <>
+octave::range<octave_int64>
+ov_range<octave_int64>::int64_range_value (void) const;
+
+template <>
+octave::range<octave_uint8>
+ov_range<octave_uint8>::uint8_range_value (void) const;
+
+template <>
+octave::range<octave_uint16>
+ov_range<octave_uint16>::uint16_range_value (void) const;
+
+template <>
+octave::range<octave_uint32>
+ov_range<octave_uint32>::uint32_range_value (void) const;
+
+template <>
+octave::range<octave_uint64>
+ov_range<octave_uint64>::uint64_range_value (void) const;
+
+// The following specializations are here to preserve previous Range
+// performance until solutions can be generalized for other types.
+
+template <>
+idx_vector
+ov_range<double>::index_vector (bool require_integers) const;
+
+template <>
+octave_idx_type
+ov_range<double>::nnz (void) const;
+
+// The following specialization is also historical baggage.  For double
+// ranges, we can produce special double-valued diagnoal matrix objects
+// but Octave currently provides only double and Complex diagonal matrix
+// objects.
+
+template <>
+octave_value
+ov_range<double>::diag (octave_idx_type k) const;
+
+template <>
+octave_value
+ov_range<double>::diag (octave_idx_type nr, octave_idx_type nc) const;
+
+template <>
+void
+ov_range<double>::print_raw (std::ostream& os, bool pr_as_read_syntax) const;
+
+
+typedef ov_range<float> octave_float_range;
+typedef ov_range<double> octave_double_range;
+
+typedef ov_range<octave_int8> octave_int8_range;
+typedef ov_range<octave_int16> octave_int16_range;
+typedef ov_range<octave_int32> octave_int32_range;
+typedef ov_range<octave_int64> octave_int64_range;
+
+typedef ov_range<octave_uint8> octave_uint8_range;
+typedef ov_range<octave_uint16> octave_uint16_range;
+typedef ov_range<octave_uint32> octave_uint32_range;
+typedef ov_range<octave_uint64> octave_uint64_range;
+
+typedef octave_double_range octave_range;
+
 #endif
--- a/libinterp/octave-value/ov-re-mat.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-re-mat.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -844,18 +844,18 @@
 }
 
 mxArray *
-octave_matrix::as_mxArray (void) const
+octave_matrix::as_mxArray (bool interleaved) const
 {
-  mxArray *retval = new mxArray (mxDOUBLE_CLASS, dims (), mxREAL);
+  mxArray *retval = new mxArray (interleaved, mxDOUBLE_CLASS, dims (), mxREAL);
 
-  double *pr = static_cast<double *> (retval->get_data ());
+  mxDouble *pd = static_cast<mxDouble *> (retval->get_data ());
 
   mwSize nel = numel ();
 
-  const double *p = matrix.data ();
+  const double *pdata = matrix.data ();
 
   for (mwIndex i = 0; i < nel; i++)
-    pr[i] = p[i];
+    pd[i] = pdata[i];
 
   return retval;
 }
--- a/libinterp/octave-value/ov-re-mat.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-re-mat.h	Thu Nov 19 13:08:00 2020 -0800
@@ -241,7 +241,7 @@
   // You should not use it anywhere else.
   void * mex_get_data (void) const { return matrix.mex_get_data (); }
 
-  mxArray * as_mxArray (void) const;
+  mxArray * as_mxArray (bool interleaved) const;
 
   octave_value map (unary_mapper_t umap) const;
 
--- a/libinterp/octave-value/ov-re-sparse.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-re-sparse.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -861,24 +861,34 @@
 }
 
 mxArray *
-octave_sparse_matrix::as_mxArray (void) const
+octave_sparse_matrix::as_mxArray (bool interleaved) const
 {
   mwSize nz = nzmax ();
   mwSize nr = rows ();
   mwSize nc = columns ();
-  mxArray *retval = new mxArray (mxDOUBLE_CLASS, nr, nc, nz, mxREAL);
-  double *pr = static_cast<double *> (retval->get_data ());
+
+  mxArray *retval = new mxArray (interleaved, mxDOUBLE_CLASS, nr, nc, nz,
+                                 mxREAL);
+
+  mxDouble *pd = static_cast<mxDouble *> (retval->get_data ());
   mwIndex *ir = retval->get_ir ();
-  mwIndex *jc = retval->get_jc ();
+
+  const double *pdata = matrix.data ();
+  const octave_idx_type *pridx = matrix.ridx ();
 
   for (mwIndex i = 0; i < nz; i++)
     {
-      pr[i] = matrix.data (i);
-      ir[i] = matrix.ridx (i);
+      pd[i] = pdata[i];
+
+      ir[i] = pridx[i];
     }
 
+  mwIndex *jc = retval->get_jc ();
+
+  const octave_idx_type *pcidx = matrix.cidx ();
+
   for (mwIndex i = 0; i < nc + 1; i++)
-    jc[i] = matrix.cidx (i);
+    jc[i] = pcidx[i];
 
   return retval;
 }
--- a/libinterp/octave-value/ov-re-sparse.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-re-sparse.h	Thu Nov 19 13:08:00 2020 -0800
@@ -152,7 +152,7 @@
 
   bool load_hdf5 (octave_hdf5_id loc_id, const char *name);
 
-  mxArray * as_mxArray (void) const;
+  mxArray * as_mxArray (bool interleaved) const;
 
   octave_value map (unary_mapper_t umap) const;
 
--- a/libinterp/octave-value/ov-scalar.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-scalar.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -98,7 +98,7 @@
 
   octave_value tmp (new octave_matrix (matrix_value ()));
 
-  return tmp.do_index_op (idx, resize_ok);
+  return tmp.index_op (idx, resize_ok);
 }
 
 octave_value
@@ -219,7 +219,7 @@
 {
   double d = double_value ();
 
-  octave_write_double (os, d);
+  octave::write_value<double> (os, d);
 
   os << "\n";
 
@@ -229,7 +229,7 @@
 bool
 octave_scalar::load_ascii (std::istream& is)
 {
-  scalar = octave_read_value<double> (is);
+  scalar = octave::read_value<double> (is);
 
   if (! is)
     error ("load: failed to load scalar constant");
@@ -356,13 +356,13 @@
 }
 
 mxArray *
-octave_scalar::as_mxArray (void) const
+octave_scalar::as_mxArray (bool interleaved) const
 {
-  mxArray *retval = new mxArray (mxDOUBLE_CLASS, 1, 1, mxREAL);
+  mxArray *retval = new mxArray (interleaved, mxDOUBLE_CLASS, 1, 1, mxREAL);
 
-  double *pr = static_cast<double *> (retval->get_data ());
+  mxDouble *pd = static_cast<mxDouble *> (retval->get_data ());
 
-  pr[0] = scalar;
+  pd[0] = scalar;
 
   return retval;
 }
--- a/libinterp/octave-value/ov-scalar.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-scalar.h	Thu Nov 19 13:08:00 2020 -0800
@@ -269,7 +269,7 @@
                      skip, flt_fmt);
   }
 
-  mxArray * as_mxArray (void) const;
+  mxArray * as_mxArray (bool interleaved) const;
 
   octave_value map (unary_mapper_t umap) const;
 
--- a/libinterp/octave-value/ov-str-mat.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-str-mat.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -234,10 +234,23 @@
 
   charMatrix chm (matrix);
 
+  if (chm.rows () > 1)
+    warning_with_id ("Octave:charmat-truncated",
+                     "multi-row character matrix converted to a string, only the first row is used");
+
   // FIXME: Is this correct?
   return chm.row_as_string (0);
 }
 
+/*
+%!test <*49536>
+%! warning ("on", "Octave:charmat-truncated", "local");
+%! s = char ("this", "is", "a", "char", "matrix");
+%! fail ("sprintf (s)", ...
+%!       "warning",     ...
+%!       "multi-row character matrix converted to a string");
+*/
+
 Array<std::string>
 octave_char_matrix_str::cellstr_value (void) const
 {
@@ -268,7 +281,8 @@
 {
   if (matrix.ndims () == 2 && numel () > 0)
     {
-      std::string tmp = string_value ();
+      charMatrix chm (matrix);
+      std::string tmp = chm.row_as_string (0);
 
       // FIXME: should this be configurable?
       size_t max_len = 100;
--- a/libinterp/octave-value/ov-struct.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-struct.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -586,9 +586,7 @@
 void
 octave_struct::print_raw (std::ostream& os, bool) const
 {
-  octave::unwind_protect frame;
-
-  frame.protect_var (Vstruct_levels_to_print);
+  octave::unwind_protect_var<int> restore_var (Vstruct_levels_to_print);
 
   if (Vstruct_levels_to_print >= 0)
     {
@@ -1022,7 +1020,7 @@
 }
 
 mxArray *
-octave_struct::as_mxArray (void) const
+octave_struct::as_mxArray (bool interleaved) const
 {
   int nf = nfields ();
   string_vector kv = map_keys ();
@@ -1032,7 +1030,7 @@
   for (int i = 0; i < nf; i++)
     f[i] = kv[i].c_str ();
 
-  mxArray *retval = new mxArray (dims (), nf, f);
+  mxArray *retval = new mxArray (interleaved, dims (), nf, f);
 
   mxArray **elts = static_cast<mxArray **> (retval->get_data ());
 
@@ -1048,7 +1046,7 @@
 
       mwIndex k = 0;
       for (mwIndex j = i; j < ntot; j += nf)
-        elts[j] = new mxArray (p[k++]);
+        elts[j] = new mxArray (interleaved, p[k++]);
     }
 
   return retval;
@@ -1299,9 +1297,7 @@
 void
 octave_scalar_struct::print_raw (std::ostream& os, bool) const
 {
-  octave::unwind_protect frame;
-
-  frame.protect_var (Vstruct_levels_to_print);
+  octave::unwind_protect_var<int> restore_var (Vstruct_levels_to_print);
 
   if (Vstruct_levels_to_print >= 0)
     {
@@ -1640,7 +1636,7 @@
 }
 
 mxArray *
-octave_scalar_struct::as_mxArray (void) const
+octave_scalar_struct::as_mxArray (bool interleaved) const
 {
   int nf = nfields ();
   string_vector kv = map_keys ();
@@ -1650,7 +1646,7 @@
   for (int i = 0; i < nf; i++)
     f[i] = kv[i].c_str ();
 
-  mxArray *retval = new mxArray (dims (), nf, f);
+  mxArray *retval = new mxArray (interleaved, dims (), nf, f);
 
   mxArray **elts = static_cast<mxArray **> (retval->get_data ());
 
@@ -1666,7 +1662,7 @@
 
       mwIndex k = 0;
       for (mwIndex j = i; j < ntot; j += nf)
-        elts[j] = new mxArray (p[k++]);
+        elts[j] = new mxArray (interleaved, p[k++]);
     }
 
   return retval;
@@ -1991,6 +1987,46 @@
 %!assert (isfield (struct ("a", 1, "b", 2), {"a", "c"}), [true, false])
 */
 
+OCTAVE_NORETURN
+static void
+invalid_cell2struct_fields_error (void)
+{
+  error ("cell2struct: FIELDS must be a cell array of strings or a scalar string");
+}
+
+static Array<std::string>
+get_cell2struct_fields (const octave_value& arg)
+{
+  if (arg.is_string ())
+    {
+      if (arg.rows () != 1)
+        invalid_cell2struct_fields_error ();
+
+      return Array<std::string> (dim_vector (1, 1), arg.string_value ());
+    }
+
+  if (arg.iscell ())
+    {
+      const Cell c = arg.cell_value ();
+
+      Array<std::string> retval (c.dims ());
+
+      for (octave_idx_type i = 0; i < c.numel (); i++)
+        {
+          const octave_value val = c(i);
+
+          if (! val.is_string () || val.rows () != 1)
+            invalid_cell2struct_fields_error ();
+
+          retval(i) = c(i).string_value ();
+        }
+
+      return retval;
+    }
+
+  invalid_cell2struct_fields_error ();
+}
+
 DEFUN (cell2struct, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn  {} {} cell2struct (@var{cell}, @var{fields})
@@ -2024,11 +2060,10 @@
   if (nargin < 2 || nargin > 3)
     print_usage ();
 
-  if (! args(0).iscell ())
-    error ("cell2struct: argument CELL must be of type cell");
-
-  if (! (args(1).iscellstr () || args(1).is_char_matrix ()))
-    error ("cell2struct: FIELDS must be a cell array of strings or a character matrix");
+  const Cell vals
+    = args(0).xcell_value ("cell2struct: argument CELL must be of type cell");
+
+  const Array<std::string> fields = get_cell2struct_fields (args(1));
 
   int dim = 0;
 
@@ -2043,9 +2078,6 @@
   if (dim < 0)
     error ("cell2struct: DIM must be a valid dimension");
 
-  const Cell vals = args(0).cell_value ();
-  const Array<std::string> fields = args(1).cellstr_value ();
-
   octave_idx_type ext = (vals.ndims () > dim ? vals.dims ()(dim) : 1);
 
   if (ext != fields.numel ())
@@ -2095,6 +2127,12 @@
 %!assert (cell2struct ({1; 2}, {"a"; "b"}), struct ("a", 1, "b", 2))
 
 %!assert (cell2struct ({}, {"f"}, 3), struct ("f", {}))
+
+%!assert (cell2struct ({1; 2; 3; 4}, {'a', 'b'; 'c', 'd'}),
+%!        struct ('a', 1, 'c', 2, 'b', 3, 'd', 4));
+%!assert (cell2struct ({1, 2, 3, 4}, {'a', 'b'; 'c', 'd'}, 2),
+%!        struct ('a', 1, 'c', 2, 'b', 3, 'd', 4));
+%!error cell2struct ({1, 2, 3, 4}, {'a', 'b'; 'c', 'd'})
 */
 
 DEFUN (rmfield, args, ,
--- a/libinterp/octave-value/ov-struct.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-struct.h	Thu Nov 19 13:08:00 2020 -0800
@@ -150,7 +150,7 @@
 
   bool load_hdf5 (octave_hdf5_id loc_id, const char *name);
 
-  mxArray * as_mxArray (void) const;
+  mxArray * as_mxArray (bool interleaved) const;
 
   octave_value
   fast_elem_extract (octave_idx_type n) const;
@@ -274,7 +274,7 @@
 
   bool load_hdf5 (octave_hdf5_id loc_id, const char *name);
 
-  mxArray * as_mxArray (void) const;
+  mxArray * as_mxArray (bool interleaved) const;
 
   bool fast_elem_insert_self (void *where, builtin_type_t btyp) const;
 
--- a/libinterp/octave-value/ov-typeinfo.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-typeinfo.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -942,7 +942,12 @@
 %!assert (typeinfo ([i, 2]), "complex matrix")
 %!assert (typeinfo (diag ([i, 2])), "complex diagonal matrix")
 
-%!assert (typeinfo (1:2), "range")
+%!test
+%! if (disable_range ())
+%!   assert (typeinfo (1:2), "matrix")
+%! else
+%!   assert (typeinfo (1:2), "range")
+%! endif
 
 %!assert (typeinfo (false), "bool")
 %!assert (typeinfo ([true, false]), "bool matrix")
--- a/libinterp/octave-value/ov-typeinfo.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov-typeinfo.h	Thu Nov 19 13:08:00 2020 -0800
@@ -56,7 +56,7 @@
       (const octave_base_value&, const octave_base_value&);
 
     typedef octave_value (*cat_op_fcn)
-      (octave_base_value&, const octave_base_value&,
+      (const octave_base_value&, const octave_base_value&,
      const Array<octave_idx_type>& ra_idx);
 
     typedef octave_value (*assign_op_fcn)
--- a/libinterp/octave-value/ov.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -76,6 +76,7 @@
 #include "ov-usr-fcn.h"
 #include "ov-fcn-handle.h"
 #include "ov-typeinfo.h"
+#include "ov-magic-int.h"
 #include "ov-null-mat.h"
 #include "ov-lazy-idx.h"
 #include "ov-java.h"
@@ -1007,7 +1008,7 @@
   : rep ()
 {
   double scalar;
-  Range range;
+  octave::range<double> range;
   NDArray array;
   boolNDArray mask;
   idx_vector::idx_class_type idx_class;
@@ -1068,15 +1069,126 @@
 }
 
 octave_value::octave_value (double base, double limit, double inc)
-  : rep (new octave_range (base, limit, inc))
+  : rep (new ov_range<double> (octave::range<double> (base, inc, limit)))
 {
   maybe_mutate ();
 }
 
 octave_value::octave_value (const Range& r, bool force_range)
+  : rep (nullptr)
+{
+  if (! force_range && ! r.ok ())
+    error ("invalid range");
+
+  if (force_range || ! Vdisable_range)
+    rep = dynamic_cast<octave_base_value *> (new ov_range<double> (octave::range<double> (r.base (), r.increment (), r.limit ())));
+  else
+    rep = dynamic_cast<octave_base_value *> (new octave_matrix (r.matrix_value ()));
+
+  maybe_mutate ();
+}
+
+octave_value::octave_value (const octave::range<char>& r, char type,
+                            bool /*force_range*/)
+#if 0
   : rep (force_range || ! Vdisable_range
-         ? dynamic_cast<octave_base_value *> (new octave_range (r))
-         : dynamic_cast<octave_base_value *> (new octave_matrix (r.matrix_value ())))
+         ? dynamic_cast<octave_base_value *> (new octave_char_range (r, type))
+         : dynamic_cast<octave_base_value *> (type == '"'
+                                              ? new octave_char_matrix_dq_str (r.array_value ())
+                                              : new octave_char_matrix_sq_str (r.array_value ())))
+#else
+  : rep (type == '"'
+         ? new octave_char_matrix_dq_str (r.array_value ())
+         : new octave_char_matrix_sq_str (r.array_value ()))
+#endif
+{
+  maybe_mutate ();
+}
+
+octave_value::octave_value (const octave::range<float>& r, bool force_range)
+  : rep (force_range || ! Vdisable_range
+         ? dynamic_cast<octave_base_value *> (new ov_range<float> (r))
+         : dynamic_cast<octave_base_value *> (new octave_float_matrix (r.array_value ())))
+{
+  maybe_mutate ();
+}
+
+octave_value::octave_value (const octave::range<double>& r, bool force_range)
+  : rep (force_range || ! Vdisable_range
+         ? dynamic_cast<octave_base_value *> (new ov_range<double> (r))
+         : dynamic_cast<octave_base_value *> (new octave_matrix (r.array_value ())))
+{
+  maybe_mutate ();
+}
+
+octave_value::octave_value (const octave::range<octave_int8>& r,
+                            bool force_range)
+  : rep (force_range || ! Vdisable_range
+         ? dynamic_cast<octave_base_value *> (new ov_range<octave_int8> (r))
+         : dynamic_cast<octave_base_value *> (new octave_int8_matrix (r.array_value ())))
+{
+  maybe_mutate ();
+}
+
+octave_value::octave_value (const octave::range<octave_int16>& r,
+                            bool force_range)
+  : rep (force_range || ! Vdisable_range
+         ? dynamic_cast<octave_base_value *> (new ov_range<octave_int16> (r))
+         : dynamic_cast<octave_base_value *> (new octave_int16_matrix (r.array_value ())))
+{
+  maybe_mutate ();
+}
+
+octave_value::octave_value (const octave::range<octave_int32>& r,
+                            bool force_range)
+  : rep (force_range || ! Vdisable_range
+         ? dynamic_cast<octave_base_value *> (new ov_range<octave_int32> (r))
+         : dynamic_cast<octave_base_value *> (new octave_int32_matrix (r.array_value ())))
+{
+  maybe_mutate ();
+}
+
+octave_value::octave_value (const octave::range<octave_int64>& r,
+                            bool force_range)
+  : rep (force_range || ! Vdisable_range
+         ? dynamic_cast<octave_base_value *> (new ov_range<octave_int64> (r))
+         : dynamic_cast<octave_base_value *> (new octave_int64_matrix (r.array_value ())))
+{
+  maybe_mutate ();
+}
+
+octave_value::octave_value (const octave::range<octave_uint8>& r,
+                            bool force_range)
+  : rep (force_range || ! Vdisable_range
+         ? dynamic_cast<octave_base_value *> (new ov_range<octave_uint8> (r))
+         : dynamic_cast<octave_base_value *> (new octave_uint8_matrix (r.array_value ())))
+{
+  maybe_mutate ();
+}
+
+octave_value::octave_value (const octave::range<octave_uint16>& r,
+                            bool force_range)
+  : rep (force_range || ! Vdisable_range
+         ? dynamic_cast<octave_base_value *> (new ov_range<octave_uint16> (r))
+         : dynamic_cast<octave_base_value *> (new octave_uint16_matrix (r.array_value ())))
+{
+  maybe_mutate ();
+}
+
+octave_value::octave_value (const octave::range<octave_uint32>& r,
+                            bool force_range)
+  : rep (force_range || ! Vdisable_range
+         ? dynamic_cast<octave_base_value *> (new ov_range<octave_uint32> (r))
+         : dynamic_cast<octave_base_value *> (new octave_uint32_matrix (r.array_value ())))
+{
+  maybe_mutate ();
+}
+
+octave_value::octave_value (const octave::range<octave_uint64>& r,
+                            bool force_range)
+  : rep (force_range || ! Vdisable_range
+         ? dynamic_cast<octave_base_value *> (new ov_range<octave_uint64> (r))
+         : dynamic_cast<octave_base_value *> (new octave_uint64_matrix (r.array_value ())))
 {
   maybe_mutate ();
 }
@@ -1214,7 +1326,7 @@
 %!assert (class (single (uint64 (1))), "single")
 %!assert (class (single (true)), "single")
 %!assert (class (single ("A")), "single")
-%!error (single (sparse (1)))
+%!error single (sparse (1))
 %!test
 %! x = diag ([1 3 2]);
 %! y = single (x);
@@ -1503,7 +1615,7 @@
 
       binary_op binop = op_eq_to_binary_op (op);
 
-      t_rhs = do_binary_op (binop, t, rhs);
+      t_rhs = octave::binary_op (binop, t, rhs);
     }
 
   *this = subsasgn (type, idx, t_rhs);
@@ -1535,7 +1647,7 @@
 
       if (f)
         {
-          f (*rep, octave_value_list (), *rhs.rep);
+          f (*rep, octave_value_list (), rhs.get_rep ());
           // Usually unnecessary, but may be needed (complex arrays).
           maybe_mutate ();
         }
@@ -1544,7 +1656,7 @@
 
           binary_op binop = op_eq_to_binary_op (op);
 
-          octave_value t = do_binary_op (binop, *this, rhs);
+          octave_value t = octave::binary_op (binop, *this, rhs);
 
           operator = (t);
         }
@@ -1606,7 +1718,7 @@
 
   if (rows () == test.rows () && columns () == test.columns ())
     {
-      octave_value tmp = do_binary_op (octave_value::op_eq, *this, test);
+      octave_value tmp = octave::binary_op (octave_value::op_eq, *this, test);
 
       // Empty array also means a match.
       if (tmp.is_defined ())
@@ -2081,7 +2193,16 @@
 XVALUE_EXTRACTOR (Cell, xcell_value, cell_value)
 XVALUE_EXTRACTOR (Array<std::string>, xcellstr_value, cellstr_value)
 
-XVALUE_EXTRACTOR (Range, xrange_value, range_value)
+XVALUE_EXTRACTOR (octave::range<float>, xfloat_range_value, float_range_value)
+XVALUE_EXTRACTOR (octave::range<double>, xrange_value, range_value)
+XVALUE_EXTRACTOR (octave::range<octave_int8>, xint8_range_value, int8_range_value)
+XVALUE_EXTRACTOR (octave::range<octave_int16>, xint16_range_value, int16_range_value)
+XVALUE_EXTRACTOR (octave::range<octave_int32>, xint32_range_value, int32_range_value)
+XVALUE_EXTRACTOR (octave::range<octave_int64>, xint64_range_value, int64_range_value)
+XVALUE_EXTRACTOR (octave::range<octave_uint8>, xuint8_range_value, uint8_range_value)
+XVALUE_EXTRACTOR (octave::range<octave_uint16>, xuint16_range_value, uint16_range_value)
+XVALUE_EXTRACTOR (octave::range<octave_uint32>, xuint32_range_value, uint32_range_value)
+XVALUE_EXTRACTOR (octave::range<octave_uint64>, xuint64_range_value, uint64_range_value)
 
 XVALUE_EXTRACTOR (octave_map, xmap_value, map_value)
 XVALUE_EXTRACTOR (octave_scalar_map, xscalar_map_value, scalar_map_value)
@@ -2123,6 +2244,8 @@
   octave_value retval = *this;
   if (isnull ())
     retval = octave_value (rep->empty_clone ());
+  else if (is_magic_int ())
+    retval = octave_value (rep->double_value ());
   else
     retval.maybe_economize ();
 
@@ -2139,6 +2262,13 @@
         delete rep;
       rep = rc;
     }
+  else if (is_magic_int ())
+    {
+      octave_base_value *rc = new octave_scalar (rep->double_value ());
+      if (--rep->count == 0)
+        delete rep;
+      rep = rc;
+    }
   else
     maybe_economize ();
 }
@@ -2157,457 +2287,6 @@
   return rep->write (os, block_size, output_type, skip, flt_fmt);
 }
 
-OCTAVE_NORETURN static void
-err_binary_op (const std::string& on, const std::string& tn1,
-               const std::string& tn2)
-{
-  error ("binary operator '%s' not implemented for '%s' by '%s' operations",
-         on.c_str (), tn1.c_str (), tn2.c_str ());
-}
-
-OCTAVE_NORETURN static void
-err_binary_op_conv (const std::string& on)
-{
-  error ("type conversion failed for binary operator '%s'", on.c_str ());
-}
-
-octave_value
-do_binary_op (octave::type_info& ti, octave_value::binary_op op,
-              const octave_value& v1, const octave_value& v2)
-{
-  octave_value retval;
-
-  int t1 = v1.type_id ();
-  int t2 = v2.type_id ();
-
-  if (t1 == octave_class::static_type_id ()
-      || t2 == octave_class::static_type_id ()
-      || t1 == octave_classdef::static_type_id ()
-      || t2 == octave_classdef::static_type_id ())
-    {
-      octave::type_info::binary_class_op_fcn f
-        = ti.lookup_binary_class_op (op);
-
-      if (! f)
-        err_binary_op (octave_value::binary_op_as_string (op),
-                       v1.class_name (), v2.class_name ());
-
-      retval = f (v1, v2);
-    }
-  else
-    {
-      // FIXME: we need to handle overloading operators for built-in
-      // classes (double, char, int8, etc.)
-
-      octave::type_info::binary_op_fcn f
-        = ti.lookup_binary_op (op, t1, t2);
-
-      if (f)
-        retval = f (*v1.rep, *v2.rep);
-      else
-        {
-          octave_value tv1;
-          octave_base_value::type_conv_info cf1
-            = v1.numeric_conversion_function ();
-
-          octave_value tv2;
-          octave_base_value::type_conv_info cf2
-            = v2.numeric_conversion_function ();
-
-          // Try biased (one-sided) conversions first.
-          if (cf2.type_id () >= 0
-              && ti.lookup_binary_op (op, t1, cf2.type_id ()))
-            cf1 = nullptr;
-          else if (cf1.type_id () >= 0
-                   && ti.lookup_binary_op (op, cf1.type_id (), t2))
-            cf2 = nullptr;
-
-          if (cf1)
-            {
-              octave_base_value *tmp = cf1 (*v1.rep);
-
-              if (! tmp)
-                err_binary_op_conv (octave_value::binary_op_as_string (op));
-
-              tv1 = octave_value (tmp);
-              t1 = tv1.type_id ();
-            }
-          else
-            tv1 = v1;
-
-          if (cf2)
-            {
-              octave_base_value *tmp = cf2 (*v2.rep);
-
-              if (! tmp)
-                err_binary_op_conv (octave_value::binary_op_as_string (op));
-
-              tv2 = octave_value (tmp);
-              t2 = tv2.type_id ();
-            }
-          else
-            tv2 = v2;
-
-          if (cf1 || cf2)
-            {
-              retval = do_binary_op (op, tv1, tv2);
-            }
-          else
-            {
-              //demote double -> single and try again
-              cf1 = tv1.numeric_demotion_function ();
-
-              cf2 = tv2.numeric_demotion_function ();
-
-              // Try biased (one-sided) conversions first.
-              if (cf2.type_id () >= 0
-                  && ti.lookup_binary_op (op, t1, cf2.type_id ()))
-                cf1 = nullptr;
-              else if (cf1.type_id () >= 0
-                       && ti.lookup_binary_op (op, cf1.type_id (), t2))
-                cf2 = nullptr;
-
-              if (cf1)
-                {
-                  octave_base_value *tmp = cf1 (*tv1.rep);
-
-                  if (! tmp)
-                    err_binary_op_conv (octave_value::binary_op_as_string (op));
-
-                  tv1 = octave_value (tmp);
-                  t1 = tv1.type_id ();
-                }
-
-              if (cf2)
-                {
-                  octave_base_value *tmp = cf2 (*tv2.rep);
-
-                  if (! tmp)
-                    err_binary_op_conv (octave_value::binary_op_as_string (op));
-
-                  tv2 = octave_value (tmp);
-                  t2 = tv2.type_id ();
-                }
-
-              if (! cf1 && ! cf2)
-                err_binary_op (octave_value::binary_op_as_string (op),
-                               v1.type_name (), v2.type_name ());
-
-              f = ti.lookup_binary_op (op, t1, t2);
-
-              if (! f)
-                err_binary_op (octave_value::binary_op_as_string (op),
-                               v1.type_name (), v2.type_name ());
-
-              retval = f (*tv1.rep, *tv2.rep);
-            }
-        }
-    }
-
-  return retval;
-}
-
-octave_value
-do_binary_op (octave_value::binary_op op,
-              const octave_value& v1, const octave_value& v2)
-{
-  octave::type_info& ti = octave::__get_type_info__ ("do_binary_op");
-
-  return do_binary_op (ti, op, v1, v2);
-}
-
-static octave_value
-decompose_binary_op (octave::type_info& ti,
-                     octave_value::compound_binary_op op,
-                     const octave_value& v1, const octave_value& v2)
-{
-  switch (op)
-    {
-    case octave_value::op_trans_mul:
-      return do_binary_op (octave_value::op_mul,
-                           do_unary_op (octave_value::op_transpose, v1), v2);
-
-    case octave_value::op_mul_trans:
-      return do_binary_op (ti, octave_value::op_mul,
-                           v1, do_unary_op (octave_value::op_transpose, v2));
-
-    case octave_value::op_herm_mul:
-      return do_binary_op (ti, octave_value::op_mul,
-                           do_unary_op (octave_value::op_hermitian, v1), v2);
-
-    case octave_value::op_mul_herm:
-      return do_binary_op (ti, octave_value::op_mul,
-                           v1, do_unary_op (octave_value::op_hermitian, v2));
-
-    case octave_value::op_trans_ldiv:
-      return do_binary_op (ti, octave_value::op_ldiv,
-                           do_unary_op (octave_value::op_transpose, v1), v2);
-
-    case octave_value::op_herm_ldiv:
-      return do_binary_op (ti, octave_value::op_ldiv,
-                           do_unary_op (octave_value::op_hermitian, v1), v2);
-
-    case octave_value::op_el_not_and:
-      return do_binary_op (ti, octave_value::op_el_and,
-                           do_unary_op (octave_value::op_not, v1), v2);
-
-    case octave_value::op_el_not_or:
-      return do_binary_op (ti, octave_value::op_el_or,
-                           do_unary_op (octave_value::op_not, v1), v2);
-
-    case octave_value::op_el_and_not:
-      return do_binary_op (ti, octave_value::op_el_and,
-                           v1, do_unary_op (octave_value::op_not, v2));
-
-    case octave_value::op_el_or_not:
-      return do_binary_op (ti, octave_value::op_el_or,
-                           v1, do_unary_op (octave_value::op_not, v2));
-
-    default:
-      error ("invalid compound operator");
-    }
-}
-
-octave_value
-do_binary_op (octave::type_info& ti, octave_value::compound_binary_op op,
-              const octave_value& v1, const octave_value& v2)
-{
-  octave_value retval;
-
-  int t1 = v1.type_id ();
-  int t2 = v2.type_id ();
-
-  if (t1 == octave_class::static_type_id ()
-      || t2 == octave_class::static_type_id ()
-      || t1 == octave_classdef::static_type_id ()
-      || t2 == octave_classdef::static_type_id ())
-    {
-      octave::type_info::binary_class_op_fcn f = ti.lookup_binary_class_op (op);
-
-      if (f)
-        retval = f (v1, v2);
-      else
-        retval = decompose_binary_op (ti, op, v1, v2);
-    }
-  else
-    {
-      octave::type_info::binary_op_fcn f = ti.lookup_binary_op (op, t1, t2);
-
-      if (f)
-        retval = f (*v1.rep, *v2.rep);
-      else
-        retval = decompose_binary_op (ti, op, v1, v2);
-    }
-
-  return retval;
-}
-
-octave_value
-do_binary_op (octave_value::compound_binary_op op,
-              const octave_value& v1, const octave_value& v2)
-{
-  octave::type_info& ti = octave::__get_type_info__ ("do_binary_op");
-
-  return do_binary_op (ti, op, v1, v2);
-}
-
-OCTAVE_NORETURN static void
-err_cat_op (const std::string& tn1, const std::string& tn2)
-{
-  error ("concatenation operator not implemented for '%s' by '%s' operations",
-         tn1.c_str (), tn2.c_str ());
-}
-
-OCTAVE_NORETURN static void
-err_cat_op_conv (void)
-{
-  error ("type conversion failed for concatenation operator");
-}
-
-octave_value
-do_cat_op (octave::type_info& ti, const octave_value& v1,
-           const octave_value& v2, const Array<octave_idx_type>& ra_idx)
-{
-  octave_value retval;
-
-  // Can't rapid return for concatenation with an empty object here as
-  // something like cat(1,[],single([]) must return the correct type.
-
-  int t1 = v1.type_id ();
-  int t2 = v2.type_id ();
-
-  octave::type_info::cat_op_fcn f = ti.lookup_cat_op (t1, t2);
-
-  if (f)
-    retval = f (*v1.rep, *v2.rep, ra_idx);
-  else
-    {
-      octave_value tv1;
-      octave_base_value::type_conv_info cf1 = v1.numeric_conversion_function ();
-
-      octave_value tv2;
-      octave_base_value::type_conv_info cf2 = v2.numeric_conversion_function ();
-
-      // Try biased (one-sided) conversions first.
-      if (cf2.type_id () >= 0 && ti.lookup_cat_op (t1, cf2.type_id ()))
-        cf1 = nullptr;
-      else if (cf1.type_id () >= 0 && ti.lookup_cat_op (cf1.type_id (), t2))
-        cf2 = nullptr;
-
-      if (cf1)
-        {
-          octave_base_value *tmp = cf1 (*v1.rep);
-
-          if (! tmp)
-            err_cat_op_conv ();
-
-          tv1 = octave_value (tmp);
-          t1 = tv1.type_id ();
-        }
-      else
-        tv1 = v1;
-
-      if (cf2)
-        {
-          octave_base_value *tmp = cf2 (*v2.rep);
-
-          if (! tmp)
-            err_cat_op_conv ();
-
-          tv2 = octave_value (tmp);
-          t2 = tv2.type_id ();
-        }
-      else
-        tv2 = v2;
-
-      if (! cf1 && ! cf2)
-        err_cat_op (v1.type_name (), v2.type_name ());
-
-      retval = do_cat_op (ti, tv1, tv2, ra_idx);
-    }
-
-  return retval;
-}
-
-octave_value
-do_cat_op (const octave_value& v1, const octave_value& v2,
-           const Array<octave_idx_type>& ra_idx)
-{
-  octave::type_info& ti = octave::__get_type_info__ ("do_cat_op");
-
-  return do_cat_op (ti, v1, v2, ra_idx);
-}
-
-octave_value
-do_colon_op (const octave_value& base, const octave_value& increment,
-             const octave_value& limit, bool is_for_cmd_expr)
-{
-  octave_value retval;
-
-  if (base.isobject () || increment.isobject () || limit.isobject ())
-    {
-      std::string dispatch_type;
-
-      if (base.isobject ())
-        dispatch_type = base.class_name ();
-      else if (increment.is_defined () && increment.isobject ())
-        dispatch_type = increment.class_name ();
-      else
-        dispatch_type = limit.class_name ();
-
-      octave::symbol_table& symtab = octave::__get_symbol_table__ ("do_colon_op");
-
-      octave_value meth = symtab.find_method ("colon", dispatch_type);
-
-      if (! meth.is_defined ())
-        error ("colon method not defined for %s class", dispatch_type.c_str ());
-
-      octave_value_list args;
-
-      if (increment.is_defined ())
-        {
-          args(2) = limit;
-          args(1) = increment;
-        }
-      else
-        args(1) = limit;
-
-      args(0) = base;
-
-      octave_value_list tmp = octave::feval (meth.function_value (), args, 1);
-
-      if (tmp.length () > 0)
-        retval = tmp(0);
-    }
-  else
-    {
-      bool result_is_str = (base.is_string () && limit.is_string ());
-      bool dq_str = (base.is_dq_string () || limit.is_dq_string ());
-
-      if (base.numel () > 1 || limit.numel () > 1
-          || (increment.is_defined () && increment.numel () > 1))
-        warning_with_id ("Octave:colon-nonscalar-argument",
-                         "colon arguments should be scalars");
-
-      if (base.iscomplex () || limit.iscomplex ()
-          || (increment.is_defined () && increment.iscomplex ()))
-        warning_with_id ("Octave:colon-complex-argument",
-                         "imaginary part of complex colon arguments is ignored");
-
-      Matrix m_base, m_limit, m_increment;
-
-      try
-        {
-          m_base = base.matrix_value (true);
-        }
-      catch (octave::execution_exception& e)
-        {
-          error (e, "invalid base value in colon expression");
-        }
-
-      try
-        {
-          m_limit = limit.matrix_value (true);
-        }
-      catch (octave::execution_exception& e)
-        {
-          error (e, "invalid limit value in colon expression");
-        }
-
-      try
-        {
-          m_increment = (increment.is_defined ()
-                         ? increment.matrix_value (true)
-                         : Matrix (1, 1, 1.0));
-        }
-      catch (octave::execution_exception& e)
-        {
-          error (e, "invalid increment value in colon expression");
-        }
-
-      bool base_empty = m_base.isempty ();
-      bool limit_empty = m_limit.isempty ();
-      bool increment_empty = m_increment.isempty ();
-
-      if (base_empty || limit_empty || increment_empty)
-        retval = Range ();
-      else
-        {
-          Range r (m_base(0), m_limit(0), m_increment(0));
-
-          // For compatibility with Matlab, don't allow the range used in
-          // a FOR loop expression to be converted to a Matrix.
-
-          retval = octave_value (r, is_for_cmd_expr);
-
-          if (result_is_str)
-            retval = (retval.convert_to_str (false, true, dq_str ? '"' : '\''));
-        }
-    }
-
-  return retval;
-}
-
 void
 octave_value::print_info (std::ostream& os, const std::string& prefix) const
 {
@@ -2618,75 +2297,72 @@
   rep->print_info (os, prefix + ' ');
 }
 
-OCTAVE_NORETURN static void
-err_unary_op (const std::string& on, const std::string& tn)
-{
-  error ("unary operator '%s' not implemented for '%s' operands",
-         on.c_str (), tn.c_str ());
-}
-
-OCTAVE_NORETURN static void
-err_unary_op_conv (const std::string& on)
+void *
+octave_value::mex_get_data (mxClassID class_id, mxComplexity complexity) const
 {
-  error ("type conversion failed for unary operator '%s'", on.c_str ());
-}
-
-octave_value
-do_unary_op (octave::type_info& ti, octave_value::unary_op op,
-             const octave_value& v)
-{
-  octave_value retval;
-
-  int t = v.type_id ();
-
-  if (t == octave_class::static_type_id ()
-      || t == octave_classdef::static_type_id ())
-    {
-      octave::type_info::unary_class_op_fcn f = ti.lookup_unary_class_op (op);
-
-      if (! f)
-        err_unary_op (octave_value::unary_op_as_string (op), v.class_name ());
-
-      retval = f (v);
-    }
-  else
+  // If class_id is set to mxUNKNOWN_CLASS, return data for any type.
+  // Otherwise, require that REP matches the requested type and
+  // complexity.
+
+  if (class_id != mxUNKNOWN_CLASS)
     {
-      // FIXME: we need to handle overloading operators for built-in
-      // classes (double, char, int8, etc.)
-
-      octave::type_info::unary_op_fcn f = ti.lookup_unary_op (op, t);
-
-      if (f)
-        retval = f (*v.rep);
-      else
+      bool type_ok = false;
+
+      switch (class_id)
         {
-          octave_value tv;
-          octave_base_value::type_conv_fcn cf
-            = v.numeric_conversion_function ();
-
-          if (! cf)
-            err_unary_op (octave_value::unary_op_as_string (op),
-                          v.type_name ());
-
-          octave_base_value *tmp = cf (*v.rep);
-
-          if (! tmp)
-            err_unary_op_conv (octave_value::unary_op_as_string (op));
-
-          tv = octave_value (tmp);
-          retval = do_unary_op (op, tv);
+        case mxDOUBLE_CLASS:
+          type_ok = is_double_type ();
+          break;
+
+        case mxSINGLE_CLASS:
+          type_ok = is_single_type ();
+          break;
+
+        case mxINT8_CLASS:
+          type_ok = is_int8_type ();
+          break;
+
+        case mxINT16_CLASS:
+          type_ok = is_int16_type ();
+          break;
+
+        case mxINT32_CLASS:
+          type_ok = is_int32_type ();
+          break;
+
+        case mxINT64_CLASS:
+          type_ok = is_int64_type ();
+          break;
+
+        case mxUINT8_CLASS:
+          type_ok = is_uint8_type ();
+          break;
+
+        case mxUINT16_CLASS:
+          type_ok = is_uint16_type ();
+          break;
+
+        case mxUINT32_CLASS:
+          type_ok = is_uint32_type ();
+          break;
+
+        case mxUINT64_CLASS:
+          type_ok = is_uint64_type ();
+          break;
+
+        default:
+          // We only expect to see numeric types explicitly requested.
+          error ("mex_get_data: unexpected type requested");
         }
+
+      if (! type_ok)
+        error ("mex_get_data: type mismatch");
+
+      if (complexity == mxCOMPLEX && ! iscomplex ())
+        error ("mex_get_data: objectis not complex as requested");
     }
 
-  return retval;
-}
-
-octave_value
-do_unary_op (octave_value::unary_op op, const octave_value& v)
-{
-  octave::type_info& ti = octave::__get_type_info__ ("do_unary_op");
-
-  return do_unary_op (ti, op, v);
+  return rep->mex_get_data ();
 }
 
 OCTAVE_NORETURN static void
@@ -2697,8 +2373,15 @@
          op.c_str (), tn.c_str ());
 }
 
+OCTAVE_NORETURN static void
+err_unary_op (const std::string& on, const std::string& tn)
+{
+  error ("unary operator '%s' not implemented for '%s' operands",
+         on.c_str (), tn.c_str ());
+}
+
 octave_value&
-octave_value::do_non_const_unary_op (unary_op op)
+octave_value::non_const_unary_op (unary_op op)
 {
   if (op == op_incr || op == op_decr)
     {
@@ -2716,8 +2399,7 @@
       // Genuine.
       int t = type_id ();
 
-      octave::type_info& ti
-        = octave::__get_type_info__ ("do_non_const_unary_op");
+      octave::type_info& ti = octave::__get_type_info__ ("non_const_unary_op");
 
       octave::type_info::non_const_unary_op_fcn f
         = ti.lookup_non_const_unary_op (op, t);
@@ -2781,7 +2463,7 @@
       if (rep->count == 1)
         {
           octave::type_info& ti
-            = octave::__get_type_info__ ("do_non_const_unary_op");
+            = octave::__get_type_info__ ("non_const_unary_op");
 
           f = ti.lookup_non_const_unary_op (op, t);
         }
@@ -2789,18 +2471,18 @@
       if (f)
         f (*rep);
       else
-        *this = do_unary_op (op, *this);
+        *this = octave::unary_op (op, *this);
     }
 
   return *this;
 }
 
 octave_value&
-octave_value::do_non_const_unary_op (unary_op op, const std::string& type,
-                                     const std::list<octave_value_list>& idx)
+octave_value::non_const_unary_op (unary_op op, const std::string& type,
+                                  const std::list<octave_value_list>& idx)
 {
   if (idx.empty ())
-    do_non_const_unary_op (op);
+    non_const_unary_op (op);
   else
     {
       // FIXME: only do the following stuff if we can't find a
@@ -2910,6 +2592,585 @@
     return octave_value (rhs.empty_clone ());
 }
 
+namespace octave
+{
+  OCTAVE_NORETURN static void
+  err_binary_op (const std::string& on, const std::string& tn1,
+                 const std::string& tn2)
+  {
+    error ("binary operator '%s' not implemented for '%s' by '%s' operations",
+           on.c_str (), tn1.c_str (), tn2.c_str ());
+  }
+
+  OCTAVE_NORETURN static void
+  err_binary_op_conv (const std::string& on)
+  {
+    error ("type conversion failed for binary operator '%s'", on.c_str ());
+  }
+
+  octave_value
+  binary_op (type_info& ti, octave_value::binary_op op,
+             const octave_value& v1, const octave_value& v2)
+  {
+    octave_value retval;
+
+    int t1 = v1.type_id ();
+    int t2 = v2.type_id ();
+
+    if (t1 == octave_class::static_type_id ()
+        || t2 == octave_class::static_type_id ()
+        || t1 == octave_classdef::static_type_id ()
+        || t2 == octave_classdef::static_type_id ())
+      {
+        type_info::binary_class_op_fcn f = ti.lookup_binary_class_op (op);
+
+        if (! f)
+          err_binary_op (octave_value::binary_op_as_string (op),
+                         v1.class_name (), v2.class_name ());
+
+        retval = f (v1, v2);
+      }
+    else
+      {
+        // FIXME: we need to handle overloading operators for built-in
+        // classes (double, char, int8, etc.)
+
+        type_info::binary_op_fcn f
+          = ti.lookup_binary_op (op, t1, t2);
+
+        if (f)
+          retval = f (v1.get_rep (), v2.get_rep ());
+        else
+          {
+            octave_value tv1;
+            octave_base_value::type_conv_info cf1
+              = v1.numeric_conversion_function ();
+
+            octave_value tv2;
+            octave_base_value::type_conv_info cf2
+              = v2.numeric_conversion_function ();
+
+            // Try biased (one-sided) conversions first.
+            if (cf2.type_id () >= 0
+                && ti.lookup_binary_op (op, t1, cf2.type_id ()))
+              cf1 = nullptr;
+            else if (cf1.type_id () >= 0
+                     && ti.lookup_binary_op (op, cf1.type_id (), t2))
+              cf2 = nullptr;
+
+            if (cf1)
+              {
+                octave_base_value *tmp = cf1 (v1.get_rep ());
+
+                if (! tmp)
+                  err_binary_op_conv (octave_value::binary_op_as_string (op));
+
+                tv1 = octave_value (tmp);
+                t1 = tv1.type_id ();
+              }
+            else
+              tv1 = v1;
+
+            if (cf2)
+              {
+                octave_base_value *tmp = cf2 (v2.get_rep ());
+
+                if (! tmp)
+                  err_binary_op_conv (octave_value::binary_op_as_string (op));
+
+                tv2 = octave_value (tmp);
+                t2 = tv2.type_id ();
+              }
+            else
+              tv2 = v2;
+
+            if (cf1 || cf2)
+              {
+                retval = binary_op (op, tv1, tv2);
+              }
+            else
+              {
+                //demote double -> single and try again
+                cf1 = tv1.numeric_demotion_function ();
+
+                cf2 = tv2.numeric_demotion_function ();
+
+                // Try biased (one-sided) conversions first.
+                if (cf2.type_id () >= 0
+                    && ti.lookup_binary_op (op, t1, cf2.type_id ()))
+                  cf1 = nullptr;
+                else if (cf1.type_id () >= 0
+                         && ti.lookup_binary_op (op, cf1.type_id (), t2))
+                  cf2 = nullptr;
+
+                if (cf1)
+                  {
+                    octave_base_value *tmp = cf1 (tv1.get_rep ());
+
+                    if (! tmp)
+                      err_binary_op_conv (octave_value::binary_op_as_string (op));
+
+                    tv1 = octave_value (tmp);
+                    t1 = tv1.type_id ();
+                  }
+
+                if (cf2)
+                  {
+                    octave_base_value *tmp = cf2 (tv2.get_rep ());
+
+                    if (! tmp)
+                      err_binary_op_conv (octave_value::binary_op_as_string (op));
+
+                    tv2 = octave_value (tmp);
+                    t2 = tv2.type_id ();
+                  }
+
+                if (! cf1 && ! cf2)
+                  err_binary_op (octave_value::binary_op_as_string (op),
+                                 v1.type_name (), v2.type_name ());
+
+                f = ti.lookup_binary_op (op, t1, t2);
+
+                if (! f)
+                  err_binary_op (octave_value::binary_op_as_string (op),
+                                 v1.type_name (), v2.type_name ());
+
+                retval = f (tv1.get_rep (), tv2.get_rep ());
+              }
+          }
+      }
+
+    return retval;
+  }
+
+  octave_value
+  binary_op (octave_value::binary_op op, const octave_value& v1,
+             const octave_value& v2)
+  {
+    type_info& ti = __get_type_info__ ("binary_op");
+
+    return binary_op (ti, op, v1, v2);
+  }
+
+  static octave_value
+  decompose_binary_op (type_info& ti, octave_value::compound_binary_op op,
+                       const octave_value& v1, const octave_value& v2)
+  {
+    switch (op)
+      {
+      case octave_value::op_trans_mul:
+        return binary_op (octave_value::op_mul,
+                          unary_op (octave_value::op_transpose, v1), v2);
+
+      case octave_value::op_mul_trans:
+        return binary_op (ti, octave_value::op_mul,
+                          v1, unary_op (octave_value::op_transpose, v2));
+
+      case octave_value::op_herm_mul:
+        return binary_op (ti, octave_value::op_mul,
+                          unary_op (octave_value::op_hermitian, v1), v2);
+
+      case octave_value::op_mul_herm:
+        return binary_op (ti, octave_value::op_mul,
+                          v1, unary_op (octave_value::op_hermitian, v2));
+
+      case octave_value::op_trans_ldiv:
+        return binary_op (ti, octave_value::op_ldiv,
+                          unary_op (octave_value::op_transpose, v1), v2);
+
+      case octave_value::op_herm_ldiv:
+        return binary_op (ti, octave_value::op_ldiv,
+                          unary_op (octave_value::op_hermitian, v1), v2);
+
+      case octave_value::op_el_not_and:
+        return binary_op (ti, octave_value::op_el_and,
+                          unary_op (octave_value::op_not, v1), v2);
+
+      case octave_value::op_el_not_or:
+        return binary_op (ti, octave_value::op_el_or,
+                          unary_op (octave_value::op_not, v1), v2);
+
+      case octave_value::op_el_and_not:
+        return binary_op (ti, octave_value::op_el_and,
+                          v1, unary_op (octave_value::op_not, v2));
+
+      case octave_value::op_el_or_not:
+        return binary_op (ti, octave_value::op_el_or,
+                          v1, unary_op (octave_value::op_not, v2));
+
+      default:
+        error ("invalid compound operator");
+      }
+  }
+
+  octave_value
+  binary_op (type_info& ti, octave_value::compound_binary_op op,
+             const octave_value& v1, const octave_value& v2)
+  {
+    octave_value retval;
+
+    int t1 = v1.type_id ();
+    int t2 = v2.type_id ();
+
+    if (t1 == octave_class::static_type_id ()
+        || t2 == octave_class::static_type_id ()
+        || t1 == octave_classdef::static_type_id ()
+        || t2 == octave_classdef::static_type_id ())
+      {
+        type_info::binary_class_op_fcn f = ti.lookup_binary_class_op (op);
+
+        if (f)
+          retval = f (v1, v2);
+        else
+          retval = decompose_binary_op (ti, op, v1, v2);
+      }
+    else
+      {
+        type_info::binary_op_fcn f = ti.lookup_binary_op (op, t1, t2);
+
+        if (f)
+          retval = f (v1.get_rep (), v2.get_rep ());
+        else
+          retval = decompose_binary_op (ti, op, v1, v2);
+      }
+
+    return retval;
+  }
+
+  octave_value
+  binary_op (octave_value::compound_binary_op op,
+             const octave_value& v1, const octave_value& v2)
+  {
+    type_info& ti = __get_type_info__ ("binary_op");
+
+    return binary_op (ti, op, v1, v2);
+  }
+
+  OCTAVE_NORETURN static void
+  err_cat_op (const std::string& tn1, const std::string& tn2)
+  {
+    error ("concatenation operator not implemented for '%s' by '%s' operations",
+           tn1.c_str (), tn2.c_str ());
+  }
+
+  OCTAVE_NORETURN static void
+  err_cat_op_conv (void)
+  {
+    error ("type conversion failed for concatenation operator");
+  }
+
+  octave_value
+  cat_op (type_info& ti, const octave_value& v1,
+          const octave_value& v2, const Array<octave_idx_type>& ra_idx)
+  {
+    octave_value retval;
+
+    // Can't rapid return for concatenation with an empty object here as
+    // something like cat(1,[],single([]) must return the correct type.
+
+    int t1 = v1.type_id ();
+    int t2 = v2.type_id ();
+
+    type_info::cat_op_fcn f = ti.lookup_cat_op (t1, t2);
+
+    if (f)
+      retval = f (v1.get_rep (), v2.get_rep (), ra_idx);
+    else
+      {
+        octave_value tv1;
+        octave_base_value::type_conv_info cf1 = v1.numeric_conversion_function ();
+
+        octave_value tv2;
+        octave_base_value::type_conv_info cf2 = v2.numeric_conversion_function ();
+
+        // Try biased (one-sided) conversions first.
+        if (cf2.type_id () >= 0 && ti.lookup_cat_op (t1, cf2.type_id ()))
+          cf1 = nullptr;
+        else if (cf1.type_id () >= 0 && ti.lookup_cat_op (cf1.type_id (), t2))
+          cf2 = nullptr;
+
+        if (cf1)
+          {
+            octave_base_value *tmp = cf1 (v1.get_rep ());
+
+            if (! tmp)
+              err_cat_op_conv ();
+
+            tv1 = octave_value (tmp);
+            t1 = tv1.type_id ();
+          }
+        else
+          tv1 = v1;
+
+        if (cf2)
+          {
+            octave_base_value *tmp = cf2 (v2.get_rep ());
+
+            if (! tmp)
+              err_cat_op_conv ();
+
+            tv2 = octave_value (tmp);
+            t2 = tv2.type_id ();
+          }
+        else
+          tv2 = v2;
+
+        if (! cf1 && ! cf2)
+          err_cat_op (v1.type_name (), v2.type_name ());
+
+        retval = cat_op (ti, tv1, tv2, ra_idx);
+      }
+
+    return retval;
+  }
+
+  octave_value
+  cat_op (const octave_value& v1, const octave_value& v2,
+          const Array<octave_idx_type>& ra_idx)
+  {
+    type_info& ti = __get_type_info__ ("cat_op");
+
+    return cat_op (ti, v1, v2, ra_idx);
+  }
+
+  // Unless the colon operator is used with a class or classdef object,
+  // then all arguments must be the same type or mixed with double
+  // values.
+
+  static builtin_type_t
+  get_colon_op_type (builtin_type_t op1_type, builtin_type_t op2_type)
+  {
+    if (op1_type == op2_type)
+      return op1_type;
+
+    if (op1_type == btyp_double)
+      return op2_type;
+
+    if (op2_type == btyp_double)
+      return op1_type;
+
+    return btyp_unknown;
+  }
+
+  static builtin_type_t
+  get_colon_op_type (const octave_value& base, const octave_value& increment,
+                     const octave_value& limit)
+  {
+    builtin_type_t typ
+      = get_colon_op_type (base.builtin_type (), increment.builtin_type ());
+
+    if (typ == btyp_unknown)
+      return typ;
+
+    return get_colon_op_type (typ, limit.builtin_type ());
+  }
+
+  template <typename T>
+  octave_value
+  make_range (const octave_value& base, const octave_value& increment,
+              const octave_value& limit, bool for_cmd_expr)
+  {
+    if (base.isempty () || increment.isempty () || limit.isempty ())
+      return octave_value (range<T> (), for_cmd_expr);
+
+    T base_val = octave_value_extract<T> (base);
+    T increment_val = octave_value_extract<T> (increment);
+    T limit_val = octave_value_extract<T> (limit);
+
+    range<T> r (base_val, increment_val, limit_val);
+
+    return octave_value (r, for_cmd_expr);
+  }
+
+  template <>
+  octave_value
+  make_range<char> (const octave_value& base, const octave_value& increment,
+                    const octave_value& limit, bool for_cmd_expr)
+  {
+    octave_value retval;
+
+    bool dq_str = (base.is_dq_string () || increment.is_dq_string ()
+                   || limit.is_dq_string ());
+
+    char type = dq_str ? '"' : '\'';
+
+    if (base.isempty () || increment.isempty () || limit.isempty ())
+      retval = octave_value ("", type);
+    else
+      {
+        Matrix mtx_base = base.matrix_value (true);
+        Matrix mtx_increment = increment.matrix_value (true);
+        Matrix mtx_limit = limit.matrix_value (true);
+
+        range<double> tmp (mtx_base(0), mtx_increment(0), mtx_limit(0));
+
+        retval = octave_value (tmp, for_cmd_expr);
+      }
+
+    return retval.convert_to_str (false, true, type);
+  }
+
+  octave_value
+  colon_op (const octave_value& base, const octave_value& increment_arg,
+            const octave_value& limit, bool is_for_cmd_expr)
+  {
+    if (base.isobject () || increment_arg.isobject () || limit.isobject ())
+      {
+        octave_value_list tmp1;
+
+        if (increment_arg.is_defined ())
+          {
+            tmp1(2) = limit;
+            tmp1(1) = increment_arg;
+            tmp1(0) = base;
+          }
+        else
+          {
+            tmp1(1) = limit;
+            tmp1(0) = base;
+          }
+
+        interpreter& interp = __get_interpreter__ ("colon_op");
+
+        symbol_table& symtab = interp.get_symbol_table ();
+
+        octave_value fcn = symtab.find_function ("colon", tmp1);
+
+        if (fcn.is_defined ())
+          {
+            octave_value_list tmp2 = interp.feval (fcn, tmp1, 1);
+
+            return tmp2 (0);
+          }
+      }
+
+    octave_value increment
+      = increment_arg.is_defined () ? increment_arg : octave_value (1.0);
+
+    if (base.numel () > 1 || limit.numel () > 1 || increment.numel () > 1)
+      warning_with_id ("Octave:colon-nonscalar-argument",
+                       "colon arguments should be scalars");
+
+    if (base.iscomplex () || limit.iscomplex () || increment.iscomplex ())
+      warning_with_id ("Octave:colon-complex-argument",
+                       "imaginary part of complex colon arguments is ignored");
+
+    // FIXME: is there a better way to do this job, maybe using type traits?
+
+    builtin_type_t type_id = get_colon_op_type (base, increment, limit);
+
+    // For compatibility with Matlab, don't allow the range used in
+    // a FOR loop expression to be converted to a Matrix.
+
+    switch (type_id)
+      {
+      case btyp_double:
+      case btyp_complex:
+        return make_range<double> (base, increment, limit, is_for_cmd_expr);
+
+      case btyp_float:
+      case btyp_float_complex:
+        return make_range<float> (base, increment, limit, is_for_cmd_expr);
+
+      case btyp_int8:
+        return make_range<octave_int8> (base, increment, limit, is_for_cmd_expr);
+
+      case btyp_int16:
+        return make_range<octave_int16> (base, increment, limit, is_for_cmd_expr);
+
+      case btyp_int32:
+        return make_range<octave_int32> (base, increment, limit, is_for_cmd_expr);
+
+      case btyp_int64:
+        return make_range<octave_int64> (base, increment, limit, is_for_cmd_expr);
+
+      case btyp_uint8:
+        return make_range<octave_uint8> (base, increment, limit, is_for_cmd_expr);
+
+      case btyp_uint16:
+        return make_range<octave_uint16> (base, increment, limit, is_for_cmd_expr);
+
+      case btyp_uint32:
+        return make_range<octave_uint32> (base, increment, limit, is_for_cmd_expr);
+
+      case btyp_uint64:
+        return make_range<octave_uint64> (base, increment, limit, is_for_cmd_expr);
+
+      case btyp_char:
+        return make_range<char> (base, increment, limit, is_for_cmd_expr);
+
+      default:
+        error ("invalid types found in range expression");
+      }
+
+    return octave_value ();
+  }
+
+  OCTAVE_NORETURN static void
+  err_unary_op_conv (const std::string& on)
+  {
+    error ("type conversion failed for unary operator '%s'", on.c_str ());
+  }
+
+  octave_value
+  unary_op (type_info& ti, octave_value::unary_op op,
+            const octave_value& v)
+  {
+    octave_value retval;
+
+    int t = v.type_id ();
+
+    if (t == octave_class::static_type_id ()
+        || t == octave_classdef::static_type_id ())
+      {
+        type_info::unary_class_op_fcn f = ti.lookup_unary_class_op (op);
+
+        if (! f)
+          err_unary_op (octave_value::unary_op_as_string (op), v.class_name ());
+
+        retval = f (v);
+      }
+    else
+      {
+        // FIXME: we need to handle overloading operators for built-in
+        // classes (double, char, int8, etc.)
+
+        type_info::unary_op_fcn f = ti.lookup_unary_op (op, t);
+
+        if (f)
+          retval = f (v.get_rep ());
+        else
+          {
+            octave_value tv;
+            octave_base_value::type_conv_fcn cf
+              = v.numeric_conversion_function ();
+
+            if (! cf)
+              err_unary_op (octave_value::unary_op_as_string (op),
+                            v.type_name ());
+
+            octave_base_value *tmp = cf (v.get_rep ());
+
+            if (! tmp)
+              err_unary_op_conv (octave_value::unary_op_as_string (op));
+
+            tv = octave_value (tmp);
+            retval = unary_op (op, tv);
+          }
+      }
+
+    return retval;
+  }
+
+  octave_value
+  unary_op (octave_value::unary_op op, const octave_value& v)
+  {
+    type_info& ti = __get_type_info__ ("unary_op");
+
+    return unary_op (ti, op, v);
+  }
+}
+
 void
 install_types (octave::type_info& ti)
 {
@@ -2921,7 +3182,16 @@
   octave_diag_matrix::register_type (ti);
   octave_complex_matrix::register_type (ti);
   octave_complex_diag_matrix::register_type (ti);
-  octave_range::register_type (ti);
+  ov_range<float>::register_type (ti);
+  ov_range<double>::register_type (ti);
+  ov_range<octave_int8>::register_type (ti);
+  ov_range<octave_int16>::register_type (ti);
+  ov_range<octave_int32>::register_type (ti);
+  ov_range<octave_int64>::register_type (ti);
+  ov_range<octave_uint8>::register_type (ti);
+  ov_range<octave_uint16>::register_type (ti);
+  ov_range<octave_uint32>::register_type (ti);
+  ov_range<octave_uint64>::register_type (ti);
   octave_bool::register_type (ti);
   octave_bool_matrix::register_type (ti);
   octave_char_matrix_str::register_type (ti);
@@ -2961,6 +3231,8 @@
   octave_float_complex_matrix::register_type (ti);
   octave_float_complex_diag_matrix::register_type (ti);
   octave_perm_matrix::register_type (ti);
+  octave_magic_int::register_type (ti);
+  octave_magic_uint::register_type (ti);
   octave_null_matrix::register_type (ti);
   octave_null_str::register_type (ti);
   octave_null_sq_str::register_type (ti);
--- a/libinterp/octave-value/ov.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/octave-value/ov.h	Thu Nov 19 13:08:00 2020 -0800
@@ -59,20 +59,11 @@
 class octave_fcn_handle;
 class octave_value_list;
 
+#include "mxtypes.h"
+
 #include "oct-stream.h"
 #include "ov-base.h"
 
-// Forward declarations of friend functions that have default arguments.
-
-OCTINTERP_API octave_value do_colon_op (const octave_value& base,
-                                        const octave_value& limit,
-                                        bool is_for_cmd_expr = false);
-
-OCTINTERP_API octave_value do_colon_op (const octave_value& base,
-                                        const octave_value& increment,
-                                        const octave_value& limit,
-                                        bool is_for_cmd_expr = false);
-
 class
 OCTINTERP_API
 octave_value
@@ -282,8 +273,21 @@
                 bool zero_based = false, bool cache_index = false);
   octave_value (const Array<std::string>& cellstr);
   octave_value (const idx_vector& idx, bool lazy = true);
+  OCTAVE_DEPRECATED (7, "use 'octave_value (range<double>&)' instead")
   octave_value (double base, double limit, double inc);
+  OCTAVE_DEPRECATED (7, "use 'octave_value (range<double>&)' instead")
   octave_value (const Range& r, bool force_range = false);
+  octave_value (const octave::range<char>& r, char type, bool force_range = false);
+  octave_value (const octave::range<float>& r, bool force_range = false);
+  octave_value (const octave::range<double>& r, bool force_range = false);
+  octave_value (const octave::range<octave_int8>& r, bool force_range = false);
+  octave_value (const octave::range<octave_int16>& r, bool force_range = false);
+  octave_value (const octave::range<octave_int32>& r, bool force_range = false);
+  octave_value (const octave::range<octave_int64>& r, bool force_range = false);
+  octave_value (const octave::range<octave_uint8>& r, bool force_range = false);
+  octave_value (const octave::range<octave_uint16>& r, bool force_range = false);
+  octave_value (const octave::range<octave_uint32>& r, bool force_range = false);
+  octave_value (const octave::range<octave_uint64>& r, bool force_range = false);
   octave_value (const octave_map& m);
   octave_value (const octave_scalar_map& m);
   octave_value (const std::map<std::string, octave_value>&);
@@ -472,9 +476,17 @@
                              std::list<octave_value_list>& idx,
                              size_t skip = 1);
 
+  octave_value index_op (const octave_value_list& idx, bool resize_ok = false)
+  {
+    return rep->do_index_op (idx, resize_ok);
+  }
+
+  OCTAVE_DEPRECATED (7, "use 'octave_value::index_op' instead")
   octave_value do_index_op (const octave_value_list& idx,
                             bool resize_ok = false)
-  { return rep->do_index_op (idx, resize_ok); }
+  {
+    return index_op (idx, resize_ok);
+  }
 
   octave_value subsasgn (const std::string& type,
                          const std::list<octave_value_list>& idx,
@@ -629,6 +641,9 @@
   bool is_magic_colon (void) const
   { return rep->is_magic_colon (); }
 
+  bool is_magic_int (void) const
+  { return rep->is_magic_int (); }
+
   bool isnull (void) const
   { return rep->isnull (); }
 
@@ -935,9 +950,36 @@
   Array<std::string> cellstr_value (void) const
   { return rep->cellstr_value (); }
 
-  Range range_value (void) const
+  octave::range<float> float_range_value (void) const
+  { return rep->float_range_value (); }
+
+  octave::range<double> range_value (void) const
   { return rep->range_value (); }
 
+  octave::range<octave_int8> int8_range_value (void) const
+  { return rep->int8_range_value (); }
+
+  octave::range<octave_int16> int16_range_value (void) const
+  { return rep->int16_range_value (); }
+
+  octave::range<octave_int32> int32_range_value (void) const
+  { return rep->int32_range_value (); }
+
+  octave::range<octave_int64> int64_range_value (void) const
+  { return rep->int64_range_value (); }
+
+  octave::range<octave_uint8> uint8_range_value (void) const
+  { return rep->uint8_range_value (); }
+
+  octave::range<octave_uint16> uint16_range_value (void) const
+  { return rep->uint16_range_value (); }
+
+  octave::range<octave_uint32> uint32_range_value (void) const
+  { return rep->uint32_range_value (); }
+
+  octave::range<octave_uint64> uint64_range_value (void) const
+  { return rep->uint64_range_value (); }
+
   octave_map map_value (void) const;
 
   octave_scalar_map scalar_map_value (void) const;
@@ -1147,7 +1189,25 @@
 
   Array<std::string> xcellstr_value (const char *fmt, ...) const;
 
-  Range xrange_value (const char *fmt, ...) const;
+  octave::range<float> xfloat_range_value (const char *fmt, ...) const;
+
+  octave::range<double> xrange_value (const char *fmt, ...) const;
+
+  octave::range<octave_int8> xint8_range_value (const char *fmt, ...) const;
+
+  octave::range<octave_int16> xint16_range_value (const char *fmt, ...) const;
+
+  octave::range<octave_int32> xint32_range_value (const char *fmt, ...) const;
+
+  octave::range<octave_int64> xint64_range_value (const char *fmt, ...) const;
+
+  octave::range<octave_uint8> xuint8_range_value (const char *fmt, ...) const;
+
+  octave::range<octave_uint16> xuint16_range_value (const char *fmt, ...) const;
+
+  octave::range<octave_uint32> xuint32_range_value (const char *fmt, ...) const;
+
+  octave::range<octave_uint64> xuint64_range_value (const char *fmt, ...) const;
 
   octave_map xmap_value (const char *fmt, ...) const;
 
@@ -1255,39 +1315,27 @@
 
   std::string class_name (void) const { return rep->class_name (); }
 
-  // Unary and binary operations.
-
-  friend OCTINTERP_API octave_value
-  do_unary_op (octave::type_info& ti, unary_op op, const octave_value& a);
-
-  octave_value& do_non_const_unary_op (unary_op op);
-
-  octave_value& do_non_const_unary_op (unary_op op, const std::string& type,
-                                       const std::list<octave_value_list>& idx);
-
-  friend OCTINTERP_API octave_value
-  do_binary_op (octave::type_info& ti, binary_op op,
-                const octave_value& a, const octave_value& b);
+  // Unary operations that are member functions.  There are also some
+  // non-member functions for unary and binary operations declared
+  // below, outside of the octave_value class declaration.
 
-  friend OCTINTERP_API octave_value
-  do_binary_op (octave::type_info& ti, compound_binary_op op,
-                const octave_value& a, const octave_value& b);
+  octave_value& non_const_unary_op (unary_op op);
 
-  friend OCTINTERP_API octave_value
-  do_cat_op (octave::type_info& ti, const octave_value& a,
-             const octave_value& b, const Array<octave_idx_type>& ra_idx);
-
-  friend OCTINTERP_API octave_value do_colon_op (const octave_value& base,
-                                                 const octave_value& limit,
-                                                 bool is_for_cmd_expr)
+  OCTAVE_DEPRECATED (7, "use 'octave_value::non_const_unary_op' instead")
+  octave_value& do_non_const_unary_op (unary_op op)
   {
-    return do_colon_op (base, octave_value (), limit, is_for_cmd_expr);
+    return non_const_unary_op (op);
   }
 
-  friend OCTINTERP_API octave_value do_colon_op (const octave_value& base,
-                                                 const octave_value& increment,
-                                                 const octave_value& limit,
-                                                 bool is_for_cmd_expr);
+  octave_value& non_const_unary_op (unary_op op, const std::string& type,
+                                    const std::list<octave_value_list>& idx);
+
+  OCTAVE_DEPRECATED (7, "use 'octave_value::non_const_unary_op' instead")
+  octave_value& do_non_const_unary_op (unary_op op, const std::string& type,
+                                       const std::list<octave_value_list>& idx)
+  {
+    return non_const_unary_op (op, type, idx);
+  }
 
   const octave_base_value& get_rep (void) const { return *rep; }
 
@@ -1322,13 +1370,15 @@
 
   // Unsafe.  These functions exist to support the MEX interface.
   // You should not use them anywhere else.
-  void * mex_get_data (void) const { return rep->mex_get_data (); }
+  void * mex_get_data (mxClassID class_id = mxUNKNOWN_CLASS,
+                       mxComplexity complexity = mxREAL) const;
 
   octave_idx_type * mex_get_ir (void) const { return rep->mex_get_ir (); }
 
   octave_idx_type * mex_get_jc (void) const { return rep->mex_get_jc (); }
 
-  mxArray * as_mxArray (void) const { return rep->as_mxArray (); }
+  mxArray * as_mxArray (bool interleaved = false) const
+  { return rep->as_mxArray (interleaved); }
 
   octave_value diag (octave_idx_type k = 0) const
   { return rep->diag (k); }
@@ -1481,45 +1531,143 @@
 
 };
 
-// Publish externally used friend functions.  Which compiler requires
-// these extra declarations?
+// Non-member unary and binary operations on octave_value objects.
+
+namespace octave
+{
+  extern OCTINTERP_API octave_value
+  unary_op (type_info& ti, octave_value::unary_op op,
+            const octave_value& a);
+
+  extern OCTINTERP_API octave_value
+  unary_op (octave_value::unary_op op, const octave_value& a);
+
+  extern OCTINTERP_API octave_value
+  binary_op (type_info& ti, octave_value::binary_op op,
+             const octave_value& a, const octave_value& b);
+
+  extern OCTINTERP_API octave_value
+  binary_op (type_info& ti, octave_value::compound_binary_op op,
+             const octave_value& a, const octave_value& b);
 
-extern OCTINTERP_API octave_value
-do_unary_op (octave::type_info& ti, octave_value::unary_op op,
-             const octave_value& a);
+  extern OCTINTERP_API octave_value
+  binary_op (octave_value::binary_op op, const octave_value& a,
+             const octave_value& b);
+
+  extern OCTINTERP_API octave_value
+  binary_op (octave_value::compound_binary_op op, const octave_value& a,
+             const octave_value& b);
 
-extern OCTINTERP_API octave_value
-do_unary_op (octave_value::unary_op op, const octave_value& a);
+  extern OCTINTERP_API octave_value
+  cat_op (type_info& ti, const octave_value& a,
+          const octave_value& b, const Array<octave_idx_type>& ra_idx);
+
+  extern OCTINTERP_API octave_value
+  cat_op (const octave_value& a, const octave_value& b,
+          const Array<octave_idx_type>& ra_idx);
+
+  extern OCTINTERP_API octave_value
+  colon_op (const octave_value& base, const octave_value& increment,
+            const octave_value& limit, bool is_for_cmd_expr = false);
 
-extern OCTINTERP_API octave_value
-do_binary_op (octave::type_info& ti, octave_value::binary_op op,
-              const octave_value& a, const octave_value& b);
+  inline octave_value
+  colon_op (const octave_value& base, const octave_value& limit,
+            bool is_for_cmd_expr = false)
+  {
+    // Note, we need to pass an undefined octave_value object instead of
+    // octave_value (1.0) so that we can properly detect the
+    // two-argument case and correctly pass just two arguments to any
+    // user-defined function that is provided if either base or limit is
+    // an object.
+
+    return colon_op (base, octave_value (), limit, is_for_cmd_expr);
+  }
+}
+
+OCTAVE_DEPRECATED (7, "use 'octave::unary_op' instead")
+inline octave_value
+do_unary_op (octave::type_info& ti, octave_value::unary_op op,
+             const octave_value& a)
+{
+  return octave::unary_op (ti, op, a);
+}
 
-extern OCTINTERP_API octave_value
+OCTAVE_DEPRECATED (7, "use 'octave::unary_op' instead")
+inline octave_value
+do_unary_op (octave_value::unary_op op, const octave_value& a)
+{
+  return octave::unary_op (op, a);
+
+}
+OCTAVE_DEPRECATED (7, "use 'octave::binary_op' instead")
+inline octave_value
+do_binary_op (octave::type_info& ti, octave_value::binary_op op,
+              const octave_value& a, const octave_value& b)
+{
+  return octave::binary_op (ti, op, a, b);
+}
+
+OCTAVE_DEPRECATED (7, "use 'octave::binary_op' instead")
+inline octave_value
 do_binary_op (octave::type_info& ti, octave_value::compound_binary_op op,
-              const octave_value& a, const octave_value& b);
+              const octave_value& a, const octave_value& b)
+{
+  return octave::binary_op (ti, op, a, b);
+}
 
-extern OCTINTERP_API octave_value
+OCTAVE_DEPRECATED (7, "use 'octave::binary_op' instead")
+inline octave_value
 do_binary_op (octave_value::binary_op op, const octave_value& a,
-              const octave_value& b);
+              const octave_value& b)
+{
+  return octave::binary_op (op, a, b);
+}
 
-extern OCTINTERP_API octave_value
+OCTAVE_DEPRECATED (7, "use 'octave::binary_op' instead")
+inline octave_value
 do_binary_op (octave_value::compound_binary_op op, const octave_value& a,
-              const octave_value& b);
+              const octave_value& b)
+{
+  return octave::binary_op (op, a, b);
+}
 
-extern OCTINTERP_API octave_value
+OCTAVE_DEPRECATED (7, "use 'octave::cat_op' instead")
+inline octave_value
 do_cat_op (octave::type_info& ti, const octave_value& a,
-           const octave_value& b, const Array<octave_idx_type>& ra_idx);
+           const octave_value& b, const Array<octave_idx_type>& ra_idx)
+{
+  return octave::cat_op (ti, a, b, ra_idx);
+}
 
-extern OCTINTERP_API octave_value
+OCTAVE_DEPRECATED (7, "use 'octave::cat_op' instead")
+inline octave_value
 do_cat_op (const octave_value& a, const octave_value& b,
-           const Array<octave_idx_type>& ra_idx);
+           const Array<octave_idx_type>& ra_idx)
+{
+  return octave::cat_op (a, b, ra_idx);
+}
 
-#define OV_UNOP_FN(name)                        \
-  inline octave_value                           \
-  name (const octave_value& a)                  \
-  {                                             \
-    return do_unary_op (octave_value::name, a); \
+OCTAVE_DEPRECATED (7, "use 'octave::colon_op' instead")
+inline octave_value
+do_colon_op (const octave_value& base, const octave_value& increment,
+             const octave_value& limit, bool is_for_cmd_expr = false)
+{
+  return octave::colon_op (base, increment, limit, is_for_cmd_expr);
+}
+
+OCTAVE_DEPRECATED (7, "use 'octave::colon_op' instead")
+inline octave_value
+do_colon_op (const octave_value& base, const octave_value& limit,
+             bool is_for_cmd_expr = false)
+{
+  return octave::colon_op (base, limit, is_for_cmd_expr);
+}
+
+#define OV_UNOP_FN(name)                                \
+  inline octave_value                                   \
+  name (const octave_value& a)                          \
+  {                                                     \
+    return octave::unary_op (octave_value::name, a);    \
   }
 
 #define OV_UNOP_OP(name, op)                    \
@@ -1545,11 +1693,11 @@
 //   incr
 //   decr
 
-#define OV_BINOP_FN(name)                               \
-  inline octave_value                                   \
-  name (const octave_value& a1, const octave_value& a2) \
-  {                                                     \
-    return do_binary_op (octave_value::name, a1, a2);   \
+#define OV_BINOP_FN(name)                                       \
+  inline octave_value                                           \
+  name (const octave_value& a1, const octave_value& a2)         \
+  {                                                             \
+    return octave::binary_op (octave_value::name, a1, a2);      \
   }
 
 #define OV_BINOP_OP(name, op)                                   \
@@ -1587,11 +1735,11 @@
 
 OV_BINOP_FN (op_struct_ref)
 
-#define OV_COMP_BINOP_FN(name)                          \
-  inline octave_value                                   \
-  name (const octave_value& a1, const octave_value& a2) \
-  {                                                     \
-    return do_binary_op (octave_value::name, a1, a2);   \
+#define OV_COMP_BINOP_FN(name)                                  \
+  inline octave_value                                           \
+  name (const octave_value& a1, const octave_value& a2)         \
+  {                                                             \
+    return octave::binary_op (octave_value::name, a1, a2);      \
   }
 
 OV_COMP_BINOP_FN (op_trans_mul)
--- a/libinterp/op-kw-docs	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/op-kw-docs	Thu Nov 19 13:08:00 2020 -0800
@@ -572,6 +572,13 @@
 Mark the end of a properties block in a classdef definition.
 @seealso{properties}
 @end deftypefn
+endspmd
+@c libinterp/parse-tree/oct-parse.yy
+-*- texinfo -*-
+@deftypefn {} {} endparfor
+Mark the end of an spmd block.  See @code{spmd} for an example.
+@seealso{spmd, parfor}
+@end deftypefn
 endswitch
 @c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
@@ -732,6 +739,31 @@
 Return from a function.
 @seealso{function}
 @end deftypefn
+spmd
+@c libinterp/parse-tree/oct-parse.yy
+-*- texinfo -*-
+@deftypefn  {} {} spmd
+@deftypefnx {} {} spmd (@var{n})
+@deftypefnx {} {} spmd (@var{m}, @var{n})
+Begin a block of statements which may execute in parallel across multiple
+workers.
+
+If Octave has a parallel processing pool enabled, the block of code will be
+executed in parallel across all of the pool's workers.  Otherwise, @code{spmd}
+has no effect and the statements are processed as normal code by the main
+Octave interpreter.
+
+If called with one additional argument @var{n} then use exactly @var{n} workers
+from the pool.  If called with two arguments @var{m}, @var{n} then use a
+minimum of @var{m} workers and a maximum of @var{n} workers from the parallel
+pool.
+
+@strong{Warning:} parallel processing pools are currently unimplemented in
+Octave; @code{spmd} currently does nothing, but is included to avoid breaking
+existing @sc{matlab} code.
+
+@seealso{parfor}
+@end deftypefn
 switch
 @c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
--- a/libinterp/operators/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/operators/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -86,6 +86,7 @@
   %reldir%/op-m-s.cc \
   %reldir%/op-m-scm.cc \
   %reldir%/op-m-sm.cc \
+  %reldir%/op-mi.cc \
   %reldir%/op-pm-cm.cc \
   %reldir%/op-pm-fcm.cc \
   %reldir%/op-pm-fm.cc \
--- a/libinterp/operators/op-b-sbm.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/operators/op-b-sbm.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -49,7 +49,7 @@
 
 DEFCATOP (b_sbm, bool, sparse_bool_matrix)
 {
-  octave_bool& v1 = dynamic_cast<octave_bool&> (a1);
+  const octave_bool& v1 = dynamic_cast<const octave_bool&> (a1);
   const octave_sparse_bool_matrix& v2
     = dynamic_cast<const octave_sparse_bool_matrix&> (a2);
   SparseBoolMatrix tmp (1, 1, v1.bool_value ());
@@ -59,7 +59,7 @@
 
 DEFCATOP (b_sm, bool, sparse_matrix)
 {
-  octave_bool& v1 = dynamic_cast<octave_bool&> (a1);
+  const octave_bool& v1 = dynamic_cast<const octave_bool&> (a1);
   const octave_sparse_matrix& v2 = dynamic_cast<const octave_sparse_matrix&> (a2);
   SparseMatrix tmp (1, 1, v1.scalar_value ());
   return octave_value (tmp. concat (v2.sparse_matrix_value (), ra_idx));
@@ -67,7 +67,7 @@
 
 DEFCATOP (s_sbm, scalar, sparse_bool_matrix)
 {
-  octave_scalar& v1 = dynamic_cast<octave_scalar&> (a1);
+  const octave_scalar& v1 = dynamic_cast<const octave_scalar&> (a1);
   const octave_sparse_bool_matrix& v2
     = dynamic_cast<const octave_sparse_bool_matrix&> (a2);
   SparseMatrix tmp (1, 1, v1.scalar_value ());
--- a/libinterp/operators/op-bm-sbm.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/operators/op-bm-sbm.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -51,7 +51,7 @@
 
 DEFCATOP (bm_sbm, bool_matrix, sparse_bool_matrix)
 {
-  octave_bool_matrix& v1 = dynamic_cast<octave_bool_matrix&> (a1);
+  const octave_bool_matrix& v1 = dynamic_cast<const octave_bool_matrix&> (a1);
   const octave_sparse_bool_matrix& v2
     = dynamic_cast<const octave_sparse_bool_matrix&> (a2);
   SparseBoolMatrix tmp (v1.bool_matrix_value ());
@@ -61,7 +61,7 @@
 
 DEFCATOP (m_sbm, matrix, sparse_bool_matrix)
 {
-  octave_matrix& v1 = dynamic_cast<octave_matrix&> (a1);
+  const octave_matrix& v1 = dynamic_cast<const octave_matrix&> (a1);
   const octave_sparse_bool_matrix& v2
     = dynamic_cast<const octave_sparse_bool_matrix&> (a2);
   SparseMatrix tmp (v1.matrix_value ());
@@ -70,7 +70,7 @@
 
 DEFCATOP (bm_sm, bool_matrix, sparse_matrix)
 {
-  octave_bool_matrix& v1 = dynamic_cast<octave_bool_matrix&> (a1);
+  const octave_bool_matrix& v1 = dynamic_cast<const octave_bool_matrix&> (a1);
   const octave_sparse_matrix& v2 = dynamic_cast<const octave_sparse_matrix&> (a2);
   SparseMatrix tmp (v1.matrix_value ());
   return octave_value (tmp. concat (v2.sparse_matrix_value (), ra_idx));
--- a/libinterp/operators/op-chm.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/operators/op-chm.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -52,7 +52,7 @@
 
 DEFCATOP (chm_s, char_matrix, scalar)
 {
-  octave_char_matrix& v1 = dynamic_cast<octave_char_matrix&> (a1);
+  const octave_char_matrix& v1 = dynamic_cast<const octave_char_matrix&> (a1);
   const octave_scalar& v2 = dynamic_cast<const octave_scalar&> (a2);
 
   warn_implicit_conversion ("Octave:num-to-str",
@@ -64,7 +64,7 @@
 
 DEFCATOP (chm_m, char_matrix, matrix)
 {
-  octave_char_matrix& v1 = dynamic_cast<octave_char_matrix&> (a1);
+  const octave_char_matrix& v1 = dynamic_cast<const octave_char_matrix&> (a1);
   const octave_matrix& v2 = dynamic_cast<const octave_matrix&> (a2);
 
   warn_implicit_conversion ("Octave:num-to-str",
@@ -76,7 +76,7 @@
 
 DEFCATOP (s_chm, scalar, char_matrix)
 {
-  octave_scalar& v1 = dynamic_cast<octave_scalar&> (a1);
+  const octave_scalar& v1 = dynamic_cast<const octave_scalar&> (a1);
   const octave_char_matrix& v2 = dynamic_cast<const octave_char_matrix&> (a2);
 
   warn_implicit_conversion ("Octave:num-to-str",
@@ -88,7 +88,7 @@
 
 DEFCATOP (m_chm, matrix, char_matrix)
 {
-  octave_matrix& v1 = dynamic_cast<octave_matrix&> (a1);
+  const octave_matrix& v1 = dynamic_cast<const octave_matrix&> (a1);
   const octave_char_matrix& v2 = dynamic_cast<const octave_char_matrix&> (a2);
 
   warn_implicit_conversion ("Octave:num-to-str",
--- a/libinterp/operators/op-cm-scm.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/operators/op-cm-scm.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -129,7 +129,8 @@
 
 DEFCATOP (cm_scm, complex_matrix, sparse_complex_matrix)
 {
-  octave_complex_matrix& v1 = dynamic_cast<octave_complex_matrix&> (a1);
+  const octave_complex_matrix& v1
+    = dynamic_cast<const octave_complex_matrix&> (a1);
   const octave_sparse_complex_matrix& v2
     = dynamic_cast<const octave_sparse_complex_matrix&> (a2);
   SparseComplexMatrix tmp (v1.complex_matrix_value ());
--- a/libinterp/operators/op-cm-sm.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/operators/op-cm-sm.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -125,7 +125,8 @@
 
 DEFCATOP (cm_sm, complex_matrix, sparse_matrix)
 {
-  octave_complex_matrix& v1 = dynamic_cast<octave_complex_matrix&> (a1);
+  const octave_complex_matrix& v1
+    = dynamic_cast<const octave_complex_matrix&> (a1);
   const octave_sparse_matrix& v2
     = dynamic_cast<const octave_sparse_matrix&> (a2);
   SparseComplexMatrix tmp (v1.complex_matrix_value ());
--- a/libinterp/operators/op-cs-scm.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/operators/op-cs-scm.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -108,7 +108,7 @@
 
 DEFCATOP (cs_scm, complex, sparse_complex_matrix)
 {
-  octave_complex& v1 = dynamic_cast<octave_complex&> (a1);
+  const octave_complex& v1 = dynamic_cast<const octave_complex&> (a1);
   const octave_sparse_complex_matrix& v2
     = dynamic_cast<const octave_sparse_complex_matrix&> (a2);
   SparseComplexMatrix tmp (1, 1, v1.complex_value ());
--- a/libinterp/operators/op-cs-sm.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/operators/op-cs-sm.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -104,8 +104,9 @@
 
 DEFCATOP (cs_sm, sparse_matrix, complex)
 {
-  octave_complex& v1 = dynamic_cast<octave_complex&> (a1);
-  const octave_sparse_matrix& v2 = dynamic_cast<const octave_sparse_matrix&> (a2);
+  const octave_complex& v1 = dynamic_cast<const octave_complex&> (a1);
+  const octave_sparse_matrix& v2
+    = dynamic_cast<const octave_sparse_matrix&> (a2);
   SparseComplexMatrix tmp (1, 1, v1.complex_value ());
   return octave_value (tmp. concat (v2.sparse_matrix_value (), ra_idx));
 }
--- a/libinterp/operators/op-m-scm.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/operators/op-m-scm.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -122,7 +122,7 @@
 
 DEFCATOP (m_scm, matrix, sparse_complex_matrix)
 {
-  octave_matrix& v1 = dynamic_cast<octave_matrix&> (a1);
+  const octave_matrix& v1 = dynamic_cast<const octave_matrix&> (a1);
   const octave_sparse_complex_matrix& v2
     = dynamic_cast<const octave_sparse_complex_matrix&> (a2);
   SparseMatrix tmp (v1.matrix_value ());
--- a/libinterp/operators/op-m-sm.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/operators/op-m-sm.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -117,7 +117,7 @@
 
 DEFCATOP (m_sm, matrix, sparse_matrix)
 {
-  octave_matrix& v1 = dynamic_cast<octave_matrix&> (a1);
+  const octave_matrix& v1 = dynamic_cast<const octave_matrix&> (a1);
   const octave_sparse_matrix& v2 = dynamic_cast<const octave_sparse_matrix&> (a2);
   SparseMatrix tmp (v1.matrix_value ());
   return octave_value (tmp. concat (v2.sparse_matrix_value (), ra_idx));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/operators/op-mi.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,119 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include <iostream>
+
+#include "errwarn.h"
+#include "ops.h"
+#include "ov-magic-int.h"
+#include "ov-typeinfo.h"
+#include "ov.h"
+
+// Magic integer unary ops.  Only + and - are allowed so that
+// expressions like
+//
+//   int64 (-9007199254740994)
+//
+// produce proper int64 constants.
+
+static octave_value
+oct_unop_unsigned_uplus (const octave_base_value& a)
+{
+  const octave_magic_uint& v = dynamic_cast<const octave_magic_uint&> (a);
+  // no-op.
+  // FIXME: but can we do this just by incrementing the reference count?
+  return octave_value (v.clone ());
+}
+
+static octave_value
+oct_unop_unsigned_uminus (const octave_base_value& a)
+{
+  const octave_magic_uint& v = dynamic_cast<const octave_magic_uint&> (a);
+
+  // We are storing a uint64 value, so some fakery is needed here.
+  // Is there a better way?
+
+  octave_uint64 val = v.uint64_scalar_value ();
+
+  uint64_t ival = val.value ();
+
+  static const uint64_t max_val
+    = static_cast<uint64_t> (std::numeric_limits<int64_t>::max ());
+
+  static const uint64_t max_val_p1 = max_val + 1;
+
+  if (ival <= max_val)
+    {
+      int64_t signed_ival = ival;
+      return octave_value (new octave_magic_int (-signed_ival));
+    }
+
+  if (ival == max_val_p1)
+    {
+      // Correctly capture intmin.  For example, negating uint8(128)
+      // should return int8(-128) but converting directly to int8 and
+      // negating will not return the correct result.
+
+      static const int64_t min_signed_ival
+        = std::numeric_limits<int64_t>::min ();
+
+      return octave_value (new octave_magic_int (min_signed_ival));
+    }
+
+  return octave_value (-static_cast<double> (ival));
+}
+
+static octave_value
+oct_unop_signed_uplus (const octave_base_value& a)
+{
+  const octave_magic_int& v = dynamic_cast<const octave_magic_int&> (a);
+  // no-op.
+  // FIXME: but can we do this just by incrementing the reference count?
+  return octave_value (v.clone ());
+}
+
+static octave_value
+oct_unop_signed_uminus (const octave_base_value& a)
+{
+  const octave_magic_int& v = dynamic_cast<const octave_magic_int&> (a);
+
+  octave_int64 val = v.int64_scalar_value ();
+
+  return octave_value (new octave_magic_int (-val));
+}
+
+void
+install_mi_ops (octave::type_info& ti)
+{
+  INSTALL_UNOP_TI (ti, op_uplus, octave_magic_uint, unsigned_uplus);
+  INSTALL_UNOP_TI (ti, op_uminus, octave_magic_uint, unsigned_uminus);
+
+  INSTALL_UNOP_TI (ti, op_uplus, octave_magic_int, signed_uplus);
+  INSTALL_UNOP_TI (ti, op_uminus, octave_magic_int, signed_uminus);
+}
--- a/libinterp/operators/op-range.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/operators/op-range.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -31,63 +31,13 @@
 #include "ovl.h"
 #include "ov.h"
 #include "ov-range.h"
-#include "ov-ch-mat.h"
-#include "ov-scalar.h"
 #include "ov-re-mat.h"
-#include "ov-flt-re-mat.h"
-#include "ov-complex.h"
-#include "ov-cx-mat.h"
-#include "ov-bool.h"
-#include "ov-bool-mat.h"
 #include "ov-typeinfo.h"
 #include "ov-null-mat.h"
 #include "ops.h"
-#include "xpow.h"
 
-// range unary ops.
-
-DEFUNOP (not, range)
-{
-  const octave_range& v = dynamic_cast<const octave_range&> (a);
-
-  return octave_value (! v.matrix_value ());
-}
-
+// Allow +RNG_VAL to avoid conversion to array.
 DEFUNOP_OP (uplus, range, /* no-op */)
-DEFUNOP_OP (uminus, range, -)
-
-DEFUNOP (transpose, range)
-{
-  const octave_range& v = dynamic_cast<const octave_range&> (a);
-
-  return octave_value (v.matrix_value ().transpose ());
-}
-
-DEFBINOP_OP (addrs, range, scalar, +)
-DEFBINOP_OP (addsr, scalar, range, +)
-DEFBINOP_OP (subrs, range, scalar, -)
-DEFBINOP_OP (subsr, scalar, range, -)
-DEFBINOP_OP (mulrs, range, scalar, *)
-DEFBINOP_OP (mulsr, scalar, range, *)
-
-DEFBINOP_FN (el_powsr, scalar, range, elem_xpow)
-DEFBINOP_FN (el_powcsr, complex, range, elem_xpow)
-
-DEFNDCATOP_FN (r_r, range, range, array, array, concat)
-DEFNDCATOP_FN (r_s, range, scalar, array, array, concat)
-DEFNDCATOP_FN (r_m, range, matrix, array, array, concat)
-DEFNDCATOP_FN (r_cs, range, complex, array, complex_array, concat)
-DEFNDCATOP_FN (r_cm, range, complex_matrix, array, complex_array, concat)
-DEFNDCATOP_FN (r_b, range, bool, array, array, concat)
-DEFNDCATOP_FN (r_bm, range, bool_matrix, array, array, concat)
-DEFNDCATOP_FN (r_chm, range, char_matrix, array, char_array, concat)
-DEFNDCATOP_FN (s_r, scalar, range, array, array, concat)
-DEFNDCATOP_FN (m_r, matrix, range, array, array, concat)
-DEFNDCATOP_FN (cs_r, complex, range, complex_array, array, concat)
-DEFNDCATOP_FN (cm_r, complex_matrix, range, complex_array, array, concat)
-DEFNDCATOP_FN (b_r, bool, range, array, array, concat)
-DEFNDCATOP_FN (bm_r, bool_matrix, range, array, array, concat)
-DEFNDCATOP_FN (chm_r, char_matrix, range, char_array, array, concat)
 
 CONVDECL (range_to_matrix)
 {
@@ -99,39 +49,7 @@
 void
 install_range_ops (octave::type_info& ti)
 {
-  INSTALL_UNOP_TI (ti, op_not, octave_range, not);
   INSTALL_UNOP_TI (ti, op_uplus, octave_range, uplus);
-  INSTALL_UNOP_TI (ti, op_uminus, octave_range, uminus);
-  INSTALL_UNOP_TI (ti, op_transpose, octave_range, transpose);
-  INSTALL_UNOP_TI (ti, op_hermitian, octave_range, transpose);
-
-  INSTALL_BINOP_TI (ti, op_add, octave_range, octave_scalar, addrs);
-  INSTALL_BINOP_TI (ti, op_add, octave_scalar, octave_range, addsr);
-  INSTALL_BINOP_TI (ti, op_sub, octave_range, octave_scalar, subrs);
-  INSTALL_BINOP_TI (ti, op_sub, octave_scalar, octave_range, subsr);
-  INSTALL_BINOP_TI (ti, op_mul, octave_range, octave_scalar, mulrs);
-  INSTALL_BINOP_TI (ti, op_mul, octave_scalar, octave_range, mulsr);
-
-  INSTALL_BINOP_TI (ti, op_el_mul, octave_range, octave_scalar, mulrs);
-  INSTALL_BINOP_TI (ti, op_el_mul, octave_scalar, octave_range, mulsr);
-  INSTALL_BINOP_TI (ti, op_el_pow, octave_scalar, octave_range, el_powsr);
-  INSTALL_BINOP_TI (ti, op_el_pow, octave_complex, octave_range, el_powcsr);
-
-  INSTALL_CATOP_TI (ti, octave_range, octave_range, r_r);
-  INSTALL_CATOP_TI (ti, octave_range, octave_scalar, r_s);
-  INSTALL_CATOP_TI (ti, octave_range, octave_matrix, r_m);
-  INSTALL_CATOP_TI (ti, octave_range, octave_complex, r_cs);
-  INSTALL_CATOP_TI (ti, octave_range, octave_complex_matrix, r_cm);
-  INSTALL_CATOP_TI (ti, octave_range, octave_bool, r_b);
-  INSTALL_CATOP_TI (ti, octave_range, octave_bool_matrix, r_bm);
-  INSTALL_CATOP_TI (ti, octave_range, octave_char_matrix, r_chm);
-  INSTALL_CATOP_TI (ti, octave_scalar, octave_range, s_r);
-  INSTALL_CATOP_TI (ti, octave_matrix, octave_range, m_r);
-  INSTALL_CATOP_TI (ti, octave_complex, octave_range, cs_r);
-  INSTALL_CATOP_TI (ti, octave_complex_matrix, octave_range, cm_r);
-  INSTALL_CATOP_TI (ti, octave_bool, octave_range, b_r);
-  INSTALL_CATOP_TI (ti, octave_bool_matrix, octave_range, bm_r);
-  INSTALL_CATOP_TI (ti, octave_char_matrix, octave_range, chm_r);
 
   // FIXME: this would be unnecessary if
   // octave_base_value::numeric_assign always tried converting lhs
@@ -141,7 +59,7 @@
   INSTALL_ASSIGNCONV_TI (ti, octave_range, octave_null_str, octave_matrix);
   INSTALL_ASSIGNCONV_TI (ti, octave_range, octave_null_sq_str, octave_matrix);
 
-  // However, this should probably be here just in case we need it.
+  // Hmm, this one also seems to be needed.
 
   INSTALL_WIDENOP_TI (ti, octave_range, octave_matrix, range_to_matrix);
 }
--- a/libinterp/operators/op-s-scm.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/operators/op-s-scm.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -110,7 +110,7 @@
 
 DEFCATOP (s_scm, scalar, sparse_compelx_matrix)
 {
-  octave_scalar& v1 = dynamic_cast<octave_scalar&> (a1);
+  const octave_scalar& v1 = dynamic_cast<const octave_scalar&> (a1);
   const octave_sparse_complex_matrix& v2
     = dynamic_cast<const octave_sparse_complex_matrix&> (a2);
   SparseMatrix tmp (1, 1, v1.scalar_value ());
--- a/libinterp/operators/op-s-sm.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/operators/op-s-sm.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -101,7 +101,7 @@
 
 DEFCATOP (s_sm, scalar, sparse_matrix)
 {
-  octave_scalar& v1 = dynamic_cast<octave_scalar&> (a1);
+  const octave_scalar& v1 = dynamic_cast<const octave_scalar&> (a1);
   const octave_sparse_matrix& v2 = dynamic_cast<const octave_sparse_matrix&> (a2);
   SparseMatrix tmp (1, 1, v1.scalar_value ());
   return octave_value (tmp.concat (v2.sparse_matrix_value (), ra_idx));
--- a/libinterp/operators/op-sbm-b.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/operators/op-sbm-b.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -56,7 +56,7 @@
 
 DEFCATOP (sbm_b, sparse_bool_matrix, bool)
 {
-  octave_sparse_bool_matrix& v1 = dynamic_cast<octave_sparse_bool_matrix&> (a1);
+  const octave_sparse_bool_matrix& v1 = dynamic_cast<const octave_sparse_bool_matrix&> (a1);
   const octave_bool& v2 = dynamic_cast<const octave_bool&> (a2);
 
   SparseBoolMatrix tmp (1, 1, v2.bool_value ());
@@ -65,7 +65,7 @@
 
 DEFCATOP (sm_b, sparse_matrix, bool)
 {
-  octave_sparse_matrix& v1 = dynamic_cast<octave_sparse_matrix&> (a1);
+  const octave_sparse_matrix& v1 = dynamic_cast<const octave_sparse_matrix&> (a1);
   const octave_bool& v2 = dynamic_cast<const octave_bool&> (a2);
 
   SparseMatrix tmp (1, 1, v2.scalar_value ());
@@ -74,7 +74,7 @@
 
 DEFCATOP (sbm_s, sparse_bool_matrix, scalar)
 {
-  octave_sparse_bool_matrix& v1 = dynamic_cast<octave_sparse_bool_matrix&> (a1);
+  const octave_sparse_bool_matrix& v1 = dynamic_cast<const octave_sparse_bool_matrix&> (a1);
   const octave_scalar& v2 = dynamic_cast<const octave_scalar&> (a2);
 
   SparseMatrix tmp (1, 1, v2.scalar_value ());
--- a/libinterp/operators/op-sbm-bm.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/operators/op-sbm-bm.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -61,7 +61,7 @@
 
 DEFCATOP (sbm_bm, sparse_bool_matrix, bool_matrix)
 {
-  octave_sparse_bool_matrix& v1 = dynamic_cast<octave_sparse_bool_matrix&> (a1);
+  const octave_sparse_bool_matrix& v1 = dynamic_cast<const octave_sparse_bool_matrix&> (a1);
   const octave_bool_matrix& v2 = dynamic_cast<const octave_bool_matrix&> (a2);
 
   SparseBoolMatrix tmp (v2.bool_matrix_value ());
@@ -70,7 +70,7 @@
 
 DEFCATOP (sbm_m, sparse_bool_matrix, matrix)
 {
-  octave_sparse_bool_matrix& v1 = dynamic_cast<octave_sparse_bool_matrix&> (a1);
+  const octave_sparse_bool_matrix& v1 = dynamic_cast<const octave_sparse_bool_matrix&> (a1);
   const octave_matrix& v2 = dynamic_cast<const octave_matrix&> (a2);
 
   SparseMatrix tmp (v2.matrix_value ());
@@ -79,7 +79,7 @@
 
 DEFCATOP (sm_bm, sparse_matrix, bool_matrix)
 {
-  octave_sparse_matrix& v1 = dynamic_cast<octave_sparse_matrix&> (a1);
+  const octave_sparse_matrix& v1 = dynamic_cast<const octave_sparse_matrix&> (a1);
   const octave_bool_matrix& v2 = dynamic_cast<const octave_bool_matrix&> (a2);
 
   SparseMatrix tmp (v2.matrix_value ());
--- a/libinterp/operators/op-scm-cm.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/operators/op-scm-cm.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -129,8 +129,8 @@
 
 DEFCATOP (scm_cm, sparse_complex_matrix, complex_matrix)
 {
-  octave_sparse_complex_matrix& v1
-    = dynamic_cast<octave_sparse_complex_matrix&> (a1);
+  const octave_sparse_complex_matrix& v1
+    = dynamic_cast<const octave_sparse_complex_matrix&> (a1);
   const octave_complex_matrix& v2
     = dynamic_cast<const octave_complex_matrix&> (a2);
   SparseComplexMatrix tmp (v2.complex_matrix_value ());
--- a/libinterp/operators/op-scm-cs.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/operators/op-scm-cs.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -117,8 +117,8 @@
 
 DEFCATOP (scm_cs, sparse_complex_matrix, complex)
 {
-  octave_sparse_complex_matrix& v1
-    = dynamic_cast<octave_sparse_complex_matrix&> (a1);
+  const octave_sparse_complex_matrix& v1
+    = dynamic_cast<const octave_sparse_complex_matrix&> (a1);
   const octave_complex& v2 = dynamic_cast<const octave_complex&> (a2);
   SparseComplexMatrix tmp (1, 1, v2.complex_value ());
   return octave_value
--- a/libinterp/operators/op-scm-m.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/operators/op-scm-m.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -123,8 +123,8 @@
 
 DEFCATOP (scm_m, sparse_complex_matrix, matrix)
 {
-  octave_sparse_complex_matrix& v1
-    = dynamic_cast<octave_sparse_complex_matrix&> (a1);
+  const octave_sparse_complex_matrix& v1
+    = dynamic_cast<const octave_sparse_complex_matrix&> (a1);
   const octave_matrix& v2 = dynamic_cast<const octave_matrix&> (a2);
   SparseMatrix tmp (v2.matrix_value ());
   return octave_value
--- a/libinterp/operators/op-scm-s.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/operators/op-scm-s.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -125,8 +125,8 @@
 
 DEFCATOP (scm_s, sparse_complex_matrix, scalar)
 {
-  octave_sparse_complex_matrix& v1
-    = dynamic_cast<octave_sparse_complex_matrix&> (a1);
+  const octave_sparse_complex_matrix& v1
+    = dynamic_cast<const octave_sparse_complex_matrix&> (a1);
   const octave_scalar& v2 = dynamic_cast<const octave_scalar&> (a2);
   SparseComplexMatrix tmp (1, 1, v2.complex_value ());
   return octave_value
--- a/libinterp/operators/op-sm-cm.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/operators/op-sm-cm.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -126,7 +126,7 @@
 
 DEFCATOP (sm_cm, sparse_matrix, complex_matrix)
 {
-  octave_sparse_matrix& v1 = dynamic_cast<octave_sparse_matrix&> (a1);
+  const octave_sparse_matrix& v1 = dynamic_cast<const octave_sparse_matrix&> (a1);
   const octave_complex_matrix& v2
     = dynamic_cast<const octave_complex_matrix&> (a2);
   SparseComplexMatrix tmp (v2.complex_matrix_value ());
--- a/libinterp/operators/op-sm-cs.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/operators/op-sm-cs.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -114,7 +114,7 @@
 
 DEFCATOP (sm_cs, sparse_matrix, complex)
 {
-  octave_sparse_matrix& v1 = dynamic_cast<octave_sparse_matrix&> (a1);
+  const octave_sparse_matrix& v1 = dynamic_cast<const octave_sparse_matrix&> (a1);
   const octave_complex& v2 = dynamic_cast<const octave_complex&> (a2);
   SparseComplexMatrix tmp (1, 1, v2.complex_value ());
   return octave_value (v1.sparse_matrix_value (). concat (tmp, ra_idx));
--- a/libinterp/operators/op-sm-m.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/operators/op-sm-m.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -118,7 +118,7 @@
 
 DEFCATOP (sm_m, sparse_matrix, matrix)
 {
-  octave_sparse_matrix& v1 = dynamic_cast<octave_sparse_matrix&> (a1);
+  const octave_sparse_matrix& v1 = dynamic_cast<const octave_sparse_matrix&> (a1);
   const octave_matrix& v2 = dynamic_cast<const octave_matrix&> (a2);
   SparseMatrix tmp (v2.matrix_value ());
   return octave_value (v1.sparse_matrix_value (). concat (tmp, ra_idx));
--- a/libinterp/operators/op-sm-s.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/operators/op-sm-s.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -115,7 +115,7 @@
 
 DEFCATOP (sm_s, sparse_matrix, scalar)
 {
-  octave_sparse_matrix& v1 = dynamic_cast<octave_sparse_matrix&> (a1);
+  const octave_sparse_matrix& v1 = dynamic_cast<const octave_sparse_matrix&> (a1);
   const octave_scalar& v2 = dynamic_cast<const octave_scalar&> (a2);
   SparseMatrix tmp (1, 1, v2.scalar_value ());
   return octave_value (v1.sparse_matrix_value (). concat (tmp, ra_idx));
--- a/libinterp/operators/op-struct.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/operators/op-struct.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -60,7 +60,8 @@
 DEFNDCATOP_FN (ss_ss_concat, scalar_struct, scalar_struct, map, map, concat)
 
 static octave_value
-oct_catop_struct_matrix (octave_base_value& a1, const octave_base_value& a2,
+oct_catop_struct_matrix (const octave_base_value& a1,
+                         const octave_base_value& a2,
                          const Array<octave_idx_type>&)
 {
   const octave_struct& v1 = dynamic_cast<const octave_struct&> (a1);
@@ -76,7 +77,8 @@
 }
 
 static octave_value
-oct_catop_matrix_struct (octave_base_value& a1, const octave_base_value& a2,
+oct_catop_matrix_struct (const octave_base_value& a1,
+                         const octave_base_value& a2,
                          const Array<octave_idx_type>&)
 {
   const octave_matrix& v1 = dynamic_cast<const octave_matrix&> (a1);
--- a/libinterp/operators/ops.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/operators/ops.h	Thu Nov 19 13:08:00 2020 -0800
@@ -322,12 +322,13 @@
 
 #define DEFCATOPX(name, t1, t2)                                         \
   static octave_value                                                   \
-  CONCAT2 (oct_catop_, name) (octave_base_value&, const octave_base_value&, \
+  CONCAT2 (oct_catop_, name) (const octave_base_value&,                 \
+                              const octave_base_value&,                 \
                               const Array<octave_idx_type>& ra_idx)
 
 #define DEFCATOP(name, t1, t2)                                          \
   static octave_value                                                   \
-  CONCAT2 (oct_catop_, name) (octave_base_value& a1,                    \
+  CONCAT2 (oct_catop_, name) (const octave_base_value& a1,              \
                               const octave_base_value& a2,              \
                               const Array<octave_idx_type>& ra_idx)
 
@@ -335,11 +336,11 @@
 
 #define DEFCATOP_FN(name, t1, t2, f)                                    \
   static octave_value                                                   \
-  CONCAT2 (oct_catop_, name) (octave_base_value& a1,                    \
+  CONCAT2 (oct_catop_, name) (const octave_base_value& a1,              \
                               const octave_base_value& a2,              \
                               const Array<octave_idx_type>& ra_idx)     \
   {                                                                     \
-    CONCAT2 (octave_, t1)& v1 = dynamic_cast<CONCAT2 (octave_, t1)&> (a1); \
+    const CONCAT2 (octave_, t1)& v1 = dynamic_cast<const CONCAT2 (octave_, t1)&> (a1); \
     const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
                                                                         \
     return octave_value (v1.CONCAT2 (t1, _value) () . f (v2.CONCAT2 (t2, _value) (), ra_idx)); \
@@ -347,11 +348,11 @@
 
 #define DEFNDCATOP_FN(name, t1, t2, e1, e2, f)                          \
   static octave_value                                                   \
-  CONCAT2 (oct_catop_, name) (octave_base_value& a1,                    \
+  CONCAT2 (oct_catop_, name) (const octave_base_value& a1,              \
                               const octave_base_value& a2,              \
                               const Array<octave_idx_type>& ra_idx)     \
   {                                                                     \
-    CONCAT2 (octave_, t1)& v1 = dynamic_cast<CONCAT2 (octave_, t1)&> (a1); \
+    const CONCAT2 (octave_, t1)& v1 = dynamic_cast<const CONCAT2 (octave_, t1)&> (a1); \
     const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
                                                                         \
     return octave_value (v1.CONCAT2 (e1, _value) () . f (v2.CONCAT2 (e2, _value) (), ra_idx)); \
@@ -359,11 +360,11 @@
 
 #define DEFNDCHARCATOP_FN(name, t1, t2, f)                              \
   static octave_value                                                   \
-  CONCAT2 (oct_catop_, name) (octave_base_value& a1,                    \
+  CONCAT2 (oct_catop_, name) (const octave_base_value& a1,              \
                               const octave_base_value& a2,              \
                               const Array<octave_idx_type>& ra_idx)     \
   {                                                                     \
-    CONCAT2 (octave_, t1)& v1 = dynamic_cast<CONCAT2 (octave_, t1)&> (a1); \
+    const CONCAT2 (octave_, t1)& v1 = dynamic_cast<const CONCAT2 (octave_, t1)&> (a1); \
     const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
                                                                         \
     return octave_value (v1.char_array_value () . f (v2.char_array_value (), ra_idx), \
@@ -376,11 +377,11 @@
 
 #define DEFNDCATOP_FN2(name, t1, t2, tc1, tc2, e1, e2, f)               \
   static octave_value                                                   \
-  CONCAT2 (oct_catop_, name) (octave_base_value& a1,                    \
+  CONCAT2 (oct_catop_, name) (const octave_base_value& a1,              \
                               const octave_base_value& a2,              \
                               const Array<octave_idx_type>& ra_idx)     \
   {                                                                     \
-    CONCAT2 (octave_, t1)& v1 = dynamic_cast<CONCAT2 (octave_, t1)&> (a1); \
+    const CONCAT2 (octave_, t1)& v1 = dynamic_cast<const CONCAT2 (octave_, t1)&> (a1); \
     const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
                                                                         \
     return octave_value (tc1 (v1.CONCAT2 (e1, _value) ()) . f (tc2 (v2.CONCAT2 (e2, _value) ()), ra_idx)); \
--- a/libinterp/parse-tree/bp-table.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/bp-table.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -997,12 +997,4 @@
 
     return retval;
   }
-
-  octave_user_code *
-  get_user_code (const std::string& fname)
-  {
-    tree_evaluator& tw = __get_evaluator__ ("get_user_code");
-
-    return tw.get_user_code (fname);
-  }
 }
--- a/libinterp/parse-tree/bp-table.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/bp-table.h	Thu Nov 19 13:08:00 2020 -0800
@@ -164,9 +164,6 @@
     intmap remove_all_breakpoints_in_file_1 (octave_user_code *fcn,
                                              const std::string& fname);
   };
-
-  OCTAVE_DEPRECATED (5, "use 'octave::get_user_code' instead")
-  extern octave_user_code * get_user_code (const std::string& fname = "");
 }
 
 #endif
--- a/libinterp/parse-tree/jit-typeinfo.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/jit-typeinfo.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -116,7 +116,7 @@
   extern "C" octave_idx_type
   octave_jit_compute_nelem (double base, double limit, double inc)
   {
-    Range rng = Range (base, limit, inc);
+    range<double> rng (base, inc, limit);
     return rng.numel ();
   }
 
@@ -167,7 +167,7 @@
   extern "C" octave_base_value *
   octave_jit_cast_any_range (jit_range *rng)
   {
-    Range temp (*rng);
+    range<double> temp (*rng);
     octave_value ret (temp);
     octave_base_value *rep = ret.internal_rep ();
     rep->grab ();
@@ -480,7 +480,7 @@
   bool
   jit_range::all_elements_are_ints () const
   {
-    Range r (*this);
+    range<double> r (*this);
     return r.all_elements_are_ints ();
   }
 
--- a/libinterp/parse-tree/jit-typeinfo.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/jit-typeinfo.h	Thu Nov 19 13:08:00 2020 -0800
@@ -52,14 +52,14 @@
   struct
   jit_range
   {
-    jit_range (const Range& from)
+    jit_range (const range<double>& from)
       : m_base (from.base ()), m_limit (from.limit ()), m_inc (from.inc ()),
         m_nelem (from.numel ())
     { }
 
-    operator Range () const
+    operator range<double> () const
     {
-      return Range (m_base, m_limit, m_inc);
+      return range<double> (m_base, m_inc, m_limit);
     }
 
     bool all_elements_are_ints (void) const;
--- a/libinterp/parse-tree/lex.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/lex.h	Thu Nov 19 13:08:00 2020 -0800
@@ -661,7 +661,9 @@
 
     bool whitespace_is_significant (void);
 
-    void handle_number (void);
+    // We only provide specializations with base equal to 2, 10, or 16.
+    template <int base>
+    int handle_number (void);
 
     void handle_continuation (void);
 
@@ -772,6 +774,10 @@
       : base_lexer (interp), m_reader (interp, file), m_initial_input (true)
     { }
 
+    lexer (FILE *file, interpreter& interp, const std::string& encoding)
+      : base_lexer (interp), m_reader (interp, file, encoding), m_initial_input (true)
+    { }
+
     lexer (const std::string& eval_string, interpreter& interp)
       : base_lexer (interp), m_reader (interp, eval_string),
         m_initial_input (true)
@@ -822,6 +828,10 @@
     bool m_initial_input;
   };
 
+  template <> int base_lexer::handle_number<2> ();
+  template <> int base_lexer::handle_number<10> ();
+  template <> int base_lexer::handle_number<16> ();
+
   class
   push_lexer : public base_lexer
   {
--- a/libinterp/parse-tree/lex.ll	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/lex.ll	Thu Nov 19 13:08:00 2020 -0800
@@ -92,6 +92,7 @@
 #include <cctype>
 #include <cstring>
 
+#include <algorithm>
 #include <iostream>
 #include <set>
 #include <sstream>
@@ -117,6 +118,7 @@
 #include "interpreter.h"
 #include "lex.h"
 #include "octave.h"
+#include "ov-magic-int.h"
 #include "ov.h"
 #include "parse.h"
 #include "pt-all.h"
@@ -251,6 +253,35 @@
      }                                                  \
    while (0)
 
+#define HANDLE_NUMBER(PATTERN, BASE)                            \
+  do                                                            \
+    {                                                           \
+     curr_lexer->lexer_debug (PATTERN);                         \
+                                                                \
+     if (curr_lexer->previous_token_may_be_command ()           \
+         &&  curr_lexer->space_follows_previous_token ())       \
+       {                                                        \
+         yyless (0);                                            \
+         curr_lexer->push_start_state (COMMAND_START);          \
+       }                                                        \
+     else                                                       \
+       {                                                        \
+         int tok = curr_lexer->previous_token_value ();         \
+                                                                \
+         if (curr_lexer->whitespace_is_significant ()           \
+             && curr_lexer->space_follows_previous_token ()     \
+             && ! (tok == '[' || tok == '{'                     \
+                   || curr_lexer->previous_token_is_binop ()))  \
+           {                                                    \
+             yyless (0);                                        \
+             curr_lexer->xunput (',');                          \
+           }                                                    \
+         else                                                   \
+           return curr_lexer->handle_number<BASE> ();           \
+       }                                                        \
+    }                                                           \
+  while (0)
+
 #define HANDLE_IDENTIFIER(pattern, get_set)                             \
    do                                                                   \
      {                                                                  \
@@ -326,15 +357,40 @@
 D_      [0-9_]
 S       [ \t]
 NL      ((\n)|(\r)|(\r\n))
-Im      [iIjJ]
 CCHAR   [#%]
 IDENT   ([_$a-zA-Z][_$a-zA-Z0-9]*)
 FQIDENT ({IDENT}({S}*\.{S}*{IDENT})*)
-EXPON   ([DdEe][+-]?{D}{D_}*)
-NUMBIN  (0[bB][01_]+)
-NUMHEX  (0[xX][0-9a-fA-F][0-9a-fA-F_]*)
-NUMREAL (({D}{D_}*\.?{D_}*{EXPON}?)|(\.{D}{D_}*{EXPON}?))
-NUMBER  ({NUMREAL}|{NUMHEX}|{NUMBIN})
+
+%{
+// Decimal numbers may be real or imaginary but always create
+// double precision constants initially.  Any conversion to single
+// precision happens as part of an expression evaluation in the
+// interpreter, not the lexer and parser.
+%}
+
+DECIMAL_DIGITS ({D}{D_}*)
+EXPONENT       ([DdEe][+-]?{DECIMAL_DIGITS})
+REAL_DECIMAL   ((({DECIMAL_DIGITS}\.?)|({DECIMAL_DIGITS}?\.{DECIMAL_DIGITS})){EXPONENT}?)
+IMAG_DECIMAL   ({REAL_DECIMAL}[IiJj])
+DECIMAL_NUMBER ({REAL_DECIMAL}|{IMAG_DECIMAL})
+
+%{
+// It is possible to specify signedness and size for binary and
+// hexadecimal numbers but there is no special syntax for imaginary
+// constants.  Binary and hexadecimal constants always create integer
+// valued constants ({u,}int{8,16,32,64}).  If a size is not specified,
+// the smallest integer type that will hold the value is used.  Negative
+// values may be created with a signed size specification by applying
+// twos-complement conversion (for example, 0xffs8 produces an 8-bit
+// signed integer equal to -1 and 0b10000000s8 produces an 8-bit signed
+// integer equal to -128).
+%}
+
+SIZE_SUFFIX        ([su](8|16|32|64))
+BINARY_BITS        (0[bB][01][01_]*)
+BINARY_NUMBER      ({BINARY_BITS}|{BINARY_BITS}{SIZE_SUFFIX})
+HEXADECIMAL_BITS   (0[xX][0-9a-fA-F][0-9a-fA-F_]*)
+HEXADECIMAL_NUMBER ({HEXADECIMAL_BITS}|{HEXADECIMAL_BITS}{SIZE_SUFFIX})
 
 ANY_EXCEPT_NL [^\r\n]
 ANY_INCLUDING_NL (.|{NL})
@@ -1205,72 +1261,24 @@
     curr_lexer->pop_start_state ();
   }
 
-%{
-// Imaginary numbers.
-%}
-
-{NUMBER}{Im} {
-    curr_lexer->lexer_debug ("{NUMBER}{Im}");
-
-    if (curr_lexer->previous_token_may_be_command ()
-        &&  curr_lexer->space_follows_previous_token ())
-      {
-        yyless (0);
-        curr_lexer->push_start_state (COMMAND_START);
-      }
-    else
-      {
-        int tok = curr_lexer->previous_token_value ();
-
-        if (curr_lexer->whitespace_is_significant ()
-            && curr_lexer->space_follows_previous_token ()
-            && ! (tok == '[' || tok == '{'
-                  || curr_lexer->previous_token_is_binop ()))
-          {
-            yyless (0);
-            curr_lexer->xunput (',');
-          }
-        else
-          {
-            curr_lexer->handle_number ();
-            return curr_lexer->count_token_internal (IMAG_NUM);
-          }
-      }
+{BINARY_NUMBER} {
+    HANDLE_NUMBER ("{BINARY_NUMBER}", 2);
   }
 
 %{
-// Real numbers.  Don't grab the '.' part of a dot operator as part of
-// the constant.
+// Decimal numbers.  For expressions that are just digits followed
+// directly by an element-by-element operator, don't grab the '.'
+// part of the operator as part of the constant (for example, in an
+// expression like "13./x").
 %}
 
-{D}{D_}*/\.[\*/\\^\'] |
-{NUMBER} {
-    curr_lexer->lexer_debug ("{D}{D_}*/\\.[\\*/\\\\^\\']|{NUMBER}");
-
-    if (curr_lexer->previous_token_may_be_command ()
-        &&  curr_lexer->space_follows_previous_token ())
-      {
-        yyless (0);
-        curr_lexer->push_start_state (COMMAND_START);
-      }
-    else
-      {
-        int tok = curr_lexer->previous_token_value ();
-
-        if (curr_lexer->whitespace_is_significant ()
-            && curr_lexer->space_follows_previous_token ()
-            && ! (tok == '[' || tok == '{'
-                  || curr_lexer->previous_token_is_binop ()))
-          {
-            yyless (0);
-            curr_lexer->xunput (',');
-          }
-        else
-          {
-            curr_lexer->handle_number ();
-            return curr_lexer->count_token_internal (NUM);
-          }
-      }
+{DECIMAL_DIGITS}/\.[\*/\\^\'] |
+{DECIMAL_NUMBER} {
+    HANDLE_NUMBER ("{DECIMAL_DIGITS}/\\.[\\*/\\\\^\\']|{DECIMAL_NUMBER}", 10);
+  }
+
+{HEXADECIMAL_NUMBER} {
+    HANDLE_NUMBER ("{HEXADECIMAL_NUMBER}", 16);
   }
 
 %{
@@ -2784,7 +2792,6 @@
         m_at_beginning_of_statement = true;
         break;
 
-
       case for_kw:
       case parfor_kw:
       case while_kw:
@@ -2865,6 +2872,15 @@
           }
         break;
 
+      case spmd_kw:
+        m_at_beginning_of_statement = true;
+        break;
+
+      case endspmd_kw:
+        tok_val = new token (endspmd_kw, token::spmd_end, m_tok_beg, m_tok_end);
+        m_at_beginning_of_statement = true;
+        break;
+
       case magic_file_kw:
         {
           if ((m_reading_fcn_file || m_reading_script_file
@@ -2880,8 +2896,9 @@
       case magic_line_kw:
         {
           int l = m_tok_beg.line ();
-          tok_val = new token (magic_line_kw, static_cast<double> (l),
-                               "", m_tok_beg, m_tok_end);
+          octave_value ov_value (static_cast<double> (l));
+          tok_val = new token (magic_line_kw, ov_value, "",
+                               m_tok_beg, m_tok_end);
         }
         break;
 
@@ -2946,76 +2963,340 @@
   return (len > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X'));
 }
 
+static inline octave_value
+make_integer_value (uintmax_t long_int_val, bool unsigned_val, int bytes)
+{
+  if (unsigned_val)
+    {
+     switch (bytes)
+       {
+       case 1:
+         return octave_value (octave_uint8 (long_int_val));
+
+       case 2:
+         return octave_value (octave_uint16 (long_int_val));
+
+       case 4:
+         return octave_value (octave_uint32 (long_int_val));
+
+       case 8:
+         return octave_value (octave_uint64 (long_int_val));
+
+       default:
+         panic_impossible ();
+       };
+    }
+  else
+    {
+      // FIXME: Conversion to signed values is supposed to follow
+      // twos-complement rules.  Do we need to be more carefule here?
+
+      switch (bytes)
+        {
+        case 1:
+          return octave_value (octave_int8 (int8_t (long_int_val)));
+
+        case 2:
+          return octave_value (octave_int16 (int16_t (long_int_val)));
+
+        case 4:
+          return octave_value (octave_int32 (int32_t (long_int_val)));
+
+        case 8:
+        return octave_value (octave_int64 (int64_t (long_int_val)));
+
+        default:
+          panic_impossible ();
+        };
+    }
+
+  return octave_value ();
+}
+
 namespace octave
 {
-  void
-  base_lexer::handle_number (void)
+  template <>
+  int
+  base_lexer::handle_number<2> (void)
   {
-    double value = 0.0;
-    int nread = 0;
-
-    char *yytxt = flex_yytext ();
-
-    // Strip any underscores
-    char *tmptxt = strsave (yytxt);
-    char *rptr = tmptxt;
-    char *wptr = tmptxt;
-    while (*rptr)
-      {
-        *wptr = *rptr++;
-        wptr += (*wptr != '_');
-      }
-    *wptr = '\0';
-
-    if (looks_like_hex (tmptxt, strlen (tmptxt)))
+    // Skip 0[bB] prefix.
+    std::string yytxt (flex_yytext () + 2);
+
+    yytxt.erase (std::remove (yytxt.begin (), yytxt.end (), '_'),
+                 yytxt.end ());
+
+    size_t pos = yytxt.find_first_of ("su");
+
+    bool unsigned_val = true;
+    int bytes = -1;
+
+    if (pos == std::string::npos)
       {
-        uintmax_t long_int_value;
-
-        nread = sscanf (tmptxt, "%jx", &long_int_value);
-
-        value = static_cast<double> (long_int_value);
-      }
-    else if (looks_like_bin (tmptxt, strlen (tmptxt)))
-      {
-        uintmax_t long_int_value = 0;
-
-        for (size_t i = 0; i < strlen (tmptxt); i++)
-          {
-            if (tmptxt[i] == '0')
-              long_int_value <<= 1;
-            else if (tmptxt[i] == '1')
-            {
-              long_int_value <<= 1;
-              long_int_value += 1;
-            }
-          }
-
-        value = static_cast<double> (long_int_value);
-
-        nread = 1;  // Just to pass the assert stmt below
+        size_t num_digits = yytxt.length ();
+
+        if (num_digits <= 8)
+          bytes = 1;
+        else if (num_digits <= 16)
+          bytes = 2;
+        else if (num_digits <= 32)
+          bytes = 4;
+        else if (num_digits <= 64)
+          bytes = 8;
       }
     else
       {
-        char *idx = strpbrk (tmptxt, "Dd");
-
-        if (idx)
-          *idx = 'e';
-
-        nread = sscanf (tmptxt, "%lf", &value);
+        unsigned_val = (yytxt[pos] == 'u');
+        std::string size_str = yytxt.substr (pos+1);
+        yytxt = yytxt.substr (0, pos);
+        size_t num_digits = yytxt.length ();
+
+        if (size_str == "8" && num_digits <= 8)
+          bytes = 1;
+        else if (size_str == "16" && num_digits <= 16)
+          bytes = 2;
+        else if (size_str == "32" && num_digits <= 32)
+          bytes = 4;
+        else if (size_str == "64" && num_digits <= 64)
+          bytes = 8;
       }
 
-    delete [] tmptxt;
-
-    // If yytext doesn't contain a valid number, we are in deep doo doo.
-
-    assert (nread == 1);
+    if (bytes < 0)
+      {
+        token *tok
+          = new token (LEXICAL_ERROR,
+                       "too many digits for binary constant",
+                       m_tok_beg, m_tok_end);
+
+        push_token (tok);
+
+        return count_token_internal (LEXICAL_ERROR);
+      }
+
+    // FIXME: is there a better way?  Can uintmax_t be anything other
+    // than long or long long?  Should we just be using uint64_t instead
+    // of uintmax_t?
+
+    errno = 0;
+    char *end;
+    uintmax_t long_int_val;
+    if (sizeof (uintmax_t) == sizeof (unsigned long long))
+      long_int_val = strtoull (yytxt.c_str (), &end, 2);
+    else if (sizeof (uintmax_t) == sizeof (unsigned long))
+      long_int_val = strtoul (yytxt.c_str (), &end, 2);
+    else
+      panic_impossible ();
+
+    if (errno == ERANGE)
+      panic_impossible ();
+
+    octave_value ov_value
+      = make_integer_value (long_int_val, unsigned_val, bytes);
 
     m_looking_for_object_index = false;
     m_at_beginning_of_statement = false;
 
     update_token_positions (flex_yyleng ());
 
-    push_token (new token (NUM, value, yytxt, m_tok_beg, m_tok_end));
+    push_token (new token (NUMBER, ov_value, yytxt, m_tok_beg, m_tok_end));
+
+    return count_token_internal (NUMBER);
+  }
+
+  static uint64_t
+  flintmax (void)
+  {
+    return (static_cast<uint64_t> (1) << std::numeric_limits<double>::digits);
+  }
+
+  template <>
+  int
+  base_lexer::handle_number<10> (void)
+  {
+    bool imag = false;
+    bool digits_only = true;
+
+    char *yytxt = flex_yytext ();
+    size_t yylng = flex_yyleng ();
+
+    OCTAVE_LOCAL_BUFFER (char, tmptxt, yylng + 1);
+    char *rp = yytxt;
+    char *p = &tmptxt[0];
+
+    char ch;
+    while ((ch = *rp++))
+      {
+        switch (ch)
+          {
+          case '_':
+            break;
+
+          case 'D':
+          case 'd':
+            *p++ = 'e';
+            digits_only = false;
+            break;
+
+          case 'I':
+          case 'J':
+          case 'i':
+          case 'j':
+            // Octave does not provide imaginary integers.
+            digits_only = false;
+            imag = true;
+            break;
+
+          case '+':
+          case '-':
+          case '.':
+          case 'E':
+          case 'e':
+            digits_only = false;
+            *p++ = ch;
+            break;
+
+          default:
+            *p++ = ch;
+            break;
+          }
+      }
+
+    *p = '\0';
+
+    double value = 0.0;
+    int nread = 0;
+
+    nread = sscanf (tmptxt, "%lf", &value);
+
+    // If yytext doesn't contain a valid number, we are in deep doo doo.
+
+    assert (nread == 1);
+
+    octave_value ov_value;
+
+    // Use >= because > will not return true until value is greater than
+    // flintmax + 2!
+
+    if (digits_only && value >= flintmax ())
+      {
+        // Try reading as an unsigned 64-bit integer.  If there is a
+        // range error, then create a double value.  Otherwise, create a
+        // special uint64 object that will be automatically converted to
+        // double unless it appears as the argument to one of the int64
+        // or uint64 functions.
+
+        errno = 0;
+        char *end;
+        uintmax_t long_int_val;
+        if (sizeof (uintmax_t) == sizeof (unsigned long long))
+          long_int_val = strtoull (tmptxt, &end, 10);
+        else if (sizeof (uintmax_t) == sizeof (unsigned long))
+          long_int_val = strtoul (tmptxt, &end, 10);
+        else
+          panic_impossible ();
+
+        if (errno != ERANGE)
+          {
+            // If possible, store the value as a signed integer.
+
+            octave_base_value *magic_int;
+            if (long_int_val > std::numeric_limits<int64_t>::max ())
+              magic_int = new octave_magic_uint (octave_uint64 (long_int_val));
+            else
+              magic_int = new octave_magic_int (octave_int64 (long_int_val));
+
+            ov_value = octave_value (magic_int);
+          }
+      }
+
+    m_looking_for_object_index = false;
+    m_at_beginning_of_statement = false;
+
+    update_token_positions (yylng);
+
+    if (ov_value.is_undefined ())
+      ov_value = (imag
+                  ? octave_value (Complex (0.0, value))
+                  : octave_value (value));
+
+    push_token (new token (NUMBER, ov_value, yytxt, m_tok_beg, m_tok_end));
+
+    return count_token_internal (NUMBER);
+  }
+
+  template <>
+  int
+  base_lexer::handle_number<16> (void)
+  {
+    // Skip 0[xX] prefix.
+    std::string yytxt (flex_yytext () + 2);
+
+    yytxt.erase (std::remove (yytxt.begin (), yytxt.end (), '_'),
+                 yytxt.end ());
+
+    size_t pos = yytxt.find_first_of ("su");
+
+    bool unsigned_val = true;
+    int bytes = -1;
+
+    if (pos == std::string::npos)
+      {
+        size_t num_digits = yytxt.length ();
+
+        if (num_digits <= 2)
+          bytes = 1;
+        else if (num_digits <= 4)
+          bytes = 2;
+        else if (num_digits <= 8)
+          bytes = 4;
+        else if (num_digits <= 16)
+          bytes = 8;
+      }
+    else
+      {
+        unsigned_val = (yytxt[pos] == 'u');
+        std::string size_str = yytxt.substr (pos+1);
+        yytxt = yytxt.substr (0, pos);
+        size_t num_digits = yytxt.length ();
+
+        if (size_str == "8" && num_digits <= 2)
+          bytes = 1;
+        else if (size_str == "16" && num_digits <= 4)
+          bytes = 2;
+        else if (size_str == "32" && num_digits <= 8)
+          bytes = 4;
+        else if (size_str == "64" && num_digits <= 16)
+          bytes = 8;
+      }
+
+    if (bytes < 0)
+      {
+        token *tok
+          = new token (LEXICAL_ERROR,
+                       "too many digits for hexadecimal constant",
+                       m_tok_beg, m_tok_end);
+
+        push_token (tok);
+
+        return count_token_internal (LEXICAL_ERROR);
+      }
+
+    // Assert here because if yytext doesn't contain a valid number, we
+    // are in deep doo doo.
+
+    uintmax_t long_int_val;
+    assert (sscanf (yytxt.c_str (), "%jx", &long_int_val));
+
+    octave_value ov_value
+      = make_integer_value (long_int_val, unsigned_val, bytes);
+
+    m_looking_for_object_index = false;
+    m_at_beginning_of_statement = false;
+
+    update_token_positions (flex_yyleng ());
+
+    push_token (new token (NUMBER, ov_value, yytxt, m_tok_beg, m_tok_end));
+
+    return count_token_internal (NUMBER);
   }
 
   void
@@ -3444,12 +3725,13 @@
       case POW: std::cerr << "POW\n"; break;
       case EPOW: std::cerr << "EPOW\n"; break;
 
-      case NUM:
-      case IMAG_NUM:
+      case NUMBER:
         {
           token *tok_val = current_token ();
-          std::cerr << (tok == NUM ? "NUM" : "IMAG_NUM")
-                    << " [" << tok_val->number () << "]\n";
+          std::cerr << "NUMBER [";
+          octave_value num = tok_val->number ();
+          num.print_raw (std::cerr);
+          std::cerr << "]\n";
         }
         break;
 
--- a/libinterp/parse-tree/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -38,6 +38,7 @@
   %reldir%/pt-misc.h \
   %reldir%/pt-pr-code.h \
   %reldir%/pt-select.h \
+  %reldir%/pt-spmd.h \
   %reldir%/pt-stmt.h \
   %reldir%/pt-tm-const.h \
   %reldir%/pt-unop.h \
@@ -87,6 +88,7 @@
   %reldir%/pt-misc.cc \
   %reldir%/pt-pr-code.cc \
   %reldir%/pt-select.cc \
+  %reldir%/pt-spmd.cc \
   %reldir%/pt-stmt.cc \
   %reldir%/pt-tm-const.cc \
   %reldir%/pt-unop.cc \
--- a/libinterp/parse-tree/oct-lvalue.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/oct-lvalue.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -206,10 +206,10 @@
     return retval;
   }
 
-  void octave_lvalue::do_unary_op (octave_value::unary_op op)
+  void octave_lvalue::unary_op (octave_value::unary_op op)
   {
     if (! is_black_hole ())
-      m_frame->do_non_const_unary_op (op, m_sym, m_type, m_idx);
+      m_frame->non_const_unary_op (op, m_sym, m_type, m_idx);
   }
 
   octave_value octave_lvalue::value (void) const
--- a/libinterp/parse-tree/oct-lvalue.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/oct-lvalue.h	Thu Nov 19 13:08:00 2020 -0800
@@ -78,7 +78,13 @@
 
     bool index_is_colon (void) const;
 
-    void do_unary_op (octave_value::unary_op op);
+    void unary_op (octave_value::unary_op op);
+
+    OCTAVE_DEPRECATED (7, "use 'octave_lvalue::unary_op' instead")
+    void do_unary_op (octave_value::unary_op op)
+    {
+      return unary_op (op);
+    }
 
     octave_value value (void) const;
 
--- a/libinterp/parse-tree/oct-parse.yy	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/oct-parse.yy	Thu Nov 19 13:08:00 2020 -0800
@@ -199,12 +199,13 @@
 %token <tok_val> LEFTDIV EMUL EDIV ELEFTDIV EPLUS EMINUS
 %token <tok_val> HERMITIAN TRANSPOSE
 %token <tok_val> PLUS_PLUS MINUS_MINUS POW EPOW
-%token <tok_val> NUM IMAG_NUM
+%token <tok_val> NUMBER
 %token <tok_val> STRUCT_ELT
 %token <tok_val> NAME
 %token <tok_val> END
 %token <tok_val> DQ_STRING SQ_STRING
 %token <tok_val> FOR PARFOR WHILE DO UNTIL
+%token <tok_val> SPMD
 %token <tok_val> IF ELSEIF ELSE
 %token <tok_val> SWITCH CASE OTHERWISE
 %token <tok_val> BREAK CONTINUE FUNC_RET
@@ -253,7 +254,7 @@
 %type <tree_parameter_list_type> param_list1 param_list2
 %type <tree_parameter_list_type> return_list return_list1
 %type <tree_command_type> command select_command loop_command
-%type <tree_command_type> jump_command except_command
+%type <tree_command_type> jump_command spmd_command except_command
 %type <tree_function_def_type> function
 %type <tree_classdef_type> classdef
 %type <tree_command_type> file
@@ -540,10 +541,8 @@
                   { $$ = parser.make_constant (SQ_STRING, $1); }
                 ;
 
-constant        : NUM
-                  { $$ = parser.make_constant (NUM, $1); }
-                | IMAG_NUM
-                  { $$ = parser.make_constant (IMAG_NUM, $1); }
+constant        : NUMBER
+                  { $$ = parser.make_constant (NUMBER, $1); }
                 | string
                   { $$ = $1; }
                 ;
@@ -1056,6 +1055,8 @@
                   { $$ = $1; }
                 | jump_command
                   { $$ = $1; }
+                | spmd_command
+                  { $$ = $1; }
                 | except_command
                   { $$ = $1; }
                 | function
@@ -1326,6 +1327,25 @@
                   { $$ = parser.make_return_command ($1); }
                 ;
 
+// =======================
+// Parallel execution pool
+// =======================
+
+spmd_command    : SPMD stash_comment opt_sep opt_list END
+                  {
+                    YYUSE ($3);
+
+                    octave::comment_list *lc = $2;
+                    octave::comment_list *tc = lexer.get_comment ();
+
+                    if (! ($$ = parser.make_spmd_command ($1, $4, $5, lc, tc)))
+                      {
+                        // make_spmd_command deleted $4, LC, and TC.
+                        YYABORT;
+                      }
+                  }
+                ;
+
 // ==========
 // Exceptions
 // ==========
@@ -2467,6 +2487,10 @@
         retval = "endproperties";
         break;
 
+      case token::spmd_end:
+        retval = "endspmd";
+        break;
+
       case token::switch_end:
         retval = "endswitch";
         break;
@@ -2537,7 +2561,7 @@
       m_max_fcn_depth = m_curr_fcn_depth;
 
     // Will get a real name later.
-    m_lexer.m_symtab_context.push (octave::symbol_scope ("parser:push_fcn_symtab"));
+    m_lexer.m_symtab_context.push (symbol_scope ("parser:push_fcn_symtab"));
     m_function_scopes.push (m_lexer.m_symtab_context.curr_scope ());
 
     if (! m_lexer.m_reading_script_file && m_curr_fcn_depth == 0
@@ -2569,18 +2593,9 @@
 
     switch (op)
       {
-      case NUM:
+      case NUMBER:
         {
-          octave_value tmp (tok_val->number ());
-          retval = new tree_constant (tmp, l, c);
-          retval->stash_original_text (tok_val->text_rep ());
-        }
-        break;
-
-      case IMAG_NUM:
-        {
-          octave_value tmp (Complex (0.0, tok_val->number ()));
-          retval = new tree_constant (tmp, l, c);
+          retval = new tree_constant (tok_val->number (), l, c);
           retval->stash_original_text (tok_val->text_rep ());
         }
         break;
@@ -3230,6 +3245,34 @@
     return new tree_return_command (l, c);
   }
 
+  // Build an spmd command.
+
+  tree_spmd_command *
+  base_parser::make_spmd_command (token *spmd_tok, tree_statement_list *body,
+                                  token *end_tok, comment_list *lc,
+                                  comment_list *tc)
+  {
+    tree_spmd_command *retval = nullptr;
+
+    if (end_token_ok (end_tok, token::spmd_end))
+      {
+        int l = spmd_tok->line ();
+        int c = spmd_tok->column ();
+
+        retval = new tree_spmd_command (body, lc, tc, l, c);
+      }
+    else
+      {
+        delete body;
+        delete lc;
+        delete tc;
+
+        end_token_error (end_tok, token::spmd_end);
+      }
+
+    return retval;
+  }
+
   // Start an if command.
 
   tree_if_command_list *
@@ -3540,7 +3583,7 @@
         return nullptr;
       }
 
-    octave::symbol_scope curr_scope = m_lexer.m_symtab_context.curr_scope ();
+    symbol_scope curr_scope = m_lexer.m_symtab_context.curr_scope ();
     curr_scope.cache_name (id_name);
 
     m_lexer.m_parsed_function_name.top () = true;
@@ -4375,6 +4418,12 @@
                     return false;
                   }
               }
+            else if (iskeyword (name))
+              {
+                bison_error ("invalid use of keyword '" + name
+                             + "' in parameter list");
+                return false;
+              }
             else if (dict.find (name) != dict.end ())
               {
                 bison_error ("'" + name
@@ -4924,7 +4973,20 @@
     FILE *ffile = nullptr;
 
     if (! full_file.empty ())
+    {
+      // Check that m-file is not overly large which can segfault interpreter.
+      const int max_file_size = 512 * 1024 * 1024;  // 512 MB
+      sys::file_stat fs (full_file);
+
+      if (fs && fs.size () > max_file_size)
+        {
+          error ("file '%s' is too large, > 512 MB", full_file.c_str ());
+
+          return octave_value ();
+        }
+
       ffile = sys::fopen (full_file, "rb");
+    }
 
     if (! ffile)
       {
@@ -4934,12 +4996,11 @@
         return octave_value ();
       }
 
-    unwind_action act ([ffile] (void)
-                       {
-                         fclose (ffile);
-                       });
-
-    parser parser (ffile, interp);
+    unwind_action act ([=] (void) { ::fclose (ffile); });
+
+    // get the encoding for this folder
+    octave::input_system& input_sys = interp.get_input_system ();
+    parser parser (ffile, interp, input_sys.dir_encoding (dir_name));
 
     parser.m_curr_class_name = dispatch_type;
     parser.m_curr_package_name = package_name;
@@ -5499,23 +5560,6 @@
 
 namespace octave
 {
-  octave_value_list
-  eval_string (const std::string& eval_str, bool silent,
-               int& parse_status, int nargout)
-  {
-    interpreter& interp = __get_interpreter__ ("eval_string");
-
-    return interp.eval_string (eval_str, silent, parse_status, nargout);
-  }
-
-  octave_value
-  eval_string (const std::string& eval_str, bool silent, int& parse_status)
-  {
-    interpreter& interp = __get_interpreter__ ("eval_string");
-
-    return interp.eval_string (eval_str, silent, parse_status);
-  }
-
   void
   cleanup_statement_list (tree_statement_list **lst)
   {
@@ -5753,7 +5797,7 @@
   // the eval, then the message is stored in the exception object and we
   // will display it later, after the buffers have been restored.
 
-  octave::unwind_action act ([old_out_buf, old_err_buf] (void)
+  octave::unwind_action act ([=] (void)
                              {
                                octave_stdout.rdbuf (old_out_buf);
                                std::cerr.rdbuf (old_err_buf);
@@ -5893,10 +5937,10 @@
   if (nargin < 1 || nargin > 2)
     print_usage ();
 
-  std::string file = args(0).xstring_value ("__parse_file__: expecting filename as argument");
-
-  std::string full_file
-      = octave::sys::file_ops::tilde_expand (file);
+  std::string file
+    = args(0).xstring_value ("__parse_file__: expecting filename as argument");
+
+  std::string full_file = octave::sys::file_ops::tilde_expand (file);
 
   full_file = octave::sys::env::make_absolute (full_file);
 
--- a/libinterp/parse-tree/octave.gperf	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/octave.gperf	Thu Nov 19 13:08:00 2020 -0800
@@ -51,6 +51,7 @@
   endmethods_kw,
   endparfor_kw,
   endproperties_kw,
+  endspmd_kw,
   endswitch_kw,
   endwhile_kw,
   enumeration_kw,
@@ -69,6 +70,7 @@
   properties_kw,
   return_kw,
   set_kw,
+  spmd_kw,
   switch_kw,
   try_kw,
   until_kw,
@@ -102,6 +104,7 @@
 endmethods, END, endmethods_kw
 endparfor, END, endparfor_kw
 endproperties, END, endproperties_kw
+endspmd, END, endspmd_kw
 endswitch, END, endswitch_kw
 endwhile, END, endwhile_kw
 enumeration, ENUMERATION, enumeration_kw
@@ -118,6 +121,7 @@
 properties, PROPERTIES, properties_kw
 return, FUNC_RET, return_kw
 set, SET, set_kw
+spmd, SPMD, spmd_kw
 switch, SWITCH, switch_kw
 try, TRY, try_kw
 until, UNTIL, until_kw
@@ -125,4 +129,4 @@
 unwind_protect_cleanup, CLEANUP, unwind_protect_cleanup_kw
 while, WHILE, while_kw
 __FILE__, DQ_STRING, magic_file_kw
-__LINE__, NUM, magic_line_kw
+__LINE__, NUMBER, magic_line_kw
--- a/libinterp/parse-tree/parse.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/parse.h	Thu Nov 19 13:08:00 2020 -0800
@@ -81,6 +81,7 @@
   class tree_matrix;
   class tree_matrix;
   class tree_parameter_list;
+  class tree_spmd_command;
   class tree_statement;
   class tree_statement_list;
   class tree_statement_listtree_statement;
@@ -304,6 +305,12 @@
     // Build a return command.
     tree_command * make_return_command (token *return_tok);
 
+    // Build an spmd command.
+
+    tree_spmd_command *
+    make_spmd_command (token *spmd_tok, tree_statement_list *body,
+                       token *end_tok, comment_list *lc, comment_list *tc);
+
     // Start an if command.
     tree_if_command_list *
     start_if_command (tree_expression *expr, tree_statement_list *list);
@@ -603,6 +610,10 @@
       : base_parser (*(new lexer (file, interp)))
     { }
 
+    parser (FILE *file, interpreter& interp, std::string encoding)
+      : base_parser (*(new lexer (file, interp, encoding)))
+    { }
+
     parser (const std::string& eval_string, interpreter& interp)
       : base_parser (*(new lexer (eval_string, interp)))
     { }
@@ -712,14 +723,6 @@
   extern OCTINTERP_API octave_value_list
   feval (const octave_value_list& args, int nargout = 0);
 
-  OCTAVE_DEPRECATED (5, "use 'octave::interpreter::eval_string' instead")
-  extern OCTINTERP_API octave_value_list
-  eval_string (const std::string&, bool silent, int& parse_status, int nargout);
-
-  OCTAVE_DEPRECATED (5, "use 'octave::interpreter::eval_string' instead")
-  extern OCTINTERP_API octave_value
-  eval_string (const std::string&, bool silent, int& parse_status);
-
   extern OCTINTERP_API void
   cleanup_statement_list (tree_statement_list **lst);
 }
--- a/libinterp/parse-tree/profiler.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/profiler.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -28,6 +28,7 @@
 #endif
 
 #include "defun.h"
+#include "event-manager.h"
 #include "interpreter.h"
 #include "oct-time.h"
 #include "ov-struct.h"
@@ -255,7 +256,7 @@
   profiler::reset (void)
   {
     if (enabled ())
-      error ("Can't reset active profiler.");
+      error ("profile: can't reset active profiler");
 
     m_known_functions.clear ();
     m_fcn_index.clear ();
@@ -397,7 +398,16 @@
   octave::profiler& profiler = interp.get_profiler ();
 
   if (nargin == 1)
-    profiler.set_active (args(0).bool_value ());
+    {
+      profiler.set_active (args(0).bool_value ());
+
+      std::string status = "off";
+      if (args(0).bool_value ())
+        status = "on";
+
+      octave::event_manager& evmgr = interp.get_event_manager ();
+      evmgr.gui_status_update ("profiler", status);  // tell GUI
+    }
 
   return ovl (profiler.enabled ());
 }
--- a/libinterp/parse-tree/pt-all.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/pt-all.h	Thu Nov 19 13:08:00 2020 -0800
@@ -52,6 +52,7 @@
 #include "pt-misc.h"
 #include "pt-pr-code.h"
 #include "pt-select.h"
+#include "pt-spmd.h"
 #include "pt-stmt.h"
 #include "pt-unop.h"
 #include "pt-pr-code.h"
--- a/libinterp/parse-tree/pt-arg-list.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/pt-arg-list.h	Thu Nov 19 13:08:00 2020 -0800
@@ -116,10 +116,4 @@
   };
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-// tree_argument_list is derived from a template.
-
 #endif
-
-#endif
--- a/libinterp/parse-tree/pt-binop.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/pt-binop.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -137,7 +137,7 @@
 
                 type_info& ti = interp.get_type_info ();
 
-                val = ::do_binary_op (ti, m_etype, a, b);
+                val = binary_op (ti, m_etype, a, b);
               }
           }
       }
--- a/libinterp/parse-tree/pt-cbinop.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/pt-cbinop.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -54,7 +54,7 @@
 
                 type_info& ti = interp.get_type_info ();
 
-                val = ::do_binary_op (ti, m_etype, a, b);
+                val = binary_op (ti, m_etype, a, b);
               }
           }
       }
--- a/libinterp/parse-tree/pt-classdef.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/pt-classdef.h	Thu Nov 19 13:08:00 2020 -0800
@@ -768,7 +768,7 @@
   {
   public:
 
-    tree_classdef (const octave::symbol_scope& scope,
+    tree_classdef (const symbol_scope& scope,
                    tree_classdef_attribute_list *a, tree_identifier *i,
                    tree_classdef_superclass_list *sc,
                    tree_classdef_body *b, comment_list *lc,
@@ -795,7 +795,7 @@
       delete m_trail_comm;
     }
 
-    octave::symbol_scope scope (void) { return m_scope; }
+    symbol_scope scope (void) { return m_scope; }
 
     tree_classdef_attribute_list *
     attribute_list (void) { return m_attr_list; }
@@ -831,7 +831,7 @@
     // corresponds to any identifiers that were found in attribute lists
     // (for example).  Used again when computing the meta class object.
 
-    octave::symbol_scope m_scope;
+    symbol_scope m_scope;
 
     tree_classdef_attribute_list *m_attr_list;
 
@@ -848,10 +848,4 @@
   };
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-// Hmm, a lot of these are templates, so not sure how to typedef them.
-
 #endif
-
-#endif
--- a/libinterp/parse-tree/pt-colon.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/pt-colon.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -57,52 +57,22 @@
     if (! m_base || ! m_limit)
       return val;
 
-    octave_value ov_base = m_base->evaluate (tw);
-
-    octave_value ov_limit = m_limit->evaluate (tw);
-
-    if (ov_base.isobject () || ov_limit.isobject ())
-      {
-        octave_value_list tmp1;
-
-        if (m_increment)
-          {
-            octave_value ov_increment = m_increment->evaluate (tw);
+    octave_value ov_base;
+    octave_value ov_increment;
+    octave_value ov_limit;
 
-            tmp1(2) = ov_limit;
-            tmp1(1) = ov_increment;
-            tmp1(0) = ov_base;
-          }
-        else
-          {
-            tmp1(1) = ov_limit;
-            tmp1(0) = ov_base;
-          }
-
-        interpreter& interp = tw.get_interpreter ();
-
-        symbol_table& symtab = interp.get_symbol_table ();
-
-        octave_value fcn = symtab.find_function ("colon", tmp1);
-
-        if (! fcn.is_defined ())
-          error ("can not find overloaded colon function");
-
-        octave_value_list tmp2 = feval (fcn, tmp1, 1);
-
-        val = tmp2 (0);
+    if (m_increment)
+      {
+        ov_base = m_base->evaluate (tw);
+        ov_increment = m_increment->evaluate (tw);
+        ov_limit = m_limit->evaluate (tw);
       }
     else
       {
-        octave_value ov_increment = 1.0;
-
-        if (m_increment)
-          ov_increment = m_increment->evaluate (tw);
-
-        val = do_colon_op (ov_base, ov_increment, ov_limit,
-                           is_for_cmd_expr ());
+        ov_base = m_base->evaluate (tw);
+        ov_limit = m_limit->evaluate (tw);
       }
 
-    return val;
+    return colon_op (ov_base, ov_increment, ov_limit, is_for_cmd_expr ());
   }
 }
--- a/libinterp/parse-tree/pt-eval.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/pt-eval.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -200,7 +200,8 @@
 
             evmgr.set_workspace ();
 
-            frame.add ([&evmgr, fcn_nm, curr_debug_line] (void) {
+            frame.add ([=, &evmgr] (void)
+                       {
                          evmgr.execute_in_debugger_event (fcn_nm,
                                                           curr_debug_line);
                        });
@@ -618,7 +619,7 @@
                                             const std::string& try_code,
                                             int nargout)
   {
-    unwind_action act ([this] (size_t frm)
+    unwind_action act ([=] (size_t frm)
                        {
                          m_call_stack.restore_frame (frm);
                        }, m_call_stack.current_frame ());
@@ -628,7 +629,7 @@
     else if (context == "base")
       m_call_stack.goto_base_frame ();
     else
-      error ("evalin: CONTEXT must be \"caller\" or \"base\"");
+      error (R"(evalin: CONTEXT must be "caller" or "base")");
 
     int parse_status = 0;
 
@@ -642,7 +643,7 @@
   {
     octave_value_list retval;
 
-    unwind_action act1 ([this] (size_t frm)
+    unwind_action act1 ([=] (size_t frm)
                         {
                           m_call_stack.restore_frame (frm);
                         }, m_call_stack.current_frame ());
@@ -652,7 +653,7 @@
     else if (context == "base")
       m_call_stack.goto_base_frame ();
     else
-      error ("evalin: CONTEXT must be \"caller\" or \"base\"");
+      error (R"(evalin: CONTEXT must be "caller" or "base")");
 
     error_system& es = m_interpreter.get_error_system ();
 
@@ -828,7 +829,7 @@
 
     m_debugger_stack.push (dbgr);
 
-    frame.add ([this] (void)
+    frame.add ([=] (void)
                {
                  delete m_debugger_stack.top ();
                  m_debugger_stack.pop ();
@@ -1403,7 +1404,7 @@
     // by getting a reference to the caller or base stack frame and
     // calling assign on that?
 
-    unwind_action act ([this] (size_t frm)
+    unwind_action act ([=] (size_t frm)
                        {
                          m_call_stack.restore_frame (frm);
                        }, m_call_stack.current_frame ());
@@ -1413,7 +1414,7 @@
     else if (context == "base")
       m_call_stack.goto_base_frame ();
     else
-      error ("assignin: CONTEXT must be \"caller\" or \"base\"");
+      error (R"(assignin: CONTEXT must be "caller" or "base")");
 
     if (valid_identifier (name))
       {
@@ -1503,7 +1504,7 @@
         else if (context == "base")
           m_call_stack.goto_base_frame ();
         else
-          error ("source: context must be \"caller\" or \"base\"");
+          error (R"(source: CONTEXT must be "caller" or "base")");
       }
 
     // Find symbol name that would be in symbol_table, if it were loaded.
@@ -2409,6 +2410,36 @@
       }
   }
 
+  template <typename T>
+  void
+  tree_evaluator::execute_range_loop (const range<T>& rng, size_t line,
+                                      octave_lvalue& ult,
+                                      tree_statement_list *loop_body)
+  {
+    octave_idx_type steps = rng.numel ();
+
+    if (math::isinf (rng.limit ()))
+      warning_with_id ("Octave:infinite-loop",
+                       "FOR loop limit is infinite, will stop after %"
+                       OCTAVE_IDX_TYPE_FORMAT " steps", steps);
+
+    for (octave_idx_type i = 0; i < steps; i++)
+      {
+        if (m_echo_state)
+          m_echo_file_pos = line;
+
+        octave_value val (rng.elem (i));
+
+        ult.assign (octave_value::op_asn_eq, val);
+
+        if (loop_body)
+          loop_body->accept (*this);
+
+        if (quit_loop_now ())
+          break;
+      }
+  }
+
   void
   tree_evaluator::visit_simple_for_command (tree_simple_for_command& cmd)
   {
@@ -2448,27 +2479,70 @@
 
     if (rhs.is_range ())
       {
-        Range rng = rhs.range_value ();
-
-        octave_idx_type steps = rng.numel ();
-
-        for (octave_idx_type i = 0; i < steps; i++)
+        // FIXME: is there a better way to dispatch here?
+
+        if (rhs.is_double_type ())
+          {
+            execute_range_loop (rhs.range_value (), line, ult, loop_body);
+            return;
+          }
+
+        if (rhs.is_int64_type ())
+          {
+            execute_range_loop (rhs.int64_range_value (), line, ult, loop_body);
+            return;
+          }
+
+        if (rhs.is_uint64_type ())
+          {
+            execute_range_loop (rhs.uint64_range_value (), line, ult, loop_body);
+            return;
+          }
+
+        if (rhs.is_int32_type ())
+          {
+            execute_range_loop (rhs.int32_range_value (), line, ult, loop_body);
+            return;
+          }
+
+        if (rhs.is_uint32_type ())
           {
-            if (m_echo_state)
-              m_echo_file_pos = line;
-
-            octave_value val (rng.elem (i));
-
-            ult.assign (octave_value::op_asn_eq, val);
-
-            if (loop_body)
-              loop_body->accept (*this);
-
-            if (quit_loop_now ())
-              break;
+            execute_range_loop (rhs.uint32_range_value (), line, ult, loop_body);
+            return;
+          }
+
+        if (rhs.is_int16_type ())
+          {
+            execute_range_loop (rhs.int16_range_value (), line, ult, loop_body);
+            return;
+          }
+
+        if (rhs.is_uint16_type ())
+          {
+            execute_range_loop (rhs.uint16_range_value (), line, ult, loop_body);
+            return;
+          }
+
+        if (rhs.is_int8_type ())
+          {
+            execute_range_loop (rhs.int8_range_value (), line, ult, loop_body);
+            return;
+          }
+
+        if (rhs.is_uint8_type ())
+          {
+            execute_range_loop (rhs.uint8_range_value (), line, ult, loop_body);
+            return;
+          }
+
+        if (rhs.is_single_type ())
+          {
+            execute_range_loop (rhs.float_range_value (), line, ult, loop_body);
+            return;
           }
       }
-    else if (rhs.is_scalar_type ())
+
+    if (rhs.is_scalar_type ())
       {
         if (m_echo_state)
           m_echo_file_pos = line;
@@ -2480,9 +2554,15 @@
 
         // Maybe decrement break and continue states.
         quit_loop_now ();
+
+        return;
       }
-    else if (rhs.is_matrix_type () || rhs.iscell () || rhs.is_string ()
-             || rhs.isstruct ())
+
+    // Also handle any range types not explicitly handled above, though
+    // not as efficiently as the specialized code above.
+
+    if (rhs.is_range () || rhs.is_matrix_type () || rhs.iscell ()
+        || rhs.is_string () || rhs.isstruct ())
       {
         // A matrix or cell is reshaped to 2 dimensions and iterated by
         // columns.
@@ -2519,9 +2599,9 @@
                 if (m_echo_state)
                   m_echo_file_pos = line;
 
-                // do_index_op expects one-based indices.
+                // index_op expects one-based indices.
                 idx(iidx) = i;
-                octave_value val = arg.do_index_op (idx);
+                octave_value val = arg.index_op (idx);
 
                 ult.assign (octave_value::op_asn_eq, val);
 
@@ -2537,10 +2617,12 @@
             // Handle empty cases, while still assigning to loop var.
             ult.assign (octave_value::op_asn_eq, arg);
           }
+
+        return;
       }
-    else
-      error ("invalid type in for loop expression near line %d, column %d",
-             cmd.line (), cmd.column ());
+
+    error ("invalid type in for loop expression near line %d, column %d",
+           cmd.line (), cmd.column ());
   }
 
   void
@@ -2617,6 +2699,16 @@
       }
   }
 
+  void tree_evaluator::visit_spmd_command (tree_spmd_command& cmd)
+  {
+    // For now, we just execute the commands serially.
+
+    tree_statement_list *body = cmd.body ();
+
+    if (body)
+      body->accept (*this);
+  }
+
   void
   tree_evaluator::visit_octave_user_script (octave_user_script&)
   {
@@ -2641,6 +2733,9 @@
     if (! cmd_list)
       return retval;
 
+    // FIXME: Maybe this check belongs in the places where we push a new
+    // stack frame?  Or in the call_stack push method itself?
+
     if (m_call_stack.size () >= static_cast<size_t> (m_max_recursion_depth))
       error ("max_recursion_depth exceeded");
 
@@ -2676,53 +2771,75 @@
   {
     octave_value_list retval;
 
-    tree_statement_list *cmd_list = user_function.body ();
-
-    if (! cmd_list)
-      return retval;
-
     // If this function is a classdef constructor, extract the first input
     // argument, which must be the partially constructed object instance.
 
     octave_value_list args (xargs);
     octave_value_list ret_args;
 
+    int nargin = args.length ();
+
     if (user_function.is_classdef_constructor ())
       {
-        if (args.length () > 0)
+        if (nargin > 0)
           {
             ret_args = args.slice (0, 1, true);
-            args = args.slice (1, args.length () - 1, true);
+            --nargin;
+            args = args.slice (1, nargin, true);
           }
         else
           panic_impossible ();
       }
 
+    // FIXME: this probably shouldn't be a double-precision matrix.
+    Matrix ignored_outputs = ignored_fcn_outputs ();
+
+    tree_parameter_list *param_list = user_function.parameter_list ();
+
+    if (param_list)
+      {
+        int max_inputs = param_list->length ();
+
+        if (! param_list->takes_varargs () && nargin > max_inputs)
+          {
+            std::string name = user_function.name ();
+
+            error ("%s: function called with too many inputs", name.c_str ());
+          }
+
+        if (! param_list->varargs_only ())
+          define_parameter_list_from_arg_vector (param_list, args);
+      }
+
+    tree_parameter_list *ret_list = user_function.return_list ();
+
+    if (ret_list && ! ret_list->takes_varargs ())
+      {
+        int max_outputs = ret_list->length ();
+
+        if (nargout > max_outputs)
+          {
+            std::string name = user_function.name ();
+
+            error ("%s: function called with too many outputs", name.c_str ());
+          }
+      }
+
+    // FIXME: Is this in the right place now?
+
 #if defined (HAVE_LLVM)
     if (user_function.is_special_expr ()
         && tree_jit::execute (user_function, args, retval))
       return retval;
 #endif
 
-    if (m_call_stack.size () >= static_cast<size_t> (m_max_recursion_depth))
-      error ("max_recursion_depth exceeded");
-
-    Matrix ignored_outputs = ignored_fcn_outputs ();
-
-    bind_auto_fcn_vars (xargs.name_tags (), ignored_outputs, args.length (),
+    bind_auto_fcn_vars (xargs.name_tags (), ignored_outputs, nargin,
                         nargout, user_function.takes_varargs (),
                         user_function.all_va_args (args));
 
-    tree_parameter_list *param_list = user_function.parameter_list ();
-
-    if (param_list && ! param_list->varargs_only ())
-      define_parameter_list_from_arg_vector (param_list, args);
-
     // For classdef constructor, pre-populate the output arguments
     // with the pre-initialized object instance, extracted above.
 
-    tree_parameter_list *ret_list = user_function.return_list ();
-
     if (user_function.is_classdef_constructor ())
       {
         if (! ret_list)
@@ -2732,6 +2849,12 @@
         define_parameter_list_from_arg_vector (ret_list, ret_args);
       }
 
+    // FIXME: Maybe this check belongs in the places where we push a
+    // new stack frame?  Or in the call_stack push method itself?
+
+    if (m_call_stack.size () >= static_cast<size_t> (m_max_recursion_depth))
+      error ("max_recursion_depth exceeded");
+
     unwind_action act2 ([&user_function] () {
                           user_function.restore_warning_states ();
                         });
@@ -2745,37 +2868,41 @@
                          frame->clear_values ();
                        }, m_call_stack.get_current_stack_frame ());
 
-    {
-      profiler::enter<octave_user_function> block (m_profiler, user_function);
-
-      if (echo ())
-        push_echo_state (tree_evaluator::ECHO_FUNCTIONS,
-                         user_function.fcn_file_name ());
-
-      if (user_function.is_special_expr ())
-        {
-          assert (cmd_list->length () == 1);
-
-          tree_statement *stmt = cmd_list->front ();
-
-          tree_expression *expr = stmt->expression ();
-
-          if (expr)
-            {
-              m_call_stack.set_location (stmt->line (), stmt->column ());
-
-              retval = expr->evaluate_n (*this, nargout);
-            }
-        }
-      else
-        cmd_list->accept (*this);
-    }
-
-    if (m_returning)
-      m_returning = 0;
-
-    if (m_breaking)
-      m_breaking--;
+    tree_statement_list *cmd_list = user_function.body ();
+
+    if (cmd_list)
+      {
+        profiler::enter<octave_user_function>
+          block (m_profiler, user_function);
+
+        if (echo ())
+          push_echo_state (tree_evaluator::ECHO_FUNCTIONS,
+                           user_function.fcn_file_name ());
+
+        if (user_function.is_special_expr ())
+          {
+            assert (cmd_list->length () == 1);
+
+            tree_statement *stmt = cmd_list->front ();
+
+            tree_expression *expr = stmt->expression ();
+
+            if (expr)
+              {
+                m_call_stack.set_location (stmt->line (), stmt->column ());
+
+                retval = expr->evaluate_n (*this, nargout);
+              }
+          }
+        else
+          cmd_list->accept (*this);
+
+        if (m_returning)
+          m_returning = 0;
+
+        if (m_breaking)
+          m_breaking--;
+      }
 
     // Copy return values out.
 
@@ -3523,11 +3650,18 @@
           }
         else
           {
+            // FIXME: Maybe assign could also return the assigned value,
+            // just for convenience?
+
             assign (ans, val);
 
             if (print)
               {
-                octave_value_list args = ovl (val);
+                // Use varval instead of displaying VAL directly so that
+                // we get the right type and value for things like
+                // magic_int values that may mutate when stored.
+
+                octave_value_list args = ovl (varval (ans));
                 args.stash_name_tags (string_vector (ans));
                 feval ("display", args);
               }
@@ -4169,7 +4303,7 @@
             // evaluate the partial expression that the special "end"
             // token applies to in the calling stack frame.
 
-            unwind_action act ([this] (size_t frm)
+            unwind_action act ([=] (size_t frm)
                                {
                                  m_call_stack.restore_frame (frm);
                                }, m_call_stack.current_frame ());
@@ -4382,7 +4516,7 @@
 %! max_recursion_depth (orig_val);
 %! assert (max_recursion_depth (), orig_val);
 
-%!error (max_recursion_depth (1, 2))
+%!error max_recursion_depth (1, 2)
 */
 
 DEFMETHOD (whos_line_format, interp, args, nargout,
@@ -4494,7 +4628,7 @@
 %! silent_functions (orig_val);
 %! assert (silent_functions (), orig_val);
 
-%!error (silent_functions (1, 2))
+%!error silent_functions (1, 2)
 */
 
 DEFMETHOD (string_fill_char, interp, args, nargout,
@@ -4543,7 +4677,7 @@
 
 %!assert ( [ [], {1} ], {1} )
 
-%!error (string_fill_char (1, 2))
+%!error string_fill_char (1, 2)
 */
 
 DEFMETHOD (PS4, interp, args, nargout,
--- a/libinterp/parse-tree/pt-eval.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/pt-eval.h	Thu Nov 19 13:08:00 2020 -0800
@@ -202,6 +202,8 @@
 
     void visit_complex_for_command (tree_complex_for_command&);
 
+    void visit_spmd_command (tree_spmd_command&);
+
     void visit_octave_user_script (octave_user_script&);
 
     octave_value_list
@@ -747,6 +749,11 @@
 
   private:
 
+    template <typename T>
+    void execute_range_loop (const range<T>& rng, size_t line,
+                             octave_lvalue& ult,
+                             tree_statement_list *loop_body);
+
     void set_echo_state (int type, const std::string& file_name, size_t pos);
 
     void maybe_set_echo_state (void);
--- a/libinterp/parse-tree/pt-jit.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/pt-jit.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -715,7 +715,7 @@
       }
     else if (ty == jit_typeinfo::get_range ())
       {
-        Range rv = v.range_value ();
+        range<double> rv = v.range_value ();
         m_result = m_factory.create<jit_const_range> (rv);
       }
     else if (ty == jit_typeinfo::get_complex ())
@@ -2314,7 +2314,7 @@
   {
     if (bounds.is_range ())
       {
-        Range rng = bounds.range_value ();
+        range<double> rng = bounds.range_value ();
         return rng.numel ();
       }
 
--- a/libinterp/parse-tree/pt-misc.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/pt-misc.h	Thu Nov 19 13:08:00 2020 -0800
@@ -115,10 +115,4 @@
   };
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-// tree_parameter_list is derived from a template.
-
 #endif
-
-#endif
--- a/libinterp/parse-tree/pt-pr-code.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/pt-pr-code.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -293,6 +293,35 @@
   }
 
   void
+  tree_print_code::visit_spmd_command (tree_spmd_command& cmd)
+  {
+    print_comment_list (cmd.leading_comment ());
+
+    indent ();
+
+    m_os << "spmd";
+
+    newline ();
+
+    tree_statement_list *list = cmd.body ();
+
+    if (list)
+      {
+        increment_indent_level ();
+
+        list->accept (*this);
+
+        decrement_indent_level ();
+      }
+
+    print_indented_comment (cmd.trailing_comment ());
+
+    indent ();
+
+    m_os << "endspmd";
+  }
+
+  void
   tree_print_code::visit_octave_user_script (octave_user_script& fcn)
   {
     reset ();
--- a/libinterp/parse-tree/pt-pr-code.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/pt-pr-code.h	Thu Nov 19 13:08:00 2020 -0800
@@ -88,6 +88,8 @@
 
     void visit_complex_for_command (tree_complex_for_command&);
 
+    void visit_spmd_command (tree_spmd_command&);
+
     void visit_octave_user_script (octave_user_script&);
 
     void visit_octave_user_function (octave_user_function&);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/parse-tree/pt-spmd.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,42 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include "comment-list.h"
+#include "pt-spmd.h"
+#include "pt-stmt.h"
+
+namespace octave
+{
+  tree_spmd_command::~tree_spmd_command (void)
+  {
+    delete m_body;
+    delete m_lead_comm;
+    delete m_trail_comm;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/parse-tree/pt-spmd.h	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,83 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if ! defined (octave_pt_spmd_command_h)
+#define octave_pt_spmd_command_h 1
+
+#include "octave-config.h"
+
+#include "base-list.h"
+#include "pt-cmd.h"
+#include "pt-walk.h"
+
+namespace octave
+{
+  class tree_comment_list;
+  class tree_statement_list;
+
+  // Spmd.
+
+  class tree_spmd_command : public tree_command
+  {
+  public:
+
+    tree_spmd_command (tree_statement_list *body, comment_list *lc,
+                       comment_list *tc, int l = -1, int c = -1)
+      : tree_command (l, c), m_body (body), m_lead_comm (lc), m_trail_comm (tc)
+    { }
+
+    // No copying!
+
+    tree_spmd_command (const tree_spmd_command&) = delete;
+
+    tree_spmd_command& operator = (const tree_spmd_command&) = delete;
+
+    ~tree_spmd_command (void);
+
+    tree_statement_list * body (void) { return m_body; }
+
+    comment_list * leading_comment (void) { return m_lead_comm; }
+
+    comment_list * trailing_comment (void) { return m_trail_comm; }
+
+    void accept (tree_walker& tw)
+    {
+      tw.visit_spmd_command (*this);
+    }
+
+  private:
+
+    // List of commands.
+    tree_statement_list *m_body;
+
+    // Comment preceding SPMD token.
+    comment_list *m_lead_comm;
+
+    // Comment preceding ENDSPMD token.
+    comment_list *m_trail_comm;
+  };
+}
+
+#endif
--- a/libinterp/parse-tree/pt-tm-const.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/pt-tm-const.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -461,7 +461,7 @@
     // full.  This is done since it means that there is no recopying of
     // data, as would happen if we used a single resize.  It should be
     // noted that resize operation is also significantly slower than the
-    // do_cat_op function, so it makes sense to have an empty matrix and
+    // cat_op function, so it makes sense to have an empty matrix and
     // copy all data.
     //
     // We might also start with a empty octave_value using
@@ -532,7 +532,7 @@
             if (elt.isempty ())
               continue;
 
-            ctmp = do_cat_op (ti, ctmp, elt, ra_idx);
+            ctmp = cat_op (ti, ctmp, elt, ra_idx);
 
             ra_idx (1) += elt.columns ();
           }
--- a/libinterp/parse-tree/pt-unop.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/pt-unop.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -71,7 +71,7 @@
             profiler::enter<tree_prefix_expression>
               block (tw.get_profiler (), *this);
 
-            op_ref.do_unary_op (m_etype);
+            op_ref.unary_op (m_etype);
 
             val = op_ref.value ();
           }
@@ -87,14 +87,14 @@
                 // Attempt to do the operation in-place if it is unshared
                 // (a temporary expression).
                 if (op_val.get_count () == 1)
-                  val = op_val.do_non_const_unary_op (m_etype);
+                  val = op_val.non_const_unary_op (m_etype);
                 else
                   {
                     interpreter& interp = tw.get_interpreter ();
 
                     type_info& ti = interp.get_type_info ();
 
-                    val = ::do_unary_op (ti, m_etype, op_val);
+                    val = unary_op (ti, m_etype, op_val);
                   }
               }
           }
@@ -134,7 +134,7 @@
             profiler::enter<tree_postfix_expression>
               block (tw.get_profiler (), *this);
 
-            ref.do_unary_op (m_etype);
+            ref.unary_op (m_etype);
           }
         else
           {
@@ -149,7 +149,7 @@
 
                 type_info& ti = interp.get_type_info ();
 
-                val = ::do_unary_op (ti, m_etype, op_val);
+                val = unary_op (ti, m_etype, op_val);
               }
           }
       }
--- a/libinterp/parse-tree/pt-walk.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/pt-walk.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -174,6 +174,14 @@
       list->accept (*this);
   }
 
+  void tree_walker::visit_spmd_command (tree_spmd_command& cmd)
+  {
+    tree_statement_list *body = cmd.body ();
+
+    if (body)
+      body->accept (*this);
+  }
+
   void tree_walker::visit_octave_user_script (octave_user_script& fcn)
   {
     tree_statement_list *cmd_list = fcn.body ();
--- a/libinterp/parse-tree/pt-walk.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/pt-walk.h	Thu Nov 19 13:08:00 2020 -0800
@@ -53,6 +53,7 @@
   class tree_decl_elt;
   class tree_simple_for_command;
   class tree_complex_for_command;
+  class tree_spmd_command;
   class tree_function_def;
   class tree_identifier;
   class tree_if_clause;
@@ -142,6 +143,8 @@
 
     virtual void visit_complex_for_command (tree_complex_for_command&);
 
+    virtual void visit_spmd_command (tree_spmd_command&);
+
     virtual void visit_octave_user_script (octave_user_script&);
 
     virtual void visit_octave_user_function (octave_user_function&);
--- a/libinterp/parse-tree/token.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/token.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -62,11 +62,11 @@
       m_tok_info (s), m_orig_text ()
   { }
 
-  token::token (int tv, double d, const std::string& s, const filepos& beg_pos,
-                const filepos& end_pos)
+  token::token (int tv, const octave_value& val, const std::string& s,
+                const filepos& beg_pos, const filepos& end_pos)
     : m_maybe_cmd (false), m_tspc (false), m_beg_pos (beg_pos),
-      m_end_pos (end_pos), m_tok_val (tv), m_type_tag (double_token),
-      m_tok_info (d), m_orig_text (s)
+      m_end_pos (end_pos), m_tok_val (tv), m_type_tag (numeric_token),
+      m_tok_info (val), m_orig_text (s)
   { }
 
   token::token (int tv, end_tok_type t, const filepos& beg_pos,
@@ -114,11 +114,11 @@
     return m_tok_info.m_sr->name ();
   }
 
-  double
+  octave_value
   token::number (void) const
   {
-    assert (m_type_tag == double_token);
-    return m_tok_info.m_num;
+    assert (m_type_tag == numeric_token);
+    return *m_tok_info.m_num;
   }
 
   token::token_type
--- a/libinterp/parse-tree/token.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/libinterp/parse-tree/token.h	Thu Nov 19 13:08:00 2020 -0800
@@ -31,6 +31,7 @@
 #include <string>
 
 #include "filepos.h"
+#include "ov.h"
 #include "symrec.h"
 
 namespace octave
@@ -44,7 +45,7 @@
       generic_token,
       keyword_token,
       string_token,
-      double_token,
+      numeric_token,
       ettype_token,
       sym_rec_token,
       scls_name_token,
@@ -65,6 +66,7 @@
       switch_end,
       try_catch_end,
       unwind_protect_end,
+      spmd_end,
       while_end,
     };
 
@@ -79,8 +81,8 @@
     token (int tv, const std::string& s, const filepos& beg_pos,
            const filepos& end_pos);
 
-    token (int tv, double d, const std::string& s, const filepos& beg_pos,
-           const filepos& end_pos);
+    token (int tv, const octave_value& val, const std::string& s,
+           const filepos& beg_pos, const filepos& end_pos);
 
     token (int tv, end_tok_type t, const filepos& beg_pos,
            const filepos& end_pos);
@@ -123,12 +125,6 @@
       return m_type_tag == keyword_token || m_type_tag == ettype_token;
     }
 
-    OCTAVE_DEPRECATED (5, "use 'octave::iskeyword' instead")
-    bool is_keyword (void) const
-    {
-      return iskeyword ();
-    }
-
     bool is_symbol (void) const
     {
       return m_type_tag == sym_rec_token;
@@ -136,7 +132,7 @@
 
     std::string text (void) const;
     std::string symbol_name (void) const;
-    double number (void) const;
+    octave_value number (void) const;
     token_type ttype (void) const;
     end_tok_type ettype (void) const;
     symbol_record sym_rec (void) const;
@@ -167,7 +163,7 @@
 
       tok_info (const std::string& str) : m_str (new std::string (str)) { }
 
-      tok_info (double num) : m_num (num) { }
+      tok_info (const octave_value& num) : m_num (new octave_value (num)) { }
 
       tok_info (end_tok_type et) : m_et (et) { }
 
@@ -187,7 +183,7 @@
 
       std::string *m_str;
 
-      double m_num;
+      octave_value *m_num;
 
       end_tok_type m_et;
 
--- a/liboctave/array/CMatrix.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/array/CMatrix.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -3168,7 +3168,7 @@
       for (octave_idx_type j = 0; j < a.cols (); j++)
         {
           os << ' ';
-          octave_write_complex (os, a.elem (i, j));
+          octave::write_value<Complex> (os, a.elem (i, j));
         }
       os << "\n";
     }
@@ -3187,7 +3187,7 @@
       for (octave_idx_type i = 0; i < nr; i++)
         for (octave_idx_type j = 0; j < nc; j++)
           {
-            tmp = octave_read_value<Complex> (is);
+            tmp = octave::read_value<Complex> (is);
             if (is)
               a.elem (i, j) = tmp;
             else
--- a/liboctave/array/CNDArray.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/array/CNDArray.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -601,7 +601,7 @@
   for (octave_idx_type i = 0; i < nel; i++)
     {
       os << ' ';
-      octave_write_complex (os, a.elem (i));
+      octave::write_value<Complex> (os, a.elem (i));
       os << "\n";
     }
   return os;
@@ -617,7 +617,7 @@
       Complex tmp;
       for (octave_idx_type i = 0; i < nel; i++)
         {
-          tmp = octave_read_value<Complex> (is);
+          tmp = octave::read_value<Complex> (is);
           if (is)
             a.elem (i) = tmp;
           else
--- a/liboctave/array/CSparse.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/array/CSparse.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -7487,7 +7487,7 @@
       for (octave_idx_type i = a.cidx (j); i < a.cidx (j+1); i++)
         {
           os << a.ridx (i) + 1 << ' '  << j + 1 << ' ';
-          octave_write_complex (os, a.data (i));
+          octave::write_value<Complex> (os, a.data (i));
           os << "\n";
         }
     }
@@ -7500,7 +7500,7 @@
 {
   typedef SparseComplexMatrix::element_type elt_type;
 
-  return read_sparse_matrix<elt_type> (is, a, octave_read_value<Complex>);
+  return read_sparse_matrix<elt_type> (is, a, octave::read_value<Complex>);
 }
 
 SparseComplexMatrix
--- a/liboctave/array/Range.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/array/Range.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -39,6 +39,225 @@
 #include "lo-mappers.h"
 #include "lo-utils.h"
 
+namespace octave
+{
+  template <typename T>
+  T xtfloor (T x, T ct)
+  {
+    // C---------FLOOR(X) is the largest integer algebraically less than
+    // C         or equal to X; that is, the unfuzzy FLOOR function.
+
+    //  DINT (X) = X - DMOD (X, 1.0);
+    //  FLOOR (X) = DINT (X) - DMOD (2.0 + DSIGN (1.0, X), 3.0);
+
+    // C---------Hagerty's FL5 function follows...
+
+    T q = 1;
+
+    if (x < 0)
+      q = 1 - ct;
+
+    T rmax = q / (2 - ct);
+
+    T t1 = 1 + std::floor (x);
+    t1 = (ct / q) * (t1 < 0 ? -t1 : t1);
+    t1 = (rmax < t1 ? rmax : t1);
+    t1 = (ct > t1 ? ct : t1);
+    t1 = std::floor (x + t1);
+
+    if (x <= 0 || (t1 - x) < rmax)
+      return t1;
+    else
+      return t1 - 1;
+  }
+
+  template <typename T>
+  bool xteq (T u, T v, T ct = 3 * std::numeric_limits<T>::epsilon ())
+  {
+    T tu = std::abs (u);
+    T tv = std::abs (v);
+
+    return std::abs (u - v) < ((tu > tv ? tu : tv) * ct);
+  }
+
+  template <typename T>
+  octave_idx_type xnumel_internal (T base, T limit, T inc)
+  {
+    octave_idx_type retval = -1;
+    if (! math::isfinite (base) || ! math::isfinite (inc)
+        || math::isnan (limit))
+      retval = -2;
+    else if (math::isinf (limit)
+             && ((inc > 0 && limit > 0)
+                 || (inc < 0 && limit < 0)))
+      retval = std::numeric_limits<octave_idx_type>::max () - 1;
+    else if (inc == 0
+             || (limit > base && inc < 0)
+             || (limit < base && inc > 0))
+      {
+        retval = 0;
+      }
+    else
+      {
+        T ct = 3 * std::numeric_limits<T>::epsilon ();
+
+        T tmp = xtfloor ((limit - base + inc) / inc, ct);
+
+        octave_idx_type n_elt
+          = (tmp > 0 ? static_cast<octave_idx_type> (tmp) : 0);
+
+        // If the final element that we would compute for the range is
+        // equal to the limit of the range, or is an adjacent floating
+        // point number, accept it.  Otherwise, try a range with one
+        // fewer element.  If that fails, try again with one more
+        // element.
+        //
+        // I'm not sure this is very good, but it seems to work better
+        // than just using tfloor as above.  For example, without it,
+        // the expression 1.8:0.05:1.9 fails to produce the expected
+        // result of [1.8, 1.85, 1.9].
+
+        if (! xteq (base + (n_elt - 1) * inc, limit))
+          {
+            if (xteq (base + (n_elt - 2) * inc, limit))
+              n_elt--;
+            else if (xteq (base + n_elt * inc, limit))
+              n_elt++;
+          }
+
+        retval = (n_elt < std::numeric_limits<octave_idx_type>::max () - 1
+                  ? n_elt : -1);
+      }
+
+    return retval;
+  }
+
+  template <typename T>
+  bool xall_elements_are_ints (T base, T inc, octave_idx_type nel)
+  {
+    // If the base and increment are ints, the final value in the range
+    // will also be an integer, even if the limit is not.  If the range
+    // has only one or zero elements, then the base needs to be an integer.
+
+    return (! (math::isnan (base) || math::isnan (inc))
+            && (math::nint_big (base) == base || nel < 1)
+            && (math::nint_big (inc) == inc || nel <= 1));
+  }
+
+  template <typename T>
+  T
+  xfinal_value (T base, T limit, T inc, octave_idx_type nel)
+  {
+    T retval = T (0);
+
+    if (nel <= 1)
+      return base;
+
+    // If increment is 0, then numel should also be zero.
+
+    retval = base + (nel - 1) * inc;
+
+    // On some machines (x86 with extended precision floating point
+    // arithmetic, for example) it is possible that we can overshoot
+    // the limit by approximately the machine precision even though
+    // we were very careful in our calculation of the number of
+    // elements.  Therefore, we clip the result to the limit if it
+    // overshoots.
+
+    // NOTE: The test also includes equality (>= limit) to have
+    // expressions such as -5:1:-0 result in a -0 endpoint.
+
+    if ((inc > T (0) && retval >= limit) || (inc < T (0) && retval <= limit))
+      retval = limit;
+
+    // If all elements are integers, then ensure the final value is.
+
+    if (xall_elements_are_ints (base, inc, nel))
+      retval = std::round (retval);
+
+    return retval;
+  }
+
+  template <>
+  bool
+  range<double>::all_elements_are_ints (void) const
+  {
+    return xall_elements_are_ints (m_base, m_increment, m_numel);
+  }
+
+  template <>
+  bool
+  range<float>::all_elements_are_ints (void) const
+  {
+    return xall_elements_are_ints (m_base, m_increment, m_numel);
+  }
+
+  template <>
+  octave_idx_type
+  range<double>::get_numel (void) const
+  {
+    return xnumel_internal (m_base, m_limit, m_increment);
+  }
+
+  template <>
+  octave_idx_type
+  range<float>::get_numel (void) const
+  {
+    return xnumel_internal (m_base, m_limit, m_increment);
+  }
+
+  template <>
+  double
+  range<double>::get_final_value (void) const
+  {
+    return xfinal_value (m_base, m_limit, m_increment, m_numel);
+  }
+
+  template <>
+  float
+  range<float>::get_final_value (void) const
+  {
+    return xfinal_value (m_base, m_limit, m_increment, m_numel);
+  }
+
+  template <>
+  octave_idx_type
+  range<double>::nnz (void) const
+  {
+    octave_idx_type retval = 0;
+
+    if (! isempty ())
+      {
+        if ((m_base > 0 && m_limit > 0)
+            || (m_base < 0 && m_limit < 0))
+          {
+            // All elements have the same sign, hence there are no zeros.
+            retval = m_numel;
+          }
+        else if (m_increment != 0)
+          {
+            if (m_base == 0 || m_limit == 0)
+              // Exactly one zero at beginning or end of range.
+              retval = m_numel - 1;
+            else if (math::mod (-m_base, m_increment) != 0)
+              // Range crosses negative/positive without hitting zero.
+              retval = m_numel;
+            else
+              // Range crosses negative/positive and hits zero.
+              retval = m_numel - 1;
+          }
+        else
+          {
+            // All elements are equal (m_increment = 0) but not
+            // positive or negative, therefore all elements are zero.
+            retval = 0;
+          }
+      }
+
+    return retval;
+  }
+}
+
 bool
 Range::all_elements_are_ints (void) const
 {
@@ -46,9 +265,9 @@
   // be an integer, even if the limit is not.  If there is one or fewer
   // elements only the base needs to be an integer.
 
-  return (! (octave::math::isnan (rng_base) || octave::math::isnan (rng_inc))
-          && (octave::math::nint_big (rng_base) == rng_base || rng_numel < 1)
-          && (octave::math::nint_big (rng_inc) == rng_inc || rng_numel <= 1));
+  return (! (octave::math::isnan (m_base) || octave::math::isnan (m_inc))
+          && (octave::math::nint_big (m_base) == m_base || m_numel < 1)
+          && (octave::math::nint_big (m_inc) == m_inc || m_numel <= 1));
 }
 
 octave_idx_type
@@ -58,27 +277,26 @@
 
   if (! isempty ())
     {
-      if ((rng_base > 0.0 && rng_limit > 0.0)
-          || (rng_base < 0.0 && rng_limit < 0.0))
+      if ((m_base > 0.0 && m_limit > 0.0) || (m_base < 0.0 && m_limit < 0.0))
         {
           // All elements have the same sign, hence there are no zeros.
-          retval = rng_numel;
+          retval = m_numel;
         }
-      else if (rng_inc != 0.0)
+      else if (m_inc != 0.0)
         {
-          if (rng_base == 0.0 || rng_limit == 0.0)
+          if (m_base == 0.0 || m_limit == 0.0)
             // Exactly one zero at beginning or end of range.
-            retval = rng_numel - 1;
-          else if ((rng_base / rng_inc) != std::floor (rng_base / rng_inc))
+            retval = m_numel - 1;
+          else if ((m_base / m_inc) != std::floor (m_base / m_inc))
             // Range crosses negative/positive without hitting zero.
-            retval = rng_numel;
+            retval = m_numel;
           else
             // Range crosses negative/positive and hits zero.
-            retval = rng_numel - 1;
+            retval = m_numel - 1;
         }
       else
         {
-          // All elements are equal (rng_inc = 0) but not positive or negative,
+          // All elements are equal (m_inc = 0) but not positive or negative,
           // therefore all elements are zero.
           retval = 0;
         }
@@ -90,37 +308,37 @@
 Matrix
 Range::matrix_value (void) const
 {
-  if (rng_numel > 0 && cache.isempty ())
+  Matrix retval (1, m_numel);
+
+  if (m_numel > 0)
     {
-      cache.resize (1, rng_numel);
-
       // The first element must always be *exactly* the base.
       // E.g, -0 would otherwise become +0 in the loop (-0 + 0*increment).
-      cache(0) = rng_base;
+      retval(0) = m_base;
 
-      double b = rng_base;
-      double increment = rng_inc;
-      for (octave_idx_type i = 1; i < rng_numel - 1; i++)
-        cache.xelem (i) = b + i * increment;
+      double b = m_base;
+      double increment = m_inc;
+      for (octave_idx_type i = 1; i < m_numel - 1; i++)
+        retval.xelem (i) = b + i * increment;
 
-      cache.xelem (rng_numel - 1) = rng_limit;
+      retval.xelem (m_numel - 1) = m_limit;
     }
 
-  return cache;
+  return retval;
 }
 
 double
 Range::checkelem (octave_idx_type i) const
 {
-  if (i < 0 || i >= rng_numel)
-    octave::err_index_out_of_range (2, 2, i+1, rng_numel, dims ());
+  if (i < 0 || i >= m_numel)
+    octave::err_index_out_of_range (2, 2, i+1, m_numel, dims ());
 
   if (i == 0)
-    return rng_base;
-  else if (i < rng_numel - 1)
-    return rng_base + i * rng_inc;
+    return m_base;
+  else if (i < m_numel - 1)
+    return m_base + i * m_inc;
   else
-    return rng_limit;
+    return m_limit;
 }
 
 double
@@ -128,7 +346,7 @@
 {
   // Ranges are *always* row vectors.
   if (i != 0)
-    octave::err_index_out_of_range (1, 1, i+1, rng_numel, dims ());
+    octave::err_index_out_of_range (1, 1, i+1, m_numel, dims ());
 
   return checkelem (j);
 }
@@ -137,11 +355,11 @@
 Range::elem (octave_idx_type i) const
 {
   if (i == 0)
-    return rng_base;
-  else if (i < rng_numel - 1)
-    return rng_base + i * rng_inc;
+    return m_base;
+  else if (i < m_numel - 1)
+    return m_base + i * m_inc;
   else
-    return rng_limit;
+    return m_limit;
 }
 
 // Helper class used solely for idx_vector.loop () function call
@@ -173,11 +391,11 @@
 {
   Array<double> retval;
 
-  octave_idx_type n = rng_numel;
+  octave_idx_type n = m_numel;
 
   if (i.is_colon ())
     {
-      retval = matrix_value ().reshape (dim_vector (rng_numel, 1));
+      retval = matrix_value ().reshape (dim_vector (m_numel, 1));
     }
   else
     {
@@ -196,7 +414,7 @@
       // idx_vector loop across all values in i,
       // executing __rangeidx_helper (i) for each i
       i.loop (n, __rangeidx_helper (retval.fortran_vec (),
-                                    rng_base, rng_inc, rng_limit, rng_numel));
+                                    m_base, m_inc, m_limit, m_numel));
     }
 
   return retval;
@@ -209,17 +427,17 @@
 Range::min (void) const
 {
   double retval = 0.0;
-  if (rng_numel > 0)
+  if (m_numel > 0)
     {
-      if (rng_inc > 0)
-        retval = rng_base;
+      if (m_inc > 0)
+        retval = m_base;
       else
         {
-          retval = rng_base + (rng_numel - 1) * rng_inc;
+          retval = m_base + (m_numel - 1) * m_inc;
 
           // Require '<=' test.  See note in max ().
-          if (retval <= rng_limit)
-            retval = rng_limit;
+          if (retval <= m_limit)
+            retval = m_limit;
         }
 
     }
@@ -230,24 +448,24 @@
 Range::max (void) const
 {
   double retval = 0.0;
-  if (rng_numel > 0)
+  if (m_numel > 0)
     {
-      if (rng_inc > 0)
+      if (m_inc > 0)
         {
-          retval = rng_base + (rng_numel - 1) * rng_inc;
+          retval = m_base + (m_numel - 1) * m_inc;
 
           // On some machines (x86 with extended precision floating point
           // arithmetic, for example) it is possible that we can overshoot the
           // limit by approximately the machine precision even though we were
           // very careful in our calculation of the number of elements.
           // Therefore, we clip the result to the limit if it overshoots.
-          // The test also includes equality (>= rng_limit) to have expressions
+          // The test also includes equality (>= m_limit) to have expressions
           // such as -5:1:-0 result in a -0 endpoint.
-          if (retval >= rng_limit)
-            retval = rng_limit;
+          if (retval >= m_limit)
+            retval = m_limit;
         }
       else
-        retval = rng_base;
+        retval = m_base;
     }
   return retval;
 }
@@ -255,12 +473,11 @@
 void
 Range::sort_internal (bool ascending)
 {
-  if ((ascending && rng_base > rng_limit && rng_inc < 0.0)
-      || (! ascending && rng_base < rng_limit && rng_inc > 0.0))
+  if ((ascending && m_base > m_limit && m_inc < 0.0)
+      || (! ascending && m_base < m_limit && m_inc > 0.0))
     {
-      std::swap (rng_base, rng_limit);
-      rng_inc = -rng_inc;
-      clear_cache ();
+      std::swap (m_base, m_limit);
+      m_inc = -m_inc;
     }
 }
 
@@ -275,12 +492,11 @@
 
   bool reverse = false;
 
-  if ((ascending && rng_base > rng_limit && rng_inc < 0.0)
-      || (! ascending && rng_base < rng_limit && rng_inc > 0.0))
+  if ((ascending && m_base > m_limit && m_inc < 0.0)
+      || (! ascending && m_base < m_limit && m_inc > 0.0))
     {
-      std::swap (rng_base, rng_limit);
-      rng_inc = -rng_inc;
-      clear_cache ();
+      std::swap (m_base, m_limit);
+      m_inc = -m_inc;
       reverse = true;
     }
 
@@ -337,9 +553,9 @@
 sortmode
 Range::issorted (sortmode mode) const
 {
-  if (rng_numel > 1 && rng_inc > 0)
+  if (m_numel > 1 && m_inc > 0)
     mode = (mode == DESCENDING) ? UNSORTED : ASCENDING;
-  else if (rng_numel > 1 && rng_inc < 0)
+  else if (m_numel > 1 && m_inc < 0)
     mode = (mode == ASCENDING) ? UNSORTED : DESCENDING;
   else
     mode = (mode == UNSORTED) ? ASCENDING : mode;
@@ -350,9 +566,9 @@
 void
 Range::set_base (double b)
 {
-  if (rng_base != b)
+  if (m_base != b)
     {
-      rng_base = b;
+      m_base = b;
 
       init ();
     }
@@ -361,9 +577,9 @@
 void
 Range::set_limit (double l)
 {
-  if (rng_limit != l)
+  if (m_limit != l)
     {
-      rng_limit = l;
+      m_limit = l;
 
       init ();
     }
@@ -372,9 +588,9 @@
 void
 Range::set_inc (double i)
 {
-  if (rng_inc != i)
+  if (m_inc != i)
     {
-      rng_inc = i;
+      m_inc = i;
 
       init ();
     }
@@ -384,7 +600,7 @@
 operator << (std::ostream& os, const Range& a)
 {
   double b = a.base ();
-  double increment = a.inc ();
+  double increment = a.increment ();
   octave_idx_type nel = a.numel ();
 
   if (nel > 1)
@@ -396,7 +612,7 @@
     }
 
   // Print out the last element exactly, rather than a calculated last element.
-  os << a.rng_limit << "\n";
+  os << a.m_limit << "\n";
 
   return os;
 }
@@ -404,17 +620,17 @@
 std::istream&
 operator >> (std::istream& is, Range& a)
 {
-  is >> a.rng_base;
+  is >> a.m_base;
   if (is)
     {
-      double tmp_rng_limit;
-      is >> tmp_rng_limit;
+      double tmp_limit;
+      is >> tmp_limit;
 
       if (is)
-        is >> a.rng_inc;
+        is >> a.m_inc;
 
-      // Clip the rng_limit to the true limit, rebuild numel, clear cache
-      a.set_limit (tmp_rng_limit);
+      // Clip the m_limit to the true limit, rebuild numel, clear cache
+      a.set_limit (tmp_limit);
     }
 
   return is;
@@ -423,64 +639,37 @@
 Range
 operator - (const Range& r)
 {
-  return Range (-r.base (), -r.limit (), -r.inc (), r.numel ());
+  return Range (-r.base (), -r.limit (), -r.increment (), r.numel ());
 }
 
 Range operator + (double x, const Range& r)
 {
-  Range result (x + r.base (), x + r.limit (), r.inc (), r.numel ());
-  // Check whether new range was constructed properly.  A non-finite
-  // value (Inf or NaN) requires that the output be of the same size
-  // as the original range with all values set to the non-finite value.
-  if (result.rng_numel < 0)
-    result.cache = x + r.matrix_value ();
-
-  return result;
+  return Range (x + r.base (), x + r.limit (), r.increment (), r.numel ());
 }
 
 Range operator + (const Range& r, double x)
 {
-  Range result (r.base () + x, r.limit () + x, r.inc (), r.numel ());
-  if (result.rng_numel < 0)
-    result.cache = r.matrix_value () + x;
-
-  return result;
+  return Range (r.base () + x, r.limit () + x, r.increment (), r.numel ());
 }
 
 Range operator - (double x, const Range& r)
 {
-  Range result (x - r.base (), x - r.limit (), -r.inc (), r.numel ());
-  if (result.rng_numel < 0)
-    result.cache = x - r.matrix_value ();
-
-  return result;
+  return Range (x - r.base (), x - r.limit (), -r.increment (), r.numel ());
 }
 
 Range operator - (const Range& r, double x)
 {
-  Range result (r.base () - x, r.limit () - x, r.inc (), r.numel ());
-  if (result.rng_numel < 0)
-    result.cache = r.matrix_value () - x;
-
-  return result;
+  return Range (r.base () - x, r.limit () - x, r.increment (), r.numel ());
 }
 
 Range operator * (double x, const Range& r)
 {
-  Range result (x * r.base (), x * r.limit (), x * r.inc (), r.numel ());
-  if (result.rng_numel < 0)
-    result.cache = x * r.matrix_value ();
-
-  return result;
+  return Range (x * r.base (), x * r.limit (), x * r.increment (), r.numel ());
 }
 
 Range operator * (const Range& r, double x)
 {
-  Range result (r.base () * x, r.limit () * x, r.inc () * x, r.numel ());
-  if (result.rng_numel < 0)
-    result.cache = r.matrix_value () * x;
-
-  return result;
+  return Range (r.base () * x, r.limit () * x, r.increment () * x, r.numel ());
 }
 
 // C  See Knuth, Art Of Computer Programming, Vol. 1, Problem 1.2.4-5.
@@ -560,9 +749,16 @@
 {
   octave_idx_type retval = -1;
 
-  if (rng_inc == 0
-      || (rng_limit > rng_base && rng_inc < 0)
-      || (rng_limit < rng_base && rng_inc > 0))
+  if (! octave::math::isfinite (m_base) || ! octave::math::isfinite (m_inc)
+      || octave::math::isnan (m_limit))
+    retval = -2;
+  else if (octave::math::isinf (m_limit)
+           && ((m_inc > 0 && m_limit > 0)
+               || (m_inc < 0 && m_limit < 0)))
+    retval = std::numeric_limits<octave_idx_type>::max () - 1;
+  else if (m_inc == 0
+           || (m_limit > m_base && m_inc < 0)
+           || (m_limit < m_base && m_inc > 0))
     {
       retval = 0;
     }
@@ -570,10 +766,10 @@
     {
       double ct = 3.0 * std::numeric_limits<double>::epsilon ();
 
-      double tmp = tfloor ((rng_limit - rng_base + rng_inc) / rng_inc, ct);
+      double tmp = tfloor ((m_limit - m_base + m_inc) / m_inc, ct);
 
-      octave_idx_type n_elt = (tmp > 0.0 ? static_cast<octave_idx_type> (tmp)
-                                         : 0);
+      octave_idx_type n_elt = (tmp > 0.0
+                               ? static_cast<octave_idx_type> (tmp) : 0);
 
       // If the final element that we would compute for the range is equal to
       // the limit of the range, or is an adjacent floating point number,
@@ -584,16 +780,16 @@
       // using tfloor as above.  For example, without it, the expression
       // 1.8:0.05:1.9 fails to produce the expected result of [1.8, 1.85, 1.9].
 
-      if (! teq (rng_base + (n_elt - 1) * rng_inc, rng_limit))
+      if (! teq (m_base + (n_elt - 1) * m_inc, m_limit))
         {
-          if (teq (rng_base + (n_elt - 2) * rng_inc, rng_limit))
+          if (teq (m_base + (n_elt - 2) * m_inc, m_limit))
             n_elt--;
-          else if (teq (rng_base + n_elt * rng_inc, rng_limit))
+          else if (teq (m_base + n_elt * m_inc, m_limit))
             n_elt++;
         }
 
-      retval = (n_elt < std::numeric_limits<octave_idx_type>::max () - 1)
-               ? n_elt : -1;
+      retval = ((n_elt < std::numeric_limits<octave_idx_type>::max ())
+                ? n_elt : -1);
     }
 
   return retval;
@@ -602,12 +798,7 @@
 double
 Range::limit_internal (void) const
 {
-  double new_limit;
-
-  if (rng_inc > 0)
-    new_limit = max ();
-  else
-    new_limit = min ();
+  double new_limit = m_inc > 0 ? max () : min ();
 
   // If result must be an integer then force the new_limit to be one.
   if (all_elements_are_ints ())
@@ -619,8 +810,8 @@
 void
 Range::init (void)
 {
-  rng_numel = numel_internal ();
-  rng_limit = limit_internal ();
+  m_numel = numel_internal ();
 
-  clear_cache ();
+  if (! octave::math::isinf (m_limit))
+    m_limit = limit_internal ();
 }
--- a/liboctave/array/Range.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/array/Range.h	Thu Nov 19 13:08:00 2020 -0800
@@ -32,16 +32,350 @@
 
 #include "dMatrix.h"
 #include "dim-vector.h"
+#include "lo-error.h"
 #include "oct-sort.h"
 
+template <typename T> class Array;
+
+namespace octave
+{
+  // Helper class used solely for idx_vector.loop () function call
+
+  template <typename T>
+  class rangeidx_helper
+  {
+  public:
+
+    rangeidx_helper (T *a, T b, T i, T l, octave_idx_type n)
+      : array (a), base (b), inc (i), limit (l), nmax (n-1) { }
+
+    void operator () (octave_idx_type i)
+    {
+      if (i == 0)
+        *array++ = base;
+      else if (i < nmax)
+        *array++ = base + T (i) * inc;
+      else
+        *array++ = limit;
+    }
+
+  private:
+
+    T *array, base, inc, limit;
+    octave_idx_type nmax;
+
+  };
+
+  template <typename T>
+  class range
+  {
+  public:
+
+    range (void)
+      : m_base (0), m_increment (0), m_limit (0), m_final (0), m_numel (0)
+    { }
+
+    // LIMIT is an upper limit and may be outside the range of actual
+    // values.  For floating point ranges, we perform a tolerant check
+    // to attempt to capture limit in the set of values if it is "close"
+    // to the value of base + a multiple of the increment.
+
+    range (const T& base, const T& increment, const T& limit)
+      : m_base (base), m_increment (increment), m_limit (limit),
+        m_final (), m_numel ()
+    {
+      init ();
+    }
+
+    range (const T& base, const T& limit)
+      : m_base (base), m_increment (1), m_limit (limit), m_final (), m_numel ()
+    {
+      init ();
+    }
+
+    // Allow conversion from (presumably) properly constructed Range
+    // objects and to create constant ranges (see the static
+    // make_constant method).  The values of base, limit, increment,
+    // and numel must be consistent.
+
+    // FIXME: Actually check that base, limit, increment, and numel are
+    // consistent.
+
+    // FIXME: Is there a way to limit this to T == double?
+
+    range (const T& base, const T& increment, const T& limit,
+           octave_idx_type numel)
+      : m_base (base), m_increment (increment), m_limit (limit),
+        m_final (limit), m_numel (numel)
+    { }
+
+    range (const T& base, const T& increment, const T& limit,
+           const T& final, octave_idx_type numel)
+      : m_base (base), m_increment (increment), m_limit (limit),
+        m_final (final), m_numel (numel)
+    { }
+
+    // We don't use a constructor for this because it will conflict with
+    // range<T> (base, limit) when T is octave_idx_type.
+
+    static range<T> make_constant (const T& base, octave_idx_type numel)
+    {
+      // We could just make this constructor public, but it allows
+      // inconsistent ranges to be constructed.  And it is probably much
+      // clearer to see "make_constant" instead of puzzling over the
+      // purpose of this strange constructor form.
+
+      return range<T> (base, T (), base, numel);
+    }
+
+    // We don't use a constructor for this because it will conflict with
+    // range<T> (base, limit, increment) when T is octave_idx_type.
+
+    static range<T> make_n_element_range (const T& base, const T& increment,
+                                          octave_idx_type numel)
+    {
+      // We could just make this constructor public, but it allows
+      // inconsistent ranges to be constructed.  And it is probably much
+      // clearer to see "make_constant" instead of puzzling over the
+      // purpose of this strange constructor form.
+
+      T final_val = base + (numel - 1) * increment;
+
+      return range<T> (base, increment, final_val, numel);
+    }
+
+    range (const range<T>&) = default;
+
+    range<T>& operator = (const range<T>&) = default;
+
+    ~range (void) = default;
+
+    T base (void) const { return m_base; }
+    T increment (void) const { return m_increment; }
+    T limit (void) const { return m_limit; }
+
+    T final_value (void) const { return m_final; }
+
+    T min (void) const
+    {
+      return (m_numel > 0
+              ? m_increment > T (0) ? base () : final_value ()
+              : T (0));
+    }
+
+    T max (void) const
+    {
+      return (m_numel > 0
+              ? m_increment > T (0) ? final_value () : base ()
+              : T (0));
+    }
+
+    octave_idx_type numel (void) const { return m_numel; }
+
+    dim_vector dims (void) const { return dim_vector (1, m_numel); }
+
+    octave_idx_type rows (void) const { return 1; }
+
+    octave_idx_type cols (void) const { return numel (); }
+    octave_idx_type columns (void) const { return numel (); }
+
+    bool isempty (void) const { return numel () == 0; }
+
+    bool all_elements_are_ints (void) const { return true; }
+
+    sortmode issorted (sortmode mode = ASCENDING) const
+    {
+      if (m_numel > 1 && m_increment > T (0))
+        mode = (mode == DESCENDING) ? UNSORTED : ASCENDING;
+      else if (m_numel > 1 && m_increment < T (0))
+        mode = (mode == ASCENDING) ? UNSORTED : DESCENDING;
+      else
+        mode = (mode == UNSORTED) ? ASCENDING : mode;
+
+      return mode;
+    }
+
+    octave_idx_type nnz (void) const;
+
+    // Support for single-index subscripting, without generating matrix cache.
+
+    T checkelem (octave_idx_type i) const
+    {
+      if (i < 0 || i >= m_numel)
+        err_index_out_of_range (2, 2, i+1, m_numel, dims ());
+
+      if (i == 0)
+        return m_base;
+      else if (i < m_numel - 1)
+        return m_base + T (i) * m_increment;
+      else
+        return final_value ();
+    }
+
+    T checkelem (octave_idx_type i, octave_idx_type j) const
+    {
+      // Ranges are *always* row vectors.
+      if (i != 0)
+        err_index_out_of_range (1, 1, i+1, m_numel, dims ());
+
+      return checkelem (j);
+    }
+
+    T elem (octave_idx_type i) const
+    {
+      if (i == 0)
+        return m_base;
+      else if (i < m_numel - 1)
+        return m_base + T (i) * m_increment;
+      else
+        return final_value ();
+    }
+
+    T elem (octave_idx_type /* i */, octave_idx_type j) const
+    {
+      return elem (j);
+    }
+
+    T operator () (octave_idx_type i) const
+    {
+      return elem (i);
+    }
+
+    T operator () (octave_idx_type i, octave_idx_type j) const
+    {
+      return elem (i, j);
+    }
+
+    Array<T> index (const idx_vector& i) const
+    {
+      Array<T> retval;
+
+      octave_idx_type n = m_numel;
+
+      if (i.is_colon ())
+        {
+          retval = array_value ().reshape (dim_vector (m_numel, 1));
+        }
+      else
+        {
+          if (i.extent (n) != n)
+            err_index_out_of_range (1, 1, i.extent (n), n, dims ());
+
+          dim_vector rd = i.orig_dimensions ();
+          octave_idx_type il = i.length (n);
+
+          // taken from Array.cc.
+          if (n != 1 && rd.isvector ())
+            rd = dim_vector (1, il);
+
+          retval.clear (rd);
+
+          // idx_vector loop across all values in i,
+          // executing __rangeidx_helper (i) for each i
+          i.loop (n, rangeidx_helper<T> (retval.fortran_vec (),
+                                         m_base, m_increment, final_value (),
+                                         m_numel));
+        }
+
+      return retval;
+    }
+
+    Array<T> diag (octave_idx_type k) const
+    {
+      return array_value ().diag (k);
+    }
+
+    Array<T> array_value (void) const
+    {
+      octave_idx_type nel = numel ();
+
+      Array<T> retval (dim_vector (1, nel));
+
+      if (nel > 0)
+        {
+          // The first element must always be *exactly* the base.
+          // E.g, -0 would otherwise become +0 in the loop (-0 + 0*increment).
+          retval(0) = m_base;
+
+          for (octave_idx_type i = 1; i < nel - 1; i++)
+            retval.xelem (i) = m_base + i * m_increment;
+
+          retval.xelem (nel - 1) = final_value ();
+        }
+
+      return retval;
+    }
+
+  private:
+
+    T m_base;
+    T m_increment;
+    T m_limit;
+    T m_final;
+    octave_idx_type m_numel;
+
+    void init (void)
+    {
+      m_numel = get_numel ();
+      m_final = get_final_value ();
+    }
+
+    // Setting the number of elements to zero when the increment is zero
+    // is intentional and matches the behavior of Matlab's colon
+    // operator.
+
+    octave_idx_type get_numel (void) const
+    {
+      return ((m_increment == T (0)
+               || (m_limit > m_base && m_increment < T (0))
+               || (m_limit < m_base && m_increment > T (0)))
+              ? T (0)
+              : (m_limit - m_base + m_increment) / m_increment);
+    }
+
+    // This calculation is appropriate for integer ranges.
+
+    T get_final_value (void) const
+    {
+      return m_base + (m_numel - 1) * m_increment;
+    }
+  };
+
+  // Specializations defined externally.
+
+  template <> bool range<double>::all_elements_are_ints (void) const;
+  template <> bool range<float>::all_elements_are_ints (void) const;
+
+  template <> octave_idx_type range<double>::get_numel (void) const;
+  template <> octave_idx_type range<float>::get_numel (void) const;
+
+  template <> double range<double>::get_final_value (void) const;
+  template <> float range<float>::get_final_value (void) const;
+
+  template <> octave_idx_type range<double>::nnz (void) const;
+}
+
 class
 OCTAVE_API
 Range
 {
 public:
 
+  OCTAVE_DEPRECATED (7, "use the 'octave::range<double>' class instead")
   Range (void)
-    : rng_base (0), rng_limit (0), rng_inc (0), rng_numel (0), cache (1, 0) { }
+    : m_base (0), m_limit (0), m_inc (0), m_numel (0)
+  { }
+
+  // Assume range is already properly constructed, so just copy internal
+  // values.  However, we set LIMIT to the computed final value because
+  // that mimics the behavior of the other Range class constructors that
+  // reset limit to the computed final value.
+
+  OCTAVE_DEPRECATED (7, "use the 'octave::range<double>' class instead")
+  Range (const octave::range<double>& r)
+    : m_base (r.base ()), m_limit (r.final_value ()), m_inc (r.increment ()),
+      m_numel (r.numel ())
+  { }
 
   Range (const Range& r) = default;
 
@@ -49,44 +383,60 @@
 
   ~Range (void) = default;
 
+  OCTAVE_DEPRECATED (7, "use the 'octave::range<double>' class instead")
   Range (double b, double l)
-    : rng_base (b), rng_limit (l), rng_inc (1),
-      rng_numel (numel_internal ()), cache ()
+    : m_base (b), m_limit (l), m_inc (1), m_numel (numel_internal ())
   {
-    rng_limit = limit_internal ();
+    if (! octave::math::isinf (m_limit))
+      m_limit = limit_internal ();
   }
 
+  OCTAVE_DEPRECATED (7, "use the 'octave::range<double>' class instead")
   Range (double b, double l, double i)
-    : rng_base (b), rng_limit (l), rng_inc (i),
-      rng_numel (numel_internal ()), cache ()
+    : m_base (b), m_limit (l), m_inc (i), m_numel (numel_internal ())
   {
-    rng_limit = limit_internal ();
+    if (! octave::math::isinf (m_limit))
+      m_limit = limit_internal ();
   }
 
-  // For operators' usage (to preserve element count).
+  // NOTE: The following constructor may be deprecated and removed after
+  // the arithmetic operators are removed.
+
+  // For operators' usage (to preserve element count) and to create
+  // constant row vectors (obsolete usage).
+
+  OCTAVE_DEPRECATED (7, "use the 'octave::range<double>' class instead")
   Range (double b, double i, octave_idx_type n)
-    : rng_base (b), rng_limit (b + (n-1) * i), rng_inc (i),
-      rng_numel (n), cache ()
+    : m_base (b), m_limit (b + (n-1) * i), m_inc (i), m_numel (n)
   {
-    if (! octave::math::isfinite (b) || ! octave::math::isfinite (i)
-        || ! octave::math::isfinite (rng_limit))
-      rng_numel = -2;
-    else
-      {
-        // Code below is only needed if the resulting range must be 100%
-        // correctly constructed.  If the Range object created is only
-        // a temporary one used by operators this may be unnecessary.
-        rng_limit = limit_internal ();
-      }
+    if (! octave::math::isinf (m_limit))
+      m_limit = limit_internal ();
   }
 
-  double base (void) const { return rng_base; }
-  double limit (void) const { return rng_limit; }
-  double inc (void) const { return rng_inc; }
+  // The range has a finite number of elements.
+  bool ok (void) const
+  {
+    return (octave::math::isfinite (m_limit)
+            && (m_numel >= 0 || m_numel == -2));
+  }
+
+  double base (void) const { return m_base; }
+  double limit (void) const { return m_limit; }
+  double inc (void) const { return m_inc; }
+  double increment (void) const { return m_inc; }
 
-  octave_idx_type numel (void) const { return rng_numel; }
+  // We adjust the limit to be the final value, so return that.  We
+  // could introduce a new variable to store the final value separately,
+  // but it seems like that would just add confusion.  If we changed
+  // the meaning of the limit function, we would change the behavior of
+  // programs that expect limit to be the final value instead of the
+  // value of the limit when the range was created.  This problem will
+  // be fixed with the new template range class.
+  double final_value (void) const { return m_limit; }
 
-  dim_vector dims (void) const { return dim_vector (1, rng_numel); }
+  octave_idx_type numel (void) const { return m_numel; }
+
+  dim_vector dims (void) const { return dim_vector (1, m_numel); }
 
   octave_idx_type rows (void) const { return 1; }
 
@@ -150,13 +500,11 @@
 
 private:
 
-  double rng_base;
-  double rng_limit;
-  double rng_inc;
+  double m_base;
+  double m_limit;
+  double m_inc;
 
-  octave_idx_type rng_numel;
-
-  mutable Matrix cache;
+  octave_idx_type m_numel;
 
   octave_idx_type numel_internal (void) const;
 
@@ -164,27 +512,36 @@
 
   void init (void);
 
-  void clear_cache (void) const { cache.resize (0, 0); }
+protected:
 
-protected:
+  // NOTE: The following constructor may be removed when the arithmetic
+  // operators are removed.
 
   // For operators' usage (to allow all values to be set directly).
   Range (double b, double l, double i, octave_idx_type n)
-    : rng_base (b), rng_limit (l), rng_inc (i),
-      rng_numel (n), cache ()
-  {
-    if (! octave::math::isfinite (b) || ! octave::math::isfinite (i)
-        || ! octave::math::isfinite (l))
-      rng_numel = -2;
-  }
+    : m_base (b), m_limit (l), m_inc (i), m_numel (n)
+  { }
 };
 
+OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable")
 extern OCTAVE_API Range operator - (const Range& r);
+
+OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable")
 extern OCTAVE_API Range operator + (double x, const Range& r);
+
+OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable")
 extern OCTAVE_API Range operator + (const Range& r, double x);
+
+OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable")
 extern OCTAVE_API Range operator - (double x, const Range& r);
+
+OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable")
 extern OCTAVE_API Range operator - (const Range& r, double x);
+
+OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable")
 extern OCTAVE_API Range operator * (double x, const Range& r);
+
+OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable")
 extern OCTAVE_API Range operator * (const Range& r, double x);
 
 #endif
--- a/liboctave/array/Sparse.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/array/Sparse.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -651,9 +651,9 @@
 }
 
 /*
-%!assert <51880> (sparse (1:2, 2, 1:2, 2, 2), sparse ([0, 1; 0, 2]))
-%!assert <51880> (sparse (1:2, 1, 1:2, 2, 2), sparse ([1, 0; 2, 0]))
-%!assert <51880> (sparse (1:2, 2, 1:2, 2, 3), sparse ([0, 1, 0; 0, 2, 0]))
+%!assert <*51880> (sparse (1:2, 2, 1:2, 2, 2), sparse ([0, 1; 0, 2]))
+%!assert <*51880> (sparse (1:2, 1, 1:2, 2, 2), sparse ([1, 0; 2, 0]))
+%!assert <*51880> (sparse (1:2, 2, 1:2, 2, 3), sparse ([0, 1, 0; 0, 2, 0]))
 */
 
 template <typename T>
@@ -2969,10 +2969,10 @@
 %!test test_sparse_slice ([2 2], 22, 3);
 %!test test_sparse_slice ([2 2], 22, 4);
 
-%!assert <35570> (speye (3,1)(3:-1:1), sparse ([0; 0; 1]))
+%!assert <*35570> (speye (3,1)(3:-1:1), sparse ([0; 0; 1]))
 
 ## Test removing columns
-%!test <36656>
+%!test <*36656>
 %! s = sparse (magic (5));
 %! s(:,2:4) = [];
 %! assert (s, sparse (magic (5)(:, [1,5])));
@@ -2983,21 +2983,21 @@
 %! assert (s, sparse ([], [], [], 0, 1));
 
 ## Test (bug #37321)
-%!test <37321> a=sparse (0,0); assert (all (a) == sparse ([1]));
-%!test <37321> a=sparse (0,1); assert (all (a) == sparse ([1]));
-%!test <37321> a=sparse (1,0); assert (all (a) == sparse ([1]));
-%!test <37321> a=sparse (1,0); assert (all (a,2) == sparse ([1]));
-%!test <37321> a=sparse (1,0); assert (size (all (a,1)), [1 0]);
-%!test <37321> a=sparse (1,1);
+%!test <*37321> a=sparse (0,0); assert (all (a) == sparse ([1]));
+%!test <*37321> a=sparse (0,1); assert (all (a) == sparse ([1]));
+%!test <*37321> a=sparse (1,0); assert (all (a) == sparse ([1]));
+%!test <*37321> a=sparse (1,0); assert (all (a,2) == sparse ([1]));
+%!test <*37321> a=sparse (1,0); assert (size (all (a,1)), [1 0]);
+%!test <*37321> a=sparse (1,1);
 %! assert (all (a) == sparse ([0]));
 %! assert (size (all (a)), [1 1]);
-%!test <37321> a=sparse (2,1);
+%!test <*37321> a=sparse (2,1);
 %! assert (all (a) == sparse ([0]));
 %! assert (size (all (a)), [1 1]);
-%!test <37321> a=sparse (1,2);
+%!test <*37321> a=sparse (1,2);
 %! assert (all (a) == sparse ([0]));
 %! assert (size (all (a)), [1 1]);
-%!test <37321> a=sparse (2,2); assert (isequal (all (a), sparse ([0 0])));
+%!test <*37321> a=sparse (2,2); assert (isequal (all (a), sparse ([0 0])));
 
 ## Test assigning row to a column slice
 %!test <45589>
--- a/liboctave/array/Sparse.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/array/Sparse.h	Thu Nov 19 13:08:00 2020 -0800
@@ -273,8 +273,6 @@
 
   octave_idx_type compute_index (const Array<octave_idx_type>& ra_idx) const;
 
-  // FIXME: Functions are marked as NORETURN, but they are used with
-  //        a return statement in following code.  Shouldn't that be fixed?
   OCTAVE_NORETURN T range_error (const char *fcn, octave_idx_type n) const;
   OCTAVE_NORETURN T& range_error (const char *fcn, octave_idx_type n);
 
@@ -322,8 +320,7 @@
   T& checkelem (octave_idx_type n)
   {
     if (n < 0 || n >= numel ())
-      // FIXME: Why should we "return" when range_error is OCTAVE_NORETURN?
-      return range_error ("T& Sparse<T>::checkelem", n);
+      range_error ("T& Sparse<T>::checkelem", n);
     else
       {
         make_unique ();
@@ -334,7 +331,7 @@
   T& checkelem (octave_idx_type i, octave_idx_type j)
   {
     if (i < 0 || j < 0 || i >= dim1 () || j >= dim2 ())
-      return range_error ("T& Sparse<T>::checkelem", i, j);
+      range_error ("T& Sparse<T>::checkelem", i, j);
     else
       {
         make_unique ();
@@ -347,7 +344,7 @@
     octave_idx_type i = compute_index (ra_idx);
 
     if (i < 0)
-      return range_error ("T& Sparse<T>::checkelem", ra_idx);
+      range_error ("T& Sparse<T>::checkelem", ra_idx);
     else
       return elem (i);
   }
@@ -385,7 +382,7 @@
   T checkelem (octave_idx_type n) const
   {
     if (n < 0 || n >= numel ())
-      return range_error ("T Sparse<T>::checkelem", n);
+      range_error ("T Sparse<T>::checkelem", n);
     else
       return xelem (n);
   }
@@ -393,7 +390,7 @@
   T checkelem (octave_idx_type i, octave_idx_type j) const
   {
     if (i < 0 || j < 0 || i >= dim1 () || j >= dim2 ())
-      return range_error ("T Sparse<T>::checkelem", i, j);
+      range_error ("T Sparse<T>::checkelem", i, j);
     else
       return xelem (i, j);
   }
@@ -403,7 +400,7 @@
     octave_idx_type i = compute_index (ra_idx);
 
     if (i < 0)
-      return range_error ("T Sparse<T>::checkelem", ra_idx);
+      range_error ("T Sparse<T>::checkelem", ra_idx);
     else
       return Sparse<T>::elem (i);
   }
--- a/liboctave/array/boolSparse.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/array/boolSparse.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -282,7 +282,7 @@
 {
   typedef SparseBoolMatrix::element_type elt_type;
 
-  return read_sparse_matrix<elt_type> (is, a, octave_read_value<bool>);
+  return read_sparse_matrix<elt_type> (is, a, octave::read_value<bool>);
 }
 
 SparseBoolMatrix
--- a/liboctave/array/dMatrix.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/array/dMatrix.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -2637,7 +2637,7 @@
       for (octave_idx_type j = 0; j < a.cols (); j++)
         {
           os << ' ';
-          octave_write_double (os, a.elem (i, j));
+          octave::write_value<double> (os, a.elem (i, j));
         }
       os << "\n";
     }
@@ -2656,7 +2656,7 @@
       for (octave_idx_type i = 0; i < nr; i++)
         for (octave_idx_type j = 0; j < nc; j++)
           {
-            tmp = octave_read_value<double> (is);
+            tmp = octave::read_value<double> (is);
             if (is)
               a.elem (i, j) = tmp;
             else
--- a/liboctave/array/dNDArray.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/array/dNDArray.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -626,7 +626,7 @@
   for (octave_idx_type i = 0; i < nel; i++)
     {
       os << ' ';
-      octave_write_double (os, a.elem (i));
+      octave::write_value<double> (os, a.elem (i));
       os << "\n";
     }
   return os;
@@ -642,7 +642,7 @@
       double tmp;
       for (octave_idx_type i = 0; i < nel; i++)
         {
-          tmp = octave_read_value<double> (is);
+          tmp = octave::read_value<double> (is);
           if (is)
             a.elem (i) = tmp;
           else
--- a/liboctave/array/dSparse.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/array/dSparse.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -7493,7 +7493,7 @@
       for (octave_idx_type i = a.cidx (j); i < a.cidx (j+1); i++)
         {
           os << a.ridx (i) + 1 << ' '  << j + 1 << ' ';
-          octave_write_double (os, a.data (i));
+          octave::write_value<double> (os, a.data (i));
           os << "\n";
         }
     }
@@ -7506,7 +7506,7 @@
 {
   typedef SparseMatrix::element_type elt_type;
 
-  return read_sparse_matrix<elt_type> (is, a, octave_read_value<double>);
+  return read_sparse_matrix<elt_type> (is, a, octave::read_value<double>);
 }
 
 SparseMatrix
--- a/liboctave/array/fCMatrix.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/array/fCMatrix.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -3200,7 +3200,7 @@
       for (octave_idx_type j = 0; j < a.cols (); j++)
         {
           os << ' ';
-          octave_write_complex (os, a.elem (i, j));
+          octave::write_value<Complex> (os, a.elem (i, j));
         }
       os << "\n";
     }
@@ -3219,7 +3219,7 @@
       for (octave_idx_type i = 0; i < nr; i++)
         for (octave_idx_type j = 0; j < nc; j++)
           {
-            tmp = octave_read_value<FloatComplex> (is);
+            tmp = octave::read_value<FloatComplex> (is);
             if (is)
               a.elem (i, j) = tmp;
             else
--- a/liboctave/array/fCNDArray.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/array/fCNDArray.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -616,7 +616,7 @@
   for (octave_idx_type i = 0; i < nel; i++)
     {
       os << ' ';
-      octave_write_complex (os, a.elem (i));
+      octave::write_value<Complex> (os, a.elem (i));
       os << "\n";
     }
   return os;
@@ -632,7 +632,7 @@
       FloatComplex tmp;
       for (octave_idx_type i = 0; i < nel; i++)
         {
-          tmp = octave_read_value<FloatComplex> (is);
+          tmp = octave::read_value<FloatComplex> (is);
           if (is)
             a.elem (i) = tmp;
           else
--- a/liboctave/array/fMatrix.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/array/fMatrix.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -2647,7 +2647,7 @@
       for (octave_idx_type j = 0; j < a.cols (); j++)
         {
           os << ' ';
-          octave_write_float (os, a.elem (i, j));
+          octave::write_value<float> (os, a.elem (i, j));
         }
       os << "\n";
     }
@@ -2666,7 +2666,7 @@
       for (octave_idx_type i = 0; i < nr; i++)
         for (octave_idx_type j = 0; j < nc; j++)
           {
-            tmp = octave_read_value<float> (is);
+            tmp = octave::read_value<float> (is);
             if (is)
               a.elem (i, j) = tmp;
             else
--- a/liboctave/array/fNDArray.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/array/fNDArray.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -594,7 +594,7 @@
   for (octave_idx_type i = 0; i < nel; i++)
     {
       os << ' ';
-      octave_write_float (os, a.elem (i));
+      octave::write_value<float> (os, a.elem (i));
       os << "\n";
     }
   return os;
@@ -610,7 +610,7 @@
       float tmp;
       for (octave_idx_type i = 0; i < nel; i++)
         {
-          tmp = octave_read_value<float> (is);
+          tmp = octave::read_value<float> (is);
           if (is)
             a.elem (i) = tmp;
           else
--- a/liboctave/array/idx-vector.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/array/idx-vector.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -132,7 +132,7 @@
     octave::err_invalid_index (start + (len-1)*step);
 }
 
-idx_vector::idx_range_rep::idx_range_rep (const Range& r)
+idx_vector::idx_range_rep::idx_range_rep (const octave::range<double>& r)
   : idx_base_rep (), start (0), len (r.numel ()), step (1)
 {
   if (len < 0)
@@ -143,7 +143,7 @@
       if (r.all_elements_are_ints ())
         {
           start = static_cast<octave_idx_type> (r.base ()) - 1;
-          step = static_cast<octave_idx_type> (r.inc ());
+          step = static_cast<octave_idx_type> (r.increment ());
           if (start < 0)
             octave::err_invalid_index (start);
           if (step < 0 && start + (len - 1)*step < 0)
@@ -153,7 +153,7 @@
         {
           // find first non-integer, then gripe about it
           double b = r.base ();
-          double inc = r.inc ();
+          double inc = r.increment ();
           octave::err_invalid_index (b != std::trunc (b) ? b : b + inc);
         }
     }
@@ -207,11 +207,11 @@
   return os;
 }
 
-Range
+octave::range<double>
 idx_vector::idx_range_rep::unconvert (void) const
 {
-  return Range (static_cast<double> (start+1),
-                static_cast<double> (step), len);
+  return octave::range<double>::make_n_element_range
+    (static_cast<double> (start+1), static_cast<double> (step), len);
 }
 
 Array<octave_idx_type>
@@ -1226,7 +1226,7 @@
 }
 
 void idx_vector::unconvert (idx_class_type& iclass,
-                            double& scalar, Range& range,
+                            double& scalar, octave::range<double>& range,
                             Array<double>& array, Array<bool>& mask) const
 {
   iclass = idx_class ();
--- a/liboctave/array/idx-vector.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/array/idx-vector.h	Thu Nov 19 13:08:00 2020 -0800
@@ -41,14 +41,21 @@
 
 template <typename T> class Array;
 template <typename T> class Sparse;
-class Range;
+
+namespace octave
+{
+  template <typename T> class range;
+}
 
 // Design rationale:
-// idx_vector is a reference-counting, polymorphic pointer, that can contain
-// 4 types of index objects: a magic colon, a range, a scalar, or an index vector.
-// Polymorphic methods for single element access are provided, as well as
-// templates implementing "early dispatch", i.e., hoisting the checks for index
-// type out of loops.
+//
+// idx_vector is a reference-counting, polymorphic pointer, that can
+// contain 4 types of index objects: a magic colon, a range, a scalar,
+// or an index vector.
+//
+// Polymorphic methods for single element access are provided, as well
+// as templates implementing "early dispatch", i.e., hoisting the checks
+// for index type out of loops.
 
 class
 OCTAVE_API
@@ -173,7 +180,7 @@
     idx_range_rep (octave_idx_type _start, octave_idx_type _limit,
                    octave_idx_type _step);
 
-    idx_range_rep (const Range&);
+    idx_range_rep (const octave::range<double>&);
 
     // No copying!
 
@@ -212,7 +219,7 @@
 
     std::ostream& print (std::ostream& os) const;
 
-    Range unconvert (void) const;
+    octave::range<double> unconvert (void) const;
 
     Array<octave_idx_type> as_array (void);
 
@@ -525,7 +532,7 @@
 
   idx_vector (const Array<bool>& nda);
 
-  idx_vector (const Range& r)
+  idx_vector (const octave::range<double>& r)
     : rep (new idx_range_rep (r))
   { chkerr (); }
 
@@ -1013,7 +1020,7 @@
 
   // Unconverts the index to a scalar, Range, double array or a mask.
   void unconvert (idx_class_type& iclass,
-                  double& scalar, Range& range,
+                  double& scalar, octave::range<double>& range,
                   Array<double>& array, Array<bool>& mask) const;
 
   Array<octave_idx_type> as_array (void) const;
--- a/liboctave/external/odepack/cfode.f	Thu Nov 19 13:05:51 2020 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,112 +0,0 @@
-      SUBROUTINE CFODE (METH, ELCO, TESCO)
-CLLL. OPTIMIZE
-      INTEGER METH
-      INTEGER I, IB, NQ, NQM1, NQP1
-      DOUBLE PRECISION ELCO, TESCO
-      DOUBLE PRECISION AGAMQ, FNQ, FNQM1, PC, PINT, RAGQ,
-     1   RQFAC, RQ1FAC, TSIGN, XPIN
-      DIMENSION ELCO(13,12), TESCO(3,12)
-C-----------------------------------------------------------------------
-C CFODE IS CALLED BY THE INTEGRATOR ROUTINE TO SET COEFFICIENTS
-C NEEDED THERE.  THE COEFFICIENTS FOR THE CURRENT METHOD, AS
-C GIVEN BY THE VALUE OF METH, ARE SET FOR ALL ORDERS AND SAVED.
-C THE MAXIMUM ORDER ASSUMED HERE IS 12 IF METH = 1 AND 5 IF METH = 2.
-C (A SMALLER VALUE OF THE MAXIMUM ORDER IS ALSO ALLOWED.)
-C CFODE IS CALLED ONCE AT THE BEGINNING OF THE PROBLEM,
-C AND IS NOT CALLED AGAIN UNLESS AND UNTIL METH IS CHANGED.
-C
-C THE ELCO ARRAY CONTAINS THE BASIC METHOD COEFFICIENTS.
-C THE COEFFICIENTS EL(I), 1 .LE. I .LE. NQ+1, FOR THE METHOD OF
-C ORDER NQ ARE STORED IN ELCO(I,NQ).  THEY ARE GIVEN BY A GENETRATING
-C POLYNOMIAL, I.E.,
-C     L(X) = EL(1) + EL(2)*X + ... + EL(NQ+1)*X**NQ.
-C FOR THE IMPLICIT ADAMS METHODS, L(X) IS GIVEN BY
-C     DL/DX = (X+1)*(X+2)*...*(X+NQ-1)/FACTORIAL(NQ-1),    L(-1) = 0.
-C FOR THE BDF METHODS, L(X) IS GIVEN BY
-C     L(X) = (X+1)*(X+2)* ... *(X+NQ)/K,
-C WHERE         K = FACTORIAL(NQ)*(1 + 1/2 + ... + 1/NQ).
-C
-C THE TESCO ARRAY CONTAINS TEST CONSTANTS USED FOR THE
-C LOCAL ERROR TEST AND THE SELECTION OF STEP SIZE AND/OR ORDER.
-C AT ORDER NQ, TESCO(K,NQ) IS USED FOR THE SELECTION OF STEP
-C SIZE AT ORDER NQ - 1 IF K = 1, AT ORDER NQ IF K = 2, AND AT ORDER
-C NQ + 1 IF K = 3.
-C-----------------------------------------------------------------------
-      DIMENSION PC(12)
-C
-      GO TO (100, 200), METH
-C
- 100  ELCO(1,1) = 1.0D0
-      ELCO(2,1) = 1.0D0
-      TESCO(1,1) = 0.0D0
-      TESCO(2,1) = 2.0D0
-      TESCO(1,2) = 1.0D0
-      TESCO(3,12) = 0.0D0
-      PC(1) = 1.0D0
-      RQFAC = 1.0D0
-      DO 140 NQ = 2,12
-C-----------------------------------------------------------------------
-C THE PC ARRAY WILL CONTAIN THE COEFFICIENTS OF THE POLYNOMIAL
-C     P(X) = (X+1)*(X+2)*...*(X+NQ-1).
-C INITIALLY, P(X) = 1.
-C-----------------------------------------------------------------------
-        RQ1FAC = RQFAC
-        RQFAC = RQFAC/DBLE(NQ)
-        NQM1 = NQ - 1
-        FNQM1 = DBLE(NQM1)
-        NQP1 = NQ + 1
-C FORM COEFFICIENTS OF P(X)*(X+NQ-1). ----------------------------------
-        PC(NQ) = 0.0D0
-        DO 110 IB = 1,NQM1
-          I = NQP1 - IB
- 110      PC(I) = PC(I-1) + FNQM1*PC(I)
-        PC(1) = FNQM1*PC(1)
-C COMPUTE INTEGRAL, -1 TO 0, OF P(X) AND X*P(X). -----------------------
-        PINT = PC(1)
-        XPIN = PC(1)/2.0D0
-        TSIGN = 1.0D0
-        DO 120 I = 2,NQ
-          TSIGN = -TSIGN
-          PINT = PINT + TSIGN*PC(I)/DBLE(I)
- 120      XPIN = XPIN + TSIGN*PC(I)/DBLE(I+1)
-C STORE COEFFICIENTS IN ELCO AND TESCO. --------------------------------
-        ELCO(1,NQ) = PINT*RQ1FAC
-        ELCO(2,NQ) = 1.0D0
-        DO 130 I = 2,NQ
- 130      ELCO(I+1,NQ) = RQ1FAC*PC(I)/DBLE(I)
-        AGAMQ = RQFAC*XPIN
-        RAGQ = 1.0D0/AGAMQ
-        TESCO(2,NQ) = RAGQ
-        IF (NQ .LT. 12) TESCO(1,NQP1) = RAGQ*RQFAC/DBLE(NQP1)
-        TESCO(3,NQM1) = RAGQ
- 140    CONTINUE
-      RETURN
-C
- 200  PC(1) = 1.0D0
-      RQ1FAC = 1.0D0
-      DO 230 NQ = 1,5
-C-----------------------------------------------------------------------
-C THE PC ARRAY WILL CONTAIN THE COEFFICIENTS OF THE POLYNOMIAL
-C     P(X) = (X+1)*(X+2)*...*(X+NQ).
-C INITIALLY, P(X) = 1.
-C-----------------------------------------------------------------------
-        FNQ = DBLE(NQ)
-        NQP1 = NQ + 1
-C FORM COEFFICIENTS OF P(X)*(X+NQ). ------------------------------------
-        PC(NQP1) = 0.0D0
-        DO 210 IB = 1,NQ
-          I = NQ + 2 - IB
- 210      PC(I) = PC(I-1) + FNQ*PC(I)
-        PC(1) = FNQ*PC(1)
-C STORE COEFFICIENTS IN ELCO AND TESCO. --------------------------------
-        DO 220 I = 1,NQP1
- 220      ELCO(I,NQ) = PC(I)/PC(2)
-        ELCO(2,NQ) = 1.0D0
-        TESCO(1,NQ) = RQ1FAC
-        TESCO(2,NQ) = DBLE(NQP1)/ELCO(1,NQ)
-        TESCO(3,NQ) = DBLE(NQ+2)/ELCO(1,NQ)
-        RQ1FAC = RQ1FAC/FNQ
- 230    CONTINUE
-      RETURN
-C----------------------- END OF SUBROUTINE CFODE -----------------------
-      END
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/external/odepack/dcfode.f	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,127 @@
+      SUBROUTINE DCFODE (METH, ELCO, TESCO)
+C***BEGIN PROLOGUE  DCFODE
+C***SUBSIDIARY
+C***PURPOSE  Set ODE integrator coefficients.
+C***TYPE      DOUBLE PRECISION (SCFODE-S, DCFODE-D)
+C***AUTHOR  Hindmarsh, Alan C., (LLNL)
+C***DESCRIPTION
+C
+C  DCFODE is called by the integrator routine to set coefficients
+C  needed there.  The coefficients for the current method, as
+C  given by the value of METH, are set for all orders and saved.
+C  The maximum order assumed here is 12 if METH = 1 and 5 if METH = 2.
+C  (A smaller value of the maximum order is also allowed.)
+C  DCFODE is called once at the beginning of the problem,
+C  and is not called again unless and until METH is changed.
+C
+C  The ELCO array contains the basic method coefficients.
+C  The coefficients el(i), 1 .le. i .le. nq+1, for the method of
+C  order nq are stored in ELCO(i,nq).  They are given by a genetrating
+C  polynomial, i.e.,
+C      l(x) = el(1) + el(2)*x + ... + el(nq+1)*x**nq.
+C  For the implicit Adams methods, l(x) is given by
+C      dl/dx = (x+1)*(x+2)*...*(x+nq-1)/factorial(nq-1),    l(-1) = 0.
+C  For the BDF methods, l(x) is given by
+C      l(x) = (x+1)*(x+2)* ... *(x+nq)/K,
+C  where         K = factorial(nq)*(1 + 1/2 + ... + 1/nq).
+C
+C  The TESCO array contains test constants used for the
+C  local error test and the selection of step size and/or order.
+C  At order nq, TESCO(k,nq) is used for the selection of step
+C  size at order nq - 1 if k = 1, at order nq if k = 2, and at order
+C  nq + 1 if k = 3.
+C
+C***SEE ALSO  DLSODE
+C***ROUTINES CALLED  (NONE)
+C***REVISION HISTORY  (YYMMDD)
+C   791129  DATE WRITTEN
+C   890501  Modified prologue to SLATEC/LDOC format.  (FNF)
+C   890503  Minor cosmetic changes.  (FNF)
+C   930809  Renamed to allow single/double precision versions. (ACH)
+C***END PROLOGUE  DCFODE
+C**End
+      INTEGER METH
+      INTEGER I, IB, NQ, NQM1, NQP1
+      DOUBLE PRECISION ELCO, TESCO
+      DOUBLE PRECISION AGAMQ, FNQ, FNQM1, PC, PINT, RAGQ,
+     1   RQFAC, RQ1FAC, TSIGN, XPIN
+      DIMENSION ELCO(13,12), TESCO(3,12)
+      DIMENSION PC(12)
+C
+C***FIRST EXECUTABLE STATEMENT  DCFODE
+      GO TO (100, 200), METH
+C
+ 100  ELCO(1,1) = 1.0D0
+      ELCO(2,1) = 1.0D0
+      TESCO(1,1) = 0.0D0
+      TESCO(2,1) = 2.0D0
+      TESCO(1,2) = 1.0D0
+      TESCO(3,12) = 0.0D0
+      PC(1) = 1.0D0
+      RQFAC = 1.0D0
+      DO 140 NQ = 2,12
+C-----------------------------------------------------------------------
+C The PC array will contain the coefficients of the polynomial
+C     p(x) = (x+1)*(x+2)*...*(x+nq-1).
+C Initially, p(x) = 1.
+C-----------------------------------------------------------------------
+        RQ1FAC = RQFAC
+        RQFAC = RQFAC/NQ
+        NQM1 = NQ - 1
+        FNQM1 = NQM1
+        NQP1 = NQ + 1
+C Form coefficients of p(x)*(x+nq-1). ----------------------------------
+        PC(NQ) = 0.0D0
+        DO 110 IB = 1,NQM1
+          I = NQP1 - IB
+ 110      PC(I) = PC(I-1) + FNQM1*PC(I)
+        PC(1) = FNQM1*PC(1)
+C Compute integral, -1 to 0, of p(x) and x*p(x). -----------------------
+        PINT = PC(1)
+        XPIN = PC(1)/2.0D0
+        TSIGN = 1.0D0
+        DO 120 I = 2,NQ
+          TSIGN = -TSIGN
+          PINT = PINT + TSIGN*PC(I)/I
+ 120      XPIN = XPIN + TSIGN*PC(I)/(I+1)
+C Store coefficients in ELCO and TESCO. --------------------------------
+        ELCO(1,NQ) = PINT*RQ1FAC
+        ELCO(2,NQ) = 1.0D0
+        DO 130 I = 2,NQ
+ 130      ELCO(I+1,NQ) = RQ1FAC*PC(I)/I
+        AGAMQ = RQFAC*XPIN
+        RAGQ = 1.0D0/AGAMQ
+        TESCO(2,NQ) = RAGQ
+        IF (NQ .LT. 12) TESCO(1,NQP1) = RAGQ*RQFAC/NQP1
+        TESCO(3,NQM1) = RAGQ
+ 140    CONTINUE
+      RETURN
+C
+ 200  PC(1) = 1.0D0
+      RQ1FAC = 1.0D0
+      DO 230 NQ = 1,5
+C-----------------------------------------------------------------------
+C The PC array will contain the coefficients of the polynomial
+C     p(x) = (x+1)*(x+2)*...*(x+nq).
+C Initially, p(x) = 1.
+C-----------------------------------------------------------------------
+        FNQ = NQ
+        NQP1 = NQ + 1
+C Form coefficients of p(x)*(x+nq). ------------------------------------
+        PC(NQP1) = 0.0D0
+        DO 210 IB = 1,NQ
+          I = NQ + 2 - IB
+ 210      PC(I) = PC(I-1) + FNQ*PC(I)
+        PC(1) = FNQ*PC(1)
+C Store coefficients in ELCO and TESCO. --------------------------------
+        DO 220 I = 1,NQP1
+ 220      ELCO(I,NQ) = PC(I)/PC(2)
+        ELCO(2,NQ) = 1.0D0
+        TESCO(1,NQ) = RQ1FAC
+        TESCO(2,NQ) = NQP1/ELCO(1,NQ)
+        TESCO(3,NQ) = (NQ+2)/ELCO(1,NQ)
+        RQ1FAC = RQ1FAC/FNQ
+ 230    CONTINUE
+      RETURN
+C----------------------- END OF SUBROUTINE DCFODE ----------------------
+      END
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/external/odepack/dewset.f	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,47 @@
+      SUBROUTINE DEWSET (N, ITOL, RTOL, ATOL, YCUR, EWT)
+C***BEGIN PROLOGUE  DEWSET
+C***SUBSIDIARY
+C***PURPOSE  Set error weight vector.
+C***TYPE      DOUBLE PRECISION (SEWSET-S, DEWSET-D)
+C***AUTHOR  Hindmarsh, Alan C., (LLNL)
+C***DESCRIPTION
+C
+C  This subroutine sets the error weight vector EWT according to
+C      EWT(i) = RTOL(i)*ABS(YCUR(i)) + ATOL(i),  i = 1,...,N,
+C  with the subscript on RTOL and/or ATOL possibly replaced by 1 above,
+C  depending on the value of ITOL.
+C
+C***SEE ALSO  DLSODE
+C***ROUTINES CALLED  (NONE)
+C***REVISION HISTORY  (YYMMDD)
+C   791129  DATE WRITTEN
+C   890501  Modified prologue to SLATEC/LDOC format.  (FNF)
+C   890503  Minor cosmetic changes.  (FNF)
+C   930809  Renamed to allow single/double precision versions. (ACH)
+C***END PROLOGUE  DEWSET
+C**End
+      INTEGER N, ITOL
+      INTEGER I
+      DOUBLE PRECISION RTOL, ATOL, YCUR, EWT
+      DIMENSION RTOL(*), ATOL(*), YCUR(N), EWT(N)
+C
+C***FIRST EXECUTABLE STATEMENT  DEWSET
+      GO TO (10, 20, 30, 40), ITOL
+ 10   CONTINUE
+      DO 15 I = 1,N
+ 15     EWT(I) = RTOL(1)*ABS(YCUR(I)) + ATOL(1)
+      RETURN
+ 20   CONTINUE
+      DO 25 I = 1,N
+ 25     EWT(I) = RTOL(1)*ABS(YCUR(I)) + ATOL(I)
+      RETURN
+ 30   CONTINUE
+      DO 35 I = 1,N
+ 35     EWT(I) = RTOL(I)*ABS(YCUR(I)) + ATOL(1)
+      RETURN
+ 40   CONTINUE
+      DO 45 I = 1,N
+ 45     EWT(I) = RTOL(I)*ABS(YCUR(I)) + ATOL(I)
+      RETURN
+C----------------------- END OF SUBROUTINE DEWSET ----------------------
+      END
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/external/odepack/dintdy.f	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,110 @@
+      SUBROUTINE DINTDY (T, K, YH, NYH, DKY, IFLAG)
+C***BEGIN PROLOGUE  DINTDY
+C***SUBSIDIARY
+C***PURPOSE  Interpolate solution derivatives.
+C***TYPE      DOUBLE PRECISION (SINTDY-S, DINTDY-D)
+C***AUTHOR  Hindmarsh, Alan C., (LLNL)
+C***DESCRIPTION
+C
+C  DINTDY computes interpolated values of the K-th derivative of the
+C  dependent variable vector y, and stores it in DKY.  This routine
+C  is called within the package with K = 0 and T = TOUT, but may
+C  also be called by the user for any K up to the current order.
+C  (See detailed instructions in the usage documentation.)
+C
+C  The computed values in DKY are gotten by interpolation using the
+C  Nordsieck history array YH.  This array corresponds uniquely to a
+C  vector-valued polynomial of degree NQCUR or less, and DKY is set
+C  to the K-th derivative of this polynomial at T.
+C  The formula for DKY is:
+C               q
+C   DKY(i)  =  sum  c(j,K) * (T - tn)**(j-K) * h**(-j) * YH(i,j+1)
+C              j=K
+C  where  c(j,K) = j*(j-1)*...*(j-K+1), q = NQCUR, tn = TCUR, h = HCUR.
+C  The quantities  nq = NQCUR, l = nq+1, N = NEQ, tn, and h are
+C  communicated by COMMON.  The above sum is done in reverse order.
+C  IFLAG is returned negative if either K or T is out of bounds.
+C
+C***SEE ALSO  DLSODE
+C***ROUTINES CALLED  XERRWD
+C***COMMON BLOCKS    DLS001
+C***REVISION HISTORY  (YYMMDD)
+C   791129  DATE WRITTEN
+C   890501  Modified prologue to SLATEC/LDOC format.  (FNF)
+C   890503  Minor cosmetic changes.  (FNF)
+C   930809  Renamed to allow single/double precision versions. (ACH)
+C   010418  Reduced size of Common block /DLS001/. (ACH)
+C   031105  Restored 'own' variables to Common block /DLS001/, to
+C           enable interrupt/restart feature. (ACH)
+C   050427  Corrected roundoff decrement in TP. (ACH)
+C***END PROLOGUE  DINTDY
+C**End
+      INTEGER K, NYH, IFLAG
+      DOUBLE PRECISION T, YH, DKY
+      DIMENSION YH(NYH,*), DKY(*)
+      INTEGER ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
+     1   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, CNYH,
+     2   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP
+      INTEGER ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
+     2   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
+      DOUBLE PRECISION CONIT, CRATE, EL, ELCO, HOLD, RMAX, TESCO,
+     1   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND
+      COMMON /DLS001/ CONIT, CRATE, EL(13), ELCO(13,12),
+     1   HOLD, RMAX, TESCO(3,12),
+     2   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND,
+     2   ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
+     3   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, CNYH,
+     3   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP,
+     4   ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
+     5   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
+      INTEGER I, IC, J, JB, JB2, JJ, JJ1, JP1
+      DOUBLE PRECISION C, R, S, TP
+      CHARACTER*80 MSG
+C
+C***FIRST EXECUTABLE STATEMENT  DINTDY
+      IFLAG = 0
+      IF (K .LT. 0 .OR. K .GT. NQ) GO TO 80
+      TP = TN - HU -  100.0D0*UROUND*SIGN(ABS(TN) + ABS(HU), HU)
+      IF ((T-TP)*(T-TN) .GT. 0.0D0) GO TO 90
+C
+      S = (T - TN)/H
+      IC = 1
+      IF (K .EQ. 0) GO TO 15
+      JJ1 = L - K
+      DO 10 JJ = JJ1,NQ
+ 10     IC = IC*JJ
+ 15   C = IC
+      DO 20 I = 1,N
+ 20     DKY(I) = C*YH(I,L)
+      IF (K .EQ. NQ) GO TO 55
+      JB2 = NQ - K
+      DO 50 JB = 1,JB2
+        J = NQ - JB
+        JP1 = J + 1
+        IC = 1
+        IF (K .EQ. 0) GO TO 35
+        JJ1 = JP1 - K
+        DO 30 JJ = JJ1,J
+ 30       IC = IC*JJ
+ 35     C = IC
+        DO 40 I = 1,N
+ 40       DKY(I) = C*YH(I,JP1) + S*DKY(I)
+ 50     CONTINUE
+      IF (K .EQ. 0) RETURN
+ 55   R = H**(-K)
+      DO 60 I = 1,N
+ 60     DKY(I) = R*DKY(I)
+      RETURN
+C
+ 80   MSG = 'DINTDY-  K (=I1) illegal      '
+      CALL XERRWD (MSG, 30, 51, 0, 1, K, 0, 0, 0.0D0, 0.0D0)
+      IFLAG = -1
+      RETURN
+ 90   MSG = 'DINTDY-  T (=R1) illegal      '
+      CALL XERRWD (MSG, 30, 52, 0, 0, 0, 0, 1, T, 0.0D0)
+      MSG='      T not in interval TCUR - HU (= R1) to TCUR (=R2)      '
+      CALL XERRWD (MSG, 60, 52, 0, 0, 0, 0, 2, TP, TN)
+      IFLAG = -2
+      RETURN
+C----------------------- END OF SUBROUTINE DINTDY ----------------------
+      END
--- a/liboctave/external/odepack/dlsode.f	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/external/odepack/dlsode.f	Thu Nov 19 13:08:00 2020 -0800
@@ -1,949 +1,1211 @@
       SUBROUTINE DLSODE (F, NEQ, Y, T, TOUT, ITOL, RTOL, ATOL, ITASK,
-     1            ISTATE, IOPT, RWORK, LRW, IWORK, LIW, JAC, MF)
+     1                  ISTATE, IOPT, RWORK, LRW, IWORK, LIW, JAC, MF)
       EXTERNAL F, JAC
       INTEGER NEQ, ITOL, ITASK, ISTATE, IOPT, LRW, IWORK, LIW, MF
       DOUBLE PRECISION Y, T, TOUT, RTOL, ATOL, RWORK
       DIMENSION NEQ(*), Y(*), RTOL(*), ATOL(*), RWORK(LRW), IWORK(LIW)
-C-----------------------------------------------------------------------
-C THIS IS THE MARCH 30, 1987 VERSION OF
-C LSODE.. LIVERMORE SOLVER FOR ORDINARY DIFFERENTIAL EQUATIONS.
-C THIS VERSION IS IN DOUBLE PRECISION.
+C***BEGIN PROLOGUE  DLSODE
+C***PURPOSE  Livermore Solver for Ordinary Differential Equations.
+C            DLSODE solves the initial-value problem for stiff or
+C            nonstiff systems of first-order ODE's,
+C               dy/dt = f(t,y),   or, in component form,
+C               dy(i)/dt = f(i) = f(i,t,y(1),y(2),...,y(N)),  i=1,...,N.
+C***CATEGORY  I1A
+C***TYPE      DOUBLE PRECISION (SLSODE-S, DLSODE-D)
+C***KEYWORDS  ORDINARY DIFFERENTIAL EQUATIONS, INITIAL VALUE PROBLEM,
+C             STIFF, NONSTIFF
+C***AUTHOR  Hindmarsh, Alan C., (LLNL)
+C             Center for Applied Scientific Computing, L-561
+C             Lawrence Livermore National Laboratory
+C             Livermore, CA 94551.
+C***DESCRIPTION
+C
+C     NOTE: The "Usage" and "Arguments" sections treat only a subset of
+C           available options, in condensed fashion.  The options
+C           covered and the information supplied will support most
+C           standard uses of DLSODE.
+C
+C           For more sophisticated uses, full details on all options are
+C           given in the concluding section, headed "Long Description."
+C           A synopsis of the DLSODE Long Description is provided at the
+C           beginning of that section; general topics covered are:
+C           - Elements of the call sequence; optional input and output
+C           - Optional supplemental routines in the DLSODE package
+C           - internal COMMON block
 C
-C LSODE SOLVES THE INITIAL VALUE PROBLEM FOR STIFF OR NONSTIFF
-C SYSTEMS OF FIRST ORDER ODE-S,
-C     DY/DT = F(T,Y) ,  OR, IN COMPONENT FORM,
-C     DY(I)/DT = F(I) = F(I,T,Y(1),Y(2),...,Y(NEQ)) (I = 1,...,NEQ).
-C LSODE IS A PACKAGE BASED ON THE GEAR AND GEARB PACKAGES, AND ON THE
-C OCTOBER 23, 1978 VERSION OF THE TENTATIVE ODEPACK USER INTERFACE
-C STANDARD, WITH MINOR MODIFICATIONS.
-C-----------------------------------------------------------------------
-C REFERENCE..
-C     ALAN C. HINDMARSH,  ODEPACK, A SYSTEMATIZED COLLECTION OF ODE
-C     SOLVERS, IN SCIENTIFIC COMPUTING, R. S. STEPLEMAN ET AL. (EDS.),
-C     NORTH-HOLLAND, AMSTERDAM, 1983, PP. 55-64.
-C-----------------------------------------------------------------------
-C AUTHOR AND CONTACT.. ALAN C. HINDMARSH,
-C                      COMPUTING AND MATHEMATICS RESEARCH DIV., L-316
-C                      LAWRENCE LIVERMORE NATIONAL LABORATORY
-C                      LIVERMORE, CA 94550.
-C-----------------------------------------------------------------------
-C SUMMARY OF USAGE.
+C *Usage:
+C     Communication between the user and the DLSODE package, for normal
+C     situations, is summarized here.  This summary describes a subset
+C     of the available options.  See "Long Description" for complete
+C     details, including optional communication, nonstandard options,
+C     and instructions for special situations.
+C
+C     A sample program is given in the "Examples" section.
+C
+C     Refer to the argument descriptions for the definitions of the
+C     quantities that appear in the following sample declarations.
+C
+C     For MF = 10,
+C        PARAMETER  (LRW = 20 + 16*NEQ,           LIW = 20)
+C     For MF = 21 or 22,
+C        PARAMETER  (LRW = 22 +  9*NEQ + NEQ**2,  LIW = 20 + NEQ)
+C     For MF = 24 or 25,
+C        PARAMETER  (LRW = 22 + 10*NEQ + (2*ML+MU)*NEQ,
+C       *                                         LIW = 20 + NEQ)
 C
-C COMMUNICATION BETWEEN THE USER AND THE LSODE PACKAGE, FOR NORMAL
-C SITUATIONS, IS SUMMARIZED HERE.  THIS SUMMARY DESCRIBES ONLY A SUBSET
-C OF THE FULL SET OF OPTIONS AVAILABLE.  SEE THE FULL DESCRIPTION FOR
-C DETAILS, INCLUDING OPTIONAL COMMUNICATION, NONSTANDARD OPTIONS,
-C AND INSTRUCTIONS FOR SPECIAL SITUATIONS.  SEE ALSO THE EXAMPLE
-C PROBLEM (WITH PROGRAM AND OUTPUT) FOLLOWING THIS SUMMARY.
+C        EXTERNAL F, JAC
+C        INTEGER  NEQ, ITOL, ITASK, ISTATE, IOPT, LRW, IWORK(LIW),
+C       *         LIW, MF
+C        DOUBLE PRECISION Y(NEQ), T, TOUT, RTOL, ATOL(ntol), RWORK(LRW)
+C
+C        CALL DLSODE (F, NEQ, Y, T, TOUT, ITOL, RTOL, ATOL, ITASK,
+C       *            ISTATE, IOPT, RWORK, LRW, IWORK, LIW, JAC, MF)
+C
+C *Arguments:
+C     F     :EXT    Name of subroutine for right-hand-side vector f.
+C                   This name must be declared EXTERNAL in calling
+C                   program.  The form of F must be:
+C
+C                   SUBROUTINE  F (NEQ, T, Y, YDOT)
+C                   INTEGER  NEQ
+C                   DOUBLE PRECISION  T, Y(*), YDOT(*)
+C
+C                   The inputs are NEQ, T, Y.  F is to set
+C
+C                   YDOT(i) = f(i,T,Y(1),Y(2),...,Y(NEQ)),
+C                                                     i = 1, ..., NEQ .
 C
-C A. FIRST PROVIDE A SUBROUTINE OF THE FORM..
-C               SUBROUTINE F (NEQ, T, Y, YDOT, IERR)
-C               DIMENSION Y(NEQ), YDOT(NEQ)
-C WHICH SUPPLIES THE VECTOR FUNCTION F BY LOADING YDOT(I) WITH F(I).
+C     NEQ   :IN     Number of first-order ODE's.
+C
+C     Y     :INOUT  Array of values of the y(t) vector, of length NEQ.
+C                   Input:  For the first call, Y should contain the
+C                           values of y(t) at t = T. (Y is an input
+C                           variable only if ISTATE = 1.)
+C                   Output: On return, Y will contain the values at the
+C                           new t-value.
+C
+C     T     :INOUT  Value of the independent variable.  On return it
+C                   will be the current value of t (normally TOUT).
+C
+C     TOUT  :IN     Next point where output is desired (.NE. T).
+C
+C     ITOL  :IN     1 or 2 according as ATOL (below) is a scalar or
+C                   an array.
+C
+C     RTOL  :IN     Relative tolerance parameter (scalar).
+C
+C     ATOL  :IN     Absolute tolerance parameter (scalar or array).
+C                   If ITOL = 1, ATOL need not be dimensioned.
+C                   If ITOL = 2, ATOL must be dimensioned at least NEQ.
+C
+C                   The estimated local error in Y(i) will be controlled
+C                   so as to be roughly less (in magnitude) than
+C
+C                   EWT(i) = RTOL*ABS(Y(i)) + ATOL     if ITOL = 1, or
+C                   EWT(i) = RTOL*ABS(Y(i)) + ATOL(i)  if ITOL = 2.
+C
+C                   Thus the local error test passes if, in each
+C                   component, either the absolute error is less than
+C                   ATOL (or ATOL(i)), or the relative error is less
+C                   than RTOL.
 C
-C B. NEXT DETERMINE (OR GUESS) WHETHER OR NOT THE PROBLEM IS STIFF.
-C STIFFNESS OCCURS WHEN THE JACOBIAN MATRIX DF/DY HAS AN EIGENVALUE
-C WHOSE REAL PART IS NEGATIVE AND LARGE IN MAGNITUDE, COMPARED TO THE
-C RECIPROCAL OF THE T SPAN OF INTEREST.  IF THE PROBLEM IS NONSTIFF,
-C USE A METHOD FLAG MF = 10.  IF IT IS STIFF, THERE ARE FOUR STANDARD
-C CHOICES FOR MF, AND LSODE REQUIRES THE JACOBIAN MATRIX IN SOME FORM.
-C THIS MATRIX IS REGARDED EITHER AS FULL (MF = 21 OR 22),
-C OR BANDED (MF = 24 OR 25).  IN THE BANDED CASE, LSODE REQUIRES TWO
-C HALF-BANDWIDTH PARAMETERS ML AND MU.  THESE ARE, RESPECTIVELY, THE
-C WIDTHS OF THE LOWER AND UPPER PARTS OF THE BAND, EXCLUDING THE MAIN
-C DIAGONAL.  THUS THE BAND CONSISTS OF THE LOCATIONS (I,J) WITH
-C I-ML .LE. J .LE. I+MU, AND THE FULL BANDWIDTH IS ML+MU+1.
+C                   Use RTOL = 0.0 for pure absolute error control, and
+C                   use ATOL = 0.0 (or ATOL(i) = 0.0) for pure relative
+C                   error control.  Caution:  Actual (global) errors may
+C                   exceed these local tolerances, so choose them
+C                   conservatively.
+C
+C     ITASK :IN     Flag indicating the task DLSODE is to perform.
+C                   Use ITASK = 1 for normal computation of output
+C                   values of y at t = TOUT.
 C
-C C. IF THE PROBLEM IS STIFF, YOU ARE ENCOURAGED TO SUPPLY THE JACOBIAN
-C DIRECTLY (MF = 21 OR 24), BUT IF THIS IS NOT FEASIBLE, LSODE WILL
-C COMPUTE IT INTERNALLY BY DIFFERENCE QUOTIENTS (MF = 22 OR 25).
-C IF YOU ARE SUPPLYING THE JACOBIAN, PROVIDE A SUBROUTINE OF THE FORM..
-C               SUBROUTINE JAC (NEQ, T, Y, ML, MU, PD, NROWPD)
-C               DIMENSION Y(NEQ), PD(NROWPD,NEQ)
-C WHICH SUPPLIES DF/DY BY LOADING PD AS FOLLOWS..
-C     FOR A FULL JACOBIAN (MF = 21), LOAD PD(I,J) WITH DF(I)/DY(J),
-C THE PARTIAL DERIVATIVE OF F(I) WITH RESPECT TO Y(J).  (IGNORE THE
-C ML AND MU ARGUMENTS IN THIS CASE.)
-C     FOR A BANDED JACOBIAN (MF = 24), LOAD PD(I-J+MU+1,J) WITH
-C DF(I)/DY(J), I.E. LOAD THE DIAGONAL LINES OF DF/DY INTO THE ROWS OF
-C PD FROM THE TOP DOWN.
-C     IN EITHER CASE, ONLY NONZERO ELEMENTS NEED BE LOADED.
+C     ISTATE:INOUT  Index used for input and output to specify the state
+C                   of the calculation.
+C                   Input:
+C                    1   This is the first call for a problem.
+C                    2   This is a subsequent call.
+C                   Output:
+C                    1   Nothing was done, because TOUT was equal to T.
+C                    2   DLSODE was successful (otherwise, negative).
+C                        Note that ISTATE need not be modified after a
+C                        successful return.
+C                   -1   Excess work done on this call (perhaps wrong
+C                        MF).
+C                   -2   Excess accuracy requested (tolerances too
+C                        small).
+C                   -3   Illegal input detected (see printed message).
+C                   -4   Repeated error test failures (check all
+C                        inputs).
+C                   -5   Repeated convergence failures (perhaps bad
+C                        Jacobian supplied or wrong choice of MF or
+C                        tolerances).
+C                   -6   Error weight became zero during problem
+C                        (solution component i vanished, and ATOL or
+C                        ATOL(i) = 0.).
+C
+C     IOPT  :IN     Flag indicating whether optional inputs are used:
+C                   0   No.
+C                   1   Yes.  (See "Optional inputs" under "Long
+C                       Description," Part 1.)
 C
-C D. WRITE A MAIN PROGRAM WHICH CALLS SUBROUTINE LSODE ONCE FOR
-C EACH POINT AT WHICH ANSWERS ARE DESIRED.  THIS SHOULD ALSO PROVIDE
-C FOR POSSIBLE USE OF LOGICAL UNIT 6 FOR OUTPUT OF ERROR MESSAGES
-C BY LSODE.  ON THE FIRST CALL TO LSODE, SUPPLY ARGUMENTS AS FOLLOWS..
-C F      = NAME OF SUBROUTINE FOR RIGHT-HAND SIDE VECTOR F.
-C          THIS NAME MUST BE DECLARED EXTERNAL IN CALLING PROGRAM.
-C NEQ    = NUMBER OF FIRST ORDER ODE-S.
-C Y      = ARRAY OF INITIAL VALUES, OF LENGTH NEQ.
-C T      = THE INITIAL VALUE OF THE INDEPENDENT VARIABLE.
-C TOUT   = FIRST POINT WHERE OUTPUT IS DESIRED (.NE. T).
-C ITOL   = 1 OR 2 ACCORDING AS ATOL (BELOW) IS A SCALAR OR ARRAY.
-C RTOL   = RELATIVE TOLERANCE PARAMETER (SCALAR).
-C ATOL   = ABSOLUTE TOLERANCE PARAMETER (SCALAR OR ARRAY).
-C          THE ESTIMATED LOCAL ERROR IN Y(I) WILL BE CONTROLLED SO AS
-C          TO BE ROUGHLY LESS (IN MAGNITUDE) THAN
-C             EWT(I) = RTOL*ABS(Y(I)) + ATOL     IF ITOL = 1, OR
-C             EWT(I) = RTOL*ABS(Y(I)) + ATOL(I)  IF ITOL = 2.
-C          THUS THE LOCAL ERROR TEST PASSES IF, IN EACH COMPONENT,
-C          EITHER THE ABSOLUTE ERROR IS LESS THAN ATOL (OR ATOL(I)),
-C          OR THE RELATIVE ERROR IS LESS THAN RTOL.
-C          USE RTOL = 0.0 FOR PURE ABSOLUTE ERROR CONTROL, AND
-C          USE ATOL = 0.0 (OR ATOL(I) = 0.0) FOR PURE RELATIVE ERROR
-C          CONTROL.  CAUTION.. ACTUAL (GLOBAL) ERRORS MAY EXCEED THESE
-C          LOCAL TOLERANCES, SO CHOOSE THEM CONSERVATIVELY.
-C ITASK  = 1 FOR NORMAL COMPUTATION OF OUTPUT VALUES OF Y AT T = TOUT.
-C ISTATE = INTEGER FLAG (INPUT AND OUTPUT).  SET ISTATE = 1.
-C IOPT   = 0 TO INDICATE NO OPTIONAL INPUTS USED.
-C RWORK  = REAL WORK ARRAY OF LENGTH AT LEAST..
-C             20 + 16*NEQ                    FOR MF = 10,
-C             22 +  9*NEQ + NEQ**2           FOR MF = 21 OR 22,
-C             22 + 10*NEQ + (2*ML + MU)*NEQ  FOR MF = 24 OR 25.
-C LRW    = DECLARED LENGTH OF RWORK (IN USER-S DIMENSION).
-C IWORK  = INTEGER WORK ARRAY OF LENGTH AT LEAST..
-C             20        FOR MF = 10,
-C             20 + NEQ  FOR MF = 21, 22, 24, OR 25.
-C          IF MF = 24 OR 25, INPUT IN IWORK(1),IWORK(2) THE LOWER
-C          AND UPPER HALF-BANDWIDTHS ML,MU.
-C LIW    = DECLARED LENGTH OF IWORK (IN USER-S DIMENSION).
-C JAC    = NAME OF SUBROUTINE FOR JACOBIAN MATRIX (MF = 21 OR 24).
-C          IF USED, THIS NAME MUST BE DECLARED EXTERNAL IN CALLING
-C          PROGRAM.  IF NOT USED, PASS A DUMMY NAME.
-C MF     = METHOD FLAG.  STANDARD VALUES ARE..
-C          10 FOR NONSTIFF (ADAMS) METHOD, NO JACOBIAN USED.
-C          21 FOR STIFF (BDF) METHOD, USER-SUPPLIED FULL JACOBIAN.
-C          22 FOR STIFF METHOD, INTERNALLY GENERATED FULL JACOBIAN.
-C          24 FOR STIFF METHOD, USER-SUPPLIED BANDED JACOBIAN.
-C          25 FOR STIFF METHOD, INTERNALLY GENERATED BANDED JACOBIAN.
-C NOTE THAT THE MAIN PROGRAM MUST DECLARE ARRAYS Y, RWORK, IWORK,
-C AND POSSIBLY ATOL.
+C     RWORK :WORK   Real work array of length at least:
+C                   20 + 16*NEQ                    for MF = 10,
+C                   22 +  9*NEQ + NEQ**2           for MF = 21 or 22,
+C                   22 + 10*NEQ + (2*ML + MU)*NEQ  for MF = 24 or 25.
+C
+C     LRW   :IN     Declared length of RWORK (in user's DIMENSION
+C                   statement).
+C
+C     IWORK :WORK   Integer work array of length at least:
+C                   20        for MF = 10,
+C                   20 + NEQ  for MF = 21, 22, 24, or 25.
+C
+C                   If MF = 24 or 25, input in IWORK(1),IWORK(2) the
+C                   lower and upper Jacobian half-bandwidths ML,MU.
+C
+C                   On return, IWORK contains information that may be
+C                   of interest to the user:
 C
-C E. THE OUTPUT FROM THE FIRST CALL (OR ANY CALL) IS..
-C      Y = ARRAY OF COMPUTED VALUES OF Y(T) VECTOR.
-C      T = CORRESPONDING VALUE OF INDEPENDENT VARIABLE (NORMALLY TOUT).
-C ISTATE = 2  IF LSODE WAS SUCCESSFUL, NEGATIVE OTHERWISE.
-C          -1 MEANS EXCESS WORK DONE ON THIS CALL (PERHAPS WRONG MF).
-C          -2 MEANS EXCESS ACCURACY REQUESTED (TOLERANCES TOO SMALL).
-C          -3 MEANS ILLEGAL INPUT DETECTED (SEE PRINTED MESSAGE).
-C          -4 MEANS REPEATED ERROR TEST FAILURES (CHECK ALL INPUTS).
-C          -5 MEANS REPEATED CONVERGENCE FAILURES (PERHAPS BAD JACOBIAN
-C             SUPPLIED OR WRONG CHOICE OF MF OR TOLERANCES).
-C          -6 MEANS ERROR WEIGHT BECAME ZERO DURING PROBLEM. (SOLUTION
-C             COMPONENT I VANISHED, AND ATOL OR ATOL(I) = 0.)
-C         -13 MEANS EXIT REQUESTED IN USER-SUPPLIED FUNCTION.
+C            Name   Location   Meaning
+C            -----  ---------  -----------------------------------------
+C            NST    IWORK(11)  Number of steps taken for the problem so
+C                              far.
+C            NFE    IWORK(12)  Number of f evaluations for the problem
+C                              so far.
+C            NJE    IWORK(13)  Number of Jacobian evaluations (and of
+C                              matrix LU decompositions) for the problem
+C                              so far.
+C            NQU    IWORK(14)  Method order last used (successfully).
+C            LENRW  IWORK(17)  Length of RWORK actually required.  This
+C                              is defined on normal returns and on an
+C                              illegal input return for insufficient
+C                              storage.
+C            LENIW  IWORK(18)  Length of IWORK actually required.  This
+C                              is defined on normal returns and on an
+C                              illegal input return for insufficient
+C                              storage.
+C
+C     LIW   :IN     Declared length of IWORK (in user's DIMENSION
+C                   statement).
+C
+C     JAC   :EXT    Name of subroutine for Jacobian matrix (MF =
+C                   21 or 24).  If used, this name must be declared
+C                   EXTERNAL in calling program.  If not used, pass a
+C                   dummy name.  The form of JAC must be:
 C
-C F. TO CONTINUE THE INTEGRATION AFTER A SUCCESSFUL RETURN, SIMPLY
-C RESET TOUT AND CALL LSODE AGAIN.  NO OTHER PARAMETERS NEED BE RESET.
+C                   SUBROUTINE JAC (NEQ, T, Y, ML, MU, PD, NROWPD)
+C                   INTEGER  NEQ, ML, MU, NROWPD
+C                   DOUBLE PRECISION  T, Y(*), PD(NROWPD,*)
+C
+C                   See item c, under "Description" below for more
+C                   information about JAC.
 C
-C-----------------------------------------------------------------------
-C EXAMPLE PROBLEM.
+C     MF    :IN     Method flag.  Standard values are:
+C                   10  Nonstiff (Adams) method, no Jacobian used.
+C                   21  Stiff (BDF) method, user-supplied full Jacobian.
+C                   22  Stiff method, internally generated full
+C                       Jacobian.
+C                   24  Stiff method, user-supplied banded Jacobian.
+C                   25  Stiff method, internally generated banded
+C                       Jacobian.
+C
+C *Description:
+C     DLSODE solves the initial value problem for stiff or nonstiff
+C     systems of first-order ODE's,
+C
+C        dy/dt = f(t,y) ,
+C
+C     or, in component form,
+C
+C        dy(i)/dt = f(i) = f(i,t,y(1),y(2),...,y(NEQ))
+C                                                  (i = 1, ..., NEQ) .
 C
-C THE FOLLOWING IS A SIMPLE EXAMPLE PROBLEM, WITH THE CODING
-C NEEDED FOR ITS SOLUTION BY LSODE.  THE PROBLEM IS FROM CHEMICAL
-C KINETICS, AND CONSISTS OF THE FOLLOWING THREE RATE EQUATIONS..
-C     DY1/DT = -.04*Y1 + 1.E4*Y2*Y3
-C     DY2/DT = .04*Y1 - 1.E4*Y2*Y3 - 3.E7*Y2**2
-C     DY3/DT = 3.E7*Y2**2
-C ON THE INTERVAL FROM T = 0.0 TO T = 4.E10, WITH INITIAL CONDITIONS
-C Y1 = 1.0, Y2 = Y3 = 0.  THE PROBLEM IS STIFF.
+C     DLSODE is a package based on the GEAR and GEARB packages, and on
+C     the October 23, 1978, version of the tentative ODEPACK user
+C     interface standard, with minor modifications.
+C
+C     The steps in solving such a problem are as follows.
+C
+C     a. First write a subroutine of the form
+C
+C           SUBROUTINE  F (NEQ, T, Y, YDOT)
+C           INTEGER  NEQ
+C           DOUBLE PRECISION  T, Y(*), YDOT(*)
+C
+C        which supplies the vector function f by loading YDOT(i) with
+C        f(i).
 C
-C THE FOLLOWING CODING SOLVES THIS PROBLEM WITH LSODE, USING MF = 21
-C AND PRINTING RESULTS AT T = .4, 4., ..., 4.E10.  IT USES
-C ITOL = 2 AND ATOL MUCH SMALLER FOR Y2 THAN Y1 OR Y3 BECAUSE
-C Y2 HAS MUCH SMALLER VALUES.
-C AT THE END OF THE RUN, STATISTICAL QUANTITIES OF INTEREST ARE
-C PRINTED (SEE OPTIONAL OUTPUTS IN THE FULL DESCRIPTION BELOW).
+C     b. Next determine (or guess) whether or not the problem is stiff.
+C        Stiffness occurs when the Jacobian matrix df/dy has an
+C        eigenvalue whose real part is negative and large in magnitude
+C        compared to the reciprocal of the t span of interest.  If the
+C        problem is nonstiff, use method flag MF = 10.  If it is stiff,
+C        there are four standard choices for MF, and DLSODE requires the
+C        Jacobian matrix in some form.  This matrix is regarded either
+C        as full (MF = 21 or 22), or banded (MF = 24 or 25).  In the
+C        banded case, DLSODE requires two half-bandwidth parameters ML
+C        and MU. These are, respectively, the widths of the lower and
+C        upper parts of the band, excluding the main diagonal.  Thus the
+C        band consists of the locations (i,j) with
+C
+C           i - ML <= j <= i + MU ,
+C
+C        and the full bandwidth is ML + MU + 1 .
 C
-C     EXTERNAL FEX, JEX
-C     DOUBLE PRECISION ATOL, RTOL, RWORK, T, TOUT, Y
-C     DIMENSION Y(3), ATOL(3), RWORK(58), IWORK(23)
-C     NEQ = 3
-C     Y(1) = 1.D0
-C     Y(2) = 0.D0
-C     Y(3) = 0.D0
-C     T = 0.D0
-C     TOUT = .4D0
-C     ITOL = 2
-C     RTOL = 1.D-4
-C     ATOL(1) = 1.D-6
-C     ATOL(2) = 1.D-10
-C     ATOL(3) = 1.D-6
-C     ITASK = 1
-C     ISTATE = 1
-C     IOPT = 0
-C     LRW = 58
-C     LIW = 23
-C     MF = 21
-C     DO 40 IOUT = 1,12
-C       CALL LSODE(FEX,NEQ,Y,T,TOUT,ITOL,RTOL,ATOL,ITASK,ISTATE,
-C    1     IOPT,RWORK,LRW,IWORK,LIW,JEX,MF)
-C       WRITE(6,20)T,Y(1),Y(2),Y(3)
-C 20    FORMAT(7H AT T =,E12.4,6H   Y =,3E14.6)
-C       IF (ISTATE .LT. 0) GO TO 80
-C 40    TOUT = TOUT*10.D0
-C     WRITE(6,60)IWORK(11),IWORK(12),IWORK(13)
-C 60  FORMAT(/12H NO. STEPS =,I4,11H  NO. F-S =,I4,11H  NO. J-S =,I4)
-C     STOP
-C 80  WRITE(6,90)ISTATE
-C 90  FORMAT(///22H ERROR HALT.. ISTATE =,I3)
-C     STOP
-C     END
+C     c. If the problem is stiff, you are encouraged to supply the
+C        Jacobian directly (MF = 21 or 24), but if this is not feasible,
+C        DLSODE will compute it internally by difference quotients (MF =
+C        22 or 25).  If you are supplying the Jacobian, write a
+C        subroutine of the form
+C
+C           SUBROUTINE  JAC (NEQ, T, Y, ML, MU, PD, NROWPD)
+C           INTEGER  NEQ, ML, MU, NRWOPD
+C           DOUBLE PRECISION  T, Y(*), PD(NROWPD,*)
+C
+C        which provides df/dy by loading PD as follows:
+C        - For a full Jacobian (MF = 21), load PD(i,j) with df(i)/dy(j),
+C          the partial derivative of f(i) with respect to y(j).  (Ignore
+C          the ML and MU arguments in this case.)
+C        - For a banded Jacobian (MF = 24), load PD(i-j+MU+1,j) with
+C          df(i)/dy(j); i.e., load the diagonal lines of df/dy into the
+C          rows of PD from the top down.
+C        - In either case, only nonzero elements need be loaded.
 C
-C     SUBROUTINE FEX (NEQ, T, Y, YDOT)
-C     DOUBLE PRECISION T, Y, YDOT
-C     DIMENSION Y(3), YDOT(3)
-C     YDOT(1) = -.04D0*Y(1) + 1.D4*Y(2)*Y(3)
-C     YDOT(3) = 3.D7*Y(2)*Y(2)
-C     YDOT(2) = -YDOT(1) - YDOT(3)
-C     RETURN
-C     END
+C     d. Write a main program that calls subroutine DLSODE once for each
+C        point at which answers are desired.  This should also provide
+C        for possible use of logical unit 6 for output of error messages
+C        by DLSODE.
+C
+C        Before the first call to DLSODE, set ISTATE = 1, set Y and T to
+C        the initial values, and set TOUT to the first output point.  To
+C        continue the integration after a successful return, simply
+C        reset TOUT and call DLSODE again.  No other parameters need be
+C        reset.
 C
-C     SUBROUTINE JEX (NEQ, T, Y, ML, MU, PD, NRPD)
-C     DOUBLE PRECISION PD, T, Y
-C     DIMENSION Y(3), PD(NRPD,3)
-C     PD(1,1) = -.04D0
-C     PD(1,2) = 1.D4*Y(3)
-C     PD(1,3) = 1.D4*Y(2)
-C     PD(2,1) = .04D0
-C     PD(2,3) = -PD(1,3)
-C     PD(3,2) = 6.D7*Y(2)
-C     PD(2,2) = -PD(1,2) - PD(3,2)
-C     RETURN
-C     END
+C *Examples:
+C     The following is a simple example problem, with the coding needed
+C     for its solution by DLSODE. The problem is from chemical kinetics,
+C     and consists of the following three rate equations:
 C
-C THE OUTPUT OF THIS PROGRAM (ON A CDC-7600 IN SINGLE PRECISION)
-C IS AS FOLLOWS..
+C        dy1/dt = -.04*y1 + 1.E4*y2*y3
+C        dy2/dt = .04*y1 - 1.E4*y2*y3 - 3.E7*y2**2
+C        dy3/dt = 3.E7*y2**2
+C
+C     on the interval from t = 0.0 to t = 4.E10, with initial conditions
+C     y1 = 1.0, y2 = y3 = 0. The problem is stiff.
 C
-C   AT T =  4.0000E-01   Y =  9.851726E-01  3.386406E-05  1.479357E-02
-C   AT T =  4.0000E+00   Y =  9.055142E-01  2.240418E-05  9.446344E-02
-C   AT T =  4.0000E+01   Y =  7.158050E-01  9.184616E-06  2.841858E-01
-C   AT T =  4.0000E+02   Y =  4.504846E-01  3.222434E-06  5.495122E-01
-C   AT T =  4.0000E+03   Y =  1.831701E-01  8.940379E-07  8.168290E-01
-C   AT T =  4.0000E+04   Y =  3.897016E-02  1.621193E-07  9.610297E-01
-C   AT T =  4.0000E+05   Y =  4.935213E-03  1.983756E-08  9.950648E-01
-C   AT T =  4.0000E+06   Y =  5.159269E-04  2.064759E-09  9.994841E-01
-C   AT T =  4.0000E+07   Y =  5.306413E-05  2.122677E-10  9.999469E-01
-C   AT T =  4.0000E+08   Y =  5.494529E-06  2.197824E-11  9.999945E-01
-C   AT T =  4.0000E+09   Y =  5.129458E-07  2.051784E-12  9.999995E-01
-C   AT T =  4.0000E+10   Y = -7.170586E-08 -2.868234E-13  1.000000E+00
-C
-C   NO. STEPS = 330  NO. F-S = 405  NO. J-S =  69
-C-----------------------------------------------------------------------
-C FULL DESCRIPTION OF USER INTERFACE TO LSODE.
-C
-C THE USER INTERFACE TO LSODE CONSISTS OF THE FOLLOWING PARTS.
-C
-C I.   THE CALL SEQUENCE TO SUBROUTINE LSODE, WHICH IS A DRIVER
-C      ROUTINE FOR THE SOLVER.  THIS INCLUDES DESCRIPTIONS OF BOTH
-C      THE CALL SEQUENCE ARGUMENTS AND OF USER-SUPPLIED ROUTINES.
-C      FOLLOWING THESE DESCRIPTIONS IS A DESCRIPTION OF
-C      OPTIONAL INPUTS AVAILABLE THROUGH THE CALL SEQUENCE, AND THEN
-C      A DESCRIPTION OF OPTIONAL OUTPUTS (IN THE WORK ARRAYS).
+C     The following coding solves this problem with DLSODE, using 
+C     MF = 21 and printing results at t = .4, 4., ..., 4.E10.  It uses 
+C     ITOL = 2 and ATOL much smaller for y2 than for y1 or y3 because y2 
+C     has much smaller values.  At the end of the run, statistical 
+C     quantities of interest are printed.
 C
-C II.  DESCRIPTIONS OF OTHER ROUTINES IN THE LSODE PACKAGE THAT MAY BE
-C      (OPTIONALLY) CALLED BY THE USER.  THESE PROVIDE THE ABILITY TO
-C      ALTER ERROR MESSAGE HANDLING, SAVE AND RESTORE THE INTERNAL
-C      COMMON, AND OBTAIN SPECIFIED DERIVATIVES OF THE SOLUTION Y(T).
-C
-C III. DESCRIPTIONS OF COMMON BLOCKS TO BE DECLARED IN OVERLAY
-C      OR SIMILAR ENVIRONMENTS, OR TO BE SAVED WHEN DOING AN INTERRUPT
-C      OF THE PROBLEM AND CONTINUED SOLUTION LATER.
-C
-C IV.  DESCRIPTION OF TWO ROUTINES IN THE LSODE PACKAGE, EITHER OF
-C      WHICH THE USER MAY REPLACE WITH HIS OWN VERSION, IF DESIRED.
-C      THESE RELATE TO THE MEASUREMENT OF ERRORS.
+C        EXTERNAL  FEX, JEX
+C        INTEGER  IOPT, IOUT, ISTATE, ITASK, ITOL, IWORK(23), LIW, LRW,
+C       *         MF, NEQ
+C        DOUBLE PRECISION  ATOL(3), RTOL, RWORK(58), T, TOUT, Y(3)
+C        NEQ = 3
+C        Y(1) = 1.D0
+C        Y(2) = 0.D0
+C        Y(3) = 0.D0
+C        T = 0.D0
+C        TOUT = .4D0
+C        ITOL = 2
+C        RTOL = 1.D-4
+C        ATOL(1) = 1.D-6
+C        ATOL(2) = 1.D-10
+C        ATOL(3) = 1.D-6
+C        ITASK = 1
+C        ISTATE = 1
+C        IOPT = 0
+C        LRW = 58
+C        LIW = 23
+C        MF = 21
+C        DO 40 IOUT = 1,12
+C          CALL DLSODE (FEX, NEQ, Y, T, TOUT, ITOL, RTOL, ATOL, ITASK,
+C       *               ISTATE, IOPT, RWORK, LRW, IWORK, LIW, JEX, MF)
+C          WRITE(6,20)  T, Y(1), Y(2), Y(3)
+C    20    FORMAT(' At t =',D12.4,'   y =',3D14.6)
+C          IF (ISTATE .LT. 0)  GO TO 80
+C    40    TOUT = TOUT*10.D0
+C        WRITE(6,60)  IWORK(11), IWORK(12), IWORK(13)
+C    60  FORMAT(/' No. steps =',i4,',  No. f-s =',i4,',  No. J-s =',i4)
+C        STOP
+C    80  WRITE(6,90)  ISTATE
+C    90  FORMAT(///' Error halt.. ISTATE =',I3)
+C        STOP
+C        END
 C
-C-----------------------------------------------------------------------
-C PART I.  CALL SEQUENCE.
+C        SUBROUTINE  FEX (NEQ, T, Y, YDOT)
+C        INTEGER  NEQ
+C        DOUBLE PRECISION  T, Y(3), YDOT(3)
+C        YDOT(1) = -.04D0*Y(1) + 1.D4*Y(2)*Y(3)
+C        YDOT(3) = 3.D7*Y(2)*Y(2)
+C        YDOT(2) = -YDOT(1) - YDOT(3)
+C        RETURN
+C        END
 C
-C THE CALL SEQUENCE PARAMETERS USED FOR INPUT ONLY ARE
-C     F, NEQ, TOUT, ITOL, RTOL, ATOL, ITASK, IOPT, LRW, LIW, JAC, MF,
-C AND THOSE USED FOR BOTH INPUT AND OUTPUT ARE
-C     Y, T, ISTATE.
-C THE WORK ARRAYS RWORK AND IWORK ARE ALSO USED FOR CONDITIONAL AND
-C OPTIONAL INPUTS AND OPTIONAL OUTPUTS.  (THE TERM OUTPUT HERE REFERS
-C TO THE RETURN FROM SUBROUTINE LSODE TO THE USER-S CALLING PROGRAM.)
+C        SUBROUTINE  JEX (NEQ, T, Y, ML, MU, PD, NRPD)
+C        INTEGER  NEQ, ML, MU, NRPD
+C        DOUBLE PRECISION  T, Y(3), PD(NRPD,3)
+C        PD(1,1) = -.04D0
+C        PD(1,2) = 1.D4*Y(3)
+C        PD(1,3) = 1.D4*Y(2)
+C        PD(2,1) = .04D0
+C        PD(2,3) = -PD(1,3)
+C        PD(3,2) = 6.D7*Y(2)
+C        PD(2,2) = -PD(1,2) - PD(3,2)
+C        RETURN
+C        END
 C
-C THE LEGALITY OF INPUT PARAMETERS WILL BE THOROUGHLY CHECKED ON THE
-C INITIAL CALL FOR THE PROBLEM, BUT NOT CHECKED THEREAFTER UNLESS A
-C CHANGE IN INPUT PARAMETERS IS FLAGGED BY ISTATE = 3 ON INPUT.
+C     The output from this program (on a Cray-1 in single precision)
+C     is as follows.
 C
-C THE DESCRIPTIONS OF THE CALL ARGUMENTS ARE AS FOLLOWS.
+C     At t =  4.0000e-01   y =  9.851726e-01  3.386406e-05  1.479357e-02
+C     At t =  4.0000e+00   y =  9.055142e-01  2.240418e-05  9.446344e-02
+C     At t =  4.0000e+01   y =  7.158050e-01  9.184616e-06  2.841858e-01
+C     At t =  4.0000e+02   y =  4.504846e-01  3.222434e-06  5.495122e-01
+C     At t =  4.0000e+03   y =  1.831701e-01  8.940379e-07  8.168290e-01
+C     At t =  4.0000e+04   y =  3.897016e-02  1.621193e-07  9.610297e-01
+C     At t =  4.0000e+05   y =  4.935213e-03  1.983756e-08  9.950648e-01
+C     At t =  4.0000e+06   y =  5.159269e-04  2.064759e-09  9.994841e-01
+C     At t =  4.0000e+07   y =  5.306413e-05  2.122677e-10  9.999469e-01
+C     At t =  4.0000e+08   y =  5.494530e-06  2.197825e-11  9.999945e-01
+C     At t =  4.0000e+09   y =  5.129458e-07  2.051784e-12  9.999995e-01
+C     At t =  4.0000e+10   y = -7.170603e-08 -2.868241e-13  1.000000e+00
+C
+C     No. steps = 330,  No. f-s = 405,  No. J-s = 69
 C
-C F      = THE NAME OF THE USER-SUPPLIED SUBROUTINE DEFINING THE
-C          ODE SYSTEM.  THE SYSTEM MUST BE PUT IN THE FIRST-ORDER
-C          FORM DY/DT = F(T,Y), WHERE F IS A VECTOR-VALUED FUNCTION
-C          OF THE SCALAR T AND THE VECTOR Y.  SUBROUTINE F IS TO
-C          COMPUTE THE FUNCTION F.  IT IS TO HAVE THE FORM
-C               SUBROUTINE F (NEQ, T, Y, YDOT)
-C               DIMENSION Y(1), YDOT(1)
-C          WHERE NEQ, T, AND Y ARE INPUT, AND THE ARRAY YDOT = F(T,Y)
-C          IS OUTPUT.  Y AND YDOT ARE ARRAYS OF LENGTH NEQ.
-C          (IN THE DIMENSION STATEMENT ABOVE, 1 IS A DUMMY
-C          DIMENSION.. IT CAN BE REPLACED BY ANY VALUE.)
-C          SUBROUTINE F SHOULD NOT ALTER Y(1),...,Y(NEQ).
-C          F MUST BE DECLARED EXTERNAL IN THE CALLING PROGRAM.
+C *Accuracy:
+C     The accuracy of the solution depends on the choice of tolerances
+C     RTOL and ATOL.  Actual (global) errors may exceed these local
+C     tolerances, so choose them conservatively.
 C
-C          SUBROUTINE F MAY ACCESS USER-DEFINED QUANTITIES IN
-C          NEQ(2),... AND/OR IN Y(NEQ(1)+1),... IF NEQ IS AN ARRAY
-C          (DIMENSIONED IN F) AND/OR Y HAS LENGTH EXCEEDING NEQ(1).
-C          SEE THE DESCRIPTIONS OF NEQ AND Y BELOW.
+C *Cautions:
+C     The work arrays should not be altered between calls to DLSODE for
+C     the same problem, except possibly for the conditional and optional
+C     inputs.
 C
-C          IF QUANTITIES COMPUTED IN THE F ROUTINE ARE NEEDED
-C          EXTERNALLY TO LSODE, AN EXTRA CALL TO F SHOULD BE MADE
-C          FOR THIS PURPOSE, FOR CONSISTENT AND ACCURATE RESULTS.
-C          IF ONLY THE DERIVATIVE DY/DT IS NEEDED, USE INTDY INSTEAD.
+C *Portability:
+C     Since NEQ is dimensioned inside DLSODE, some compilers may object
+C     to a call to DLSODE with NEQ a scalar variable.  In this event, 
+C     use DIMENSION NEQ(1).  Similar remarks apply to RTOL and ATOL.
+C
+C     Note to Cray users:
+C     For maximum efficiency, use the CFT77 compiler.  Appropriate
+C     compiler optimization directives have been inserted for CFT77.
 C
-C NEQ    = THE SIZE OF THE ODE SYSTEM (NUMBER OF FIRST ORDER
-C          ORDINARY DIFFERENTIAL EQUATIONS).  USED ONLY FOR INPUT.
-C          NEQ MAY BE DECREASED, BUT NOT INCREASED, DURING THE PROBLEM.
-C          IF NEQ IS DECREASED (WITH ISTATE = 3 ON INPUT), THE
-C          REMAINING COMPONENTS OF Y SHOULD BE LEFT UNDISTURBED, IF
-C          THESE ARE TO BE ACCESSED IN F AND/OR JAC.
+C *Reference:
+C     Alan C. Hindmarsh, "ODEPACK, A Systematized Collection of ODE
+C     Solvers," in Scientific Computing, R. S. Stepleman, et al., Eds.
+C     (North-Holland, Amsterdam, 1983), pp. 55-64.
+C
+C *Long Description:
+C     The following complete description of the user interface to
+C     DLSODE consists of four parts:
+C
+C     1.  The call sequence to subroutine DLSODE, which is a driver
+C         routine for the solver.  This includes descriptions of both
+C         the call sequence arguments and user-supplied routines.
+C         Following these descriptions is a description of optional
+C         inputs available through the call sequence, and then a
+C         description of optional outputs in the work arrays.
+C
+C     2.  Descriptions of other routines in the DLSODE package that may
+C         be (optionally) called by the user.  These provide the ability
+C         to alter error message handling, save and restore the internal
+C         COMMON, and obtain specified derivatives of the solution y(t).
 C
-C          NORMALLY, NEQ IS A SCALAR, AND IT IS GENERALLY REFERRED TO
-C          AS A SCALAR IN THIS USER INTERFACE DESCRIPTION.  HOWEVER,
-C          NEQ MAY BE AN ARRAY, WITH NEQ(1) SET TO THE SYSTEM SIZE.
-C          (THE LSODE PACKAGE ACCESSES ONLY NEQ(1).)  IN EITHER CASE,
-C          THIS PARAMETER IS PASSED AS THE NEQ ARGUMENT IN ALL CALLS
-C          TO F AND JAC.  HENCE, IF IT IS AN ARRAY, LOCATIONS
-C          NEQ(2),... MAY BE USED TO STORE OTHER INTEGER DATA AND PASS
-C          IT TO F AND/OR JAC.  SUBROUTINES F AND/OR JAC MUST INCLUDE
-C          NEQ IN A DIMENSION STATEMENT IN THAT CASE.
+C     3.  Descriptions of COMMON block to be declared in overlay or
+C         similar environments, or to be saved when doing an interrupt
+C         of the problem and continued solution later.
+C
+C     4.  Description of two routines in the DLSODE package, either of
+C         which the user may replace with his own version, if desired.
+C         These relate to the measurement of errors.
+C
 C
-C Y      = A REAL ARRAY FOR THE VECTOR OF DEPENDENT VARIABLES, OF
-C          LENGTH NEQ OR MORE.  USED FOR BOTH INPUT AND OUTPUT ON THE
-C          FIRST CALL (ISTATE = 1), AND ONLY FOR OUTPUT ON OTHER CALLS.
-C          ON THE FIRST CALL, Y MUST CONTAIN THE VECTOR OF INITIAL
-C          VALUES.  ON OUTPUT, Y CONTAINS THE COMPUTED SOLUTION VECTOR,
-C          EVALUATED AT T.  IF DESIRED, THE Y ARRAY MAY BE USED
-C          FOR OTHER PURPOSES BETWEEN CALLS TO THE SOLVER.
+C                         Part 1.  Call Sequence
+C                         ----------------------
 C
-C          THIS ARRAY IS PASSED AS THE Y ARGUMENT IN ALL CALLS TO
-C          F AND JAC.  HENCE ITS LENGTH MAY EXCEED NEQ, AND LOCATIONS
-C          Y(NEQ+1),... MAY BE USED TO STORE OTHER REAL DATA AND
-C          PASS IT TO F AND/OR JAC.  (THE LSODE PACKAGE ACCESSES ONLY
-C          Y(1),...,Y(NEQ).)
+C     Arguments
+C     ---------
+C     The call sequence parameters used for input only are
+C
+C        F, NEQ, TOUT, ITOL, RTOL, ATOL, ITASK, IOPT, LRW, LIW, JAC, MF,
+C
+C     and those used for both input and output are
+C
+C        Y, T, ISTATE.
 C
-C T      = THE INDEPENDENT VARIABLE.  ON INPUT, T IS USED ONLY ON THE
-C          FIRST CALL, AS THE INITIAL POINT OF THE INTEGRATION.
-C          ON OUTPUT, AFTER EACH CALL, T IS THE VALUE AT WHICH A
-C          COMPUTED SOLUTION Y IS EVALUATED (USUALLY THE SAME AS TOUT).
-C          ON AN ERROR RETURN, T IS THE FARTHEST POINT REACHED.
+C     The work arrays RWORK and IWORK are also used for conditional and
+C     optional inputs and optional outputs.  (The term output here
+C     refers to the return from subroutine DLSODE to the user's calling
+C     program.)
 C
-C TOUT   = THE NEXT VALUE OF T AT WHICH A COMPUTED SOLUTION IS DESIRED.
-C          USED ONLY FOR INPUT.
+C     The legality of input parameters will be thoroughly checked on the
+C     initial call for the problem, but not checked thereafter unless a
+C     change in input parameters is flagged by ISTATE = 3 on input.
+C
+C     The descriptions of the call arguments are as follows.
 C
-C          WHEN STARTING THE PROBLEM (ISTATE = 1), TOUT MAY BE EQUAL
-C          TO T FOR ONE CALL, THEN SHOULD .NE. T FOR THE NEXT CALL.
-C          FOR THE INITIAL T, AN INPUT VALUE OF TOUT .NE. T IS USED
-C          IN ORDER TO DETERMINE THE DIRECTION OF THE INTEGRATION
-C          (I.E. THE ALGEBRAIC SIGN OF THE STEP SIZES) AND THE ROUGH
-C          SCALE OF THE PROBLEM.  INTEGRATION IN EITHER DIRECTION
-C          (FORWARD OR BACKWARD IN T) IS PERMITTED.
+C     F        The name of the user-supplied subroutine defining the ODE
+C              system.  The system must be put in the first-order form
+C              dy/dt = f(t,y), where f is a vector-valued function of
+C              the scalar t and the vector y. Subroutine F is to compute
+C              the function f. It is to have the form
+C
+C                 SUBROUTINE F (NEQ, T, Y, YDOT)
+C                 DOUBLE PRECISION  T, Y(*), YDOT(*)
 C
-C          IF ITASK = 2 OR 5 (ONE-STEP MODES), TOUT IS IGNORED AFTER
-C          THE FIRST CALL (I.E. THE FIRST CALL WITH TOUT .NE. T).
-C          OTHERWISE, TOUT IS REQUIRED ON EVERY CALL.
+C              where NEQ, T, and Y are input, and the array YDOT =
+C              f(T,Y) is output.  Y and YDOT are arrays of length NEQ.
+C              Subroutine F should not alter Y(1),...,Y(NEQ).  F must be
+C              declared EXTERNAL in the calling program.
 C
-C          IF ITASK = 1, 3, OR 4, THE VALUES OF TOUT NEED NOT BE
-C          MONOTONE, BUT A VALUE OF TOUT WHICH BACKS UP IS LIMITED
-C          TO THE CURRENT INTERNAL T INTERVAL, WHOSE ENDPOINTS ARE
-C          TCUR - HU AND TCUR (SEE OPTIONAL OUTPUTS, BELOW, FOR
-C          TCUR AND HU).
+C              Subroutine F may access user-defined quantities in
+C              NEQ(2),... and/or in Y(NEQ(1)+1),..., if NEQ is an array
+C              (dimensioned in F) and/or Y has length exceeding NEQ(1).
+C              See the descriptions of NEQ and Y below.
 C
-C ITOL   = AN INDICATOR FOR THE TYPE OF ERROR CONTROL.  SEE
-C          DESCRIPTION BELOW UNDER ATOL.  USED ONLY FOR INPUT.
+C              If quantities computed in the F routine are needed
+C              externally to DLSODE, an extra call to F should be made
+C              for this purpose, for consistent and accurate results.
+C              If only the derivative dy/dt is needed, use DINTDY
+C              instead.
 C
-C RTOL   = A RELATIVE ERROR TOLERANCE PARAMETER, EITHER A SCALAR OR
-C          AN ARRAY OF LENGTH NEQ.  SEE DESCRIPTION BELOW UNDER ATOL.
-C          INPUT ONLY.
-C
-C ATOL   = AN ABSOLUTE ERROR TOLERANCE PARAMETER, EITHER A SCALAR OR
-C          AN ARRAY OF LENGTH NEQ.  INPUT ONLY.
+C     NEQ      The size of the ODE system (number of first-order
+C              ordinary differential equations).  Used only for input.
+C              NEQ may be decreased, but not increased, during the
+C              problem.  If NEQ is decreased (with ISTATE = 3 on input),
+C              the remaining components of Y should be left undisturbed,
+C              if these are to be accessed in F and/or JAC.
 C
-C             THE INPUT PARAMETERS ITOL, RTOL, AND ATOL DETERMINE
-C          THE ERROR CONTROL PERFORMED BY THE SOLVER.  THE SOLVER WILL
-C          CONTROL THE VECTOR E = (E(I)) OF ESTIMATED LOCAL ERRORS
-C          IN Y, ACCORDING TO AN INEQUALITY OF THE FORM
-C                      RMS-NORM OF ( E(I)/EWT(I) )   .LE.   1,
-C          WHERE       EWT(I) = RTOL(I)*ABS(Y(I)) + ATOL(I),
-C          AND THE RMS-NORM (ROOT-MEAN-SQUARE NORM) HERE IS
-C          RMS-NORM(V) = SQRT(SUM V(I)**2 / NEQ).  HERE EWT = (EWT(I))
-C          IS A VECTOR OF WEIGHTS WHICH MUST ALWAYS BE POSITIVE, AND
-C          THE VALUES OF RTOL AND ATOL SHOULD ALL BE NON-NEGATIVE.
-C          THE FOLLOWING TABLE GIVES THE TYPES (SCALAR/ARRAY) OF
-C          RTOL AND ATOL, AND THE CORRESPONDING FORM OF EWT(I).
+C              Normally, NEQ is a scalar, and it is generally referred
+C              to as a scalar in this user interface description.
+C              However, NEQ may be an array, with NEQ(1) set to the
+C              system size.  (The DLSODE package accesses only NEQ(1).)
+C              In either case, this parameter is passed as the NEQ
+C              argument in all calls to F and JAC.  Hence, if it is an
+C              array, locations NEQ(2),... may be used to store other
+C              integer data and pass it to F and/or JAC.  Subroutines
+C              F and/or JAC must include NEQ in a DIMENSION statement
+C              in that case.
 C
-C             ITOL    RTOL       ATOL          EWT(I)
-C              1     SCALAR     SCALAR     RTOL*ABS(Y(I)) + ATOL
-C              2     SCALAR     ARRAY      RTOL*ABS(Y(I)) + ATOL(I)
-C              3     ARRAY      SCALAR     RTOL(I)*ABS(Y(I)) + ATOL
-C              4     ARRAY      ARRAY      RTOL(I)*ABS(Y(I)) + ATOL(I)
+C     Y        A real array for the vector of dependent variables, of
+C              length NEQ or more.  Used for both input and output on
+C              the first call (ISTATE = 1), and only for output on
+C              other calls.  On the first call, Y must contain the
+C              vector of initial values.  On output, Y contains the
+C              computed solution vector, evaluated at T. If desired,
+C              the Y array may be used for other purposes between
+C              calls to the solver.
+C
+C              This array is passed as the Y argument in all calls to F
+C              and JAC.  Hence its length may exceed NEQ, and locations
+C              Y(NEQ+1),... may be used to store other real data and
+C              pass it to F and/or JAC.  (The DLSODE package accesses
+C              only Y(1),...,Y(NEQ).)
 C
-C          WHEN EITHER OF THESE PARAMETERS IS A SCALAR, IT NEED NOT
-C          BE DIMENSIONED IN THE USER-S CALLING PROGRAM.
+C     T        The independent variable.  On input, T is used only on
+C              the first call, as the initial point of the integration.
+C              On output, after each call, T is the value at which a
+C              computed solution Y is evaluated (usually the same as
+C              TOUT).  On an error return, T is the farthest point
+C              reached.
 C
-C          IF NONE OF THE ABOVE CHOICES (WITH ITOL, RTOL, AND ATOL
-C          FIXED THROUGHOUT THE PROBLEM) IS SUITABLE, MORE GENERAL
-C          ERROR CONTROLS CAN BE OBTAINED BY SUBSTITUTING
-C          USER-SUPPLIED ROUTINES FOR THE SETTING OF EWT AND/OR FOR
-C          THE NORM CALCULATION.  SEE PART IV BELOW.
+C     TOUT     The next value of T at which a computed solution is
+C              desired.  Used only for input.
 C
-C          IF GLOBAL ERRORS ARE TO BE ESTIMATED BY MAKING A REPEATED
-C          RUN ON THE SAME PROBLEM WITH SMALLER TOLERANCES, THEN ALL
-C          COMPONENTS OF RTOL AND ATOL (I.E. OF EWT) SHOULD BE SCALED
-C          DOWN UNIFORMLY.
+C              When starting the problem (ISTATE = 1), TOUT may be equal
+C              to T for one call, then should not equal T for the next
+C              call.  For the initial T, an input value of TOUT .NE. T
+C              is used in order to determine the direction of the
+C              integration (i.e., the algebraic sign of the step sizes)
+C              and the rough scale of the problem.  Integration in
+C              either direction (forward or backward in T) is permitted.
 C
-C ITASK  = AN INDEX SPECIFYING THE TASK TO BE PERFORMED.
-C          INPUT ONLY.  ITASK HAS THE FOLLOWING VALUES AND MEANINGS.
-C          1  MEANS NORMAL COMPUTATION OF OUTPUT VALUES OF Y(T) AT
-C             T = TOUT (BY OVERSHOOTING AND INTERPOLATING).
-C          2  MEANS TAKE ONE STEP ONLY AND RETURN.
-C          3  MEANS STOP AT THE FIRST INTERNAL MESH POINT AT OR
-C             BEYOND T = TOUT AND RETURN.
-C          4  MEANS NORMAL COMPUTATION OF OUTPUT VALUES OF Y(T) AT
-C             T = TOUT BUT WITHOUT OVERSHOOTING T = TCRIT.
-C             TCRIT MUST BE INPUT AS RWORK(1).  TCRIT MAY BE EQUAL TO
-C             OR BEYOND TOUT, BUT NOT BEHIND IT IN THE DIRECTION OF
-C             INTEGRATION.  THIS OPTION IS USEFUL IF THE PROBLEM
-C             HAS A SINGULARITY AT OR BEYOND T = TCRIT.
-C          5  MEANS TAKE ONE STEP, WITHOUT PASSING TCRIT, AND RETURN.
-C             TCRIT MUST BE INPUT AS RWORK(1).
+C              If ITASK = 2 or 5 (one-step modes), TOUT is ignored
+C              after the first call (i.e., the first call with
+C              TOUT .NE. T).  Otherwise, TOUT is required on every call.
+C
+C              If ITASK = 1, 3, or 4, the values of TOUT need not be
+C              monotone, but a value of TOUT which backs up is limited
+C              to the current internal T interval, whose endpoints are
+C              TCUR - HU and TCUR.  (See "Optional Outputs" below for
+C              TCUR and HU.)
+C
+C
+C     ITOL     An indicator for the type of error control.  See
+C              description below under ATOL.  Used only for input.
+C
+C     RTOL     A relative error tolerance parameter, either a scalar or
+C              an array of length NEQ.  See description below under
+C              ATOL.  Input only.
+C
+C     ATOL     An absolute error tolerance parameter, either a scalar or
+C              an array of length NEQ.  Input only.
 C
-C          NOTE..  IF ITASK = 4 OR 5 AND THE SOLVER REACHES TCRIT
-C          (WITHIN ROUNDOFF), IT WILL RETURN T = TCRIT (EXACTLY) TO
-C          INDICATE THIS (UNLESS ITASK = 4 AND TOUT COMES BEFORE TCRIT,
-C          IN WHICH CASE ANSWERS AT T = TOUT ARE RETURNED FIRST).
+C              The input parameters ITOL, RTOL, and ATOL determine the
+C              error control performed by the solver.  The solver will
+C              control the vector e = (e(i)) of estimated local errors
+C              in Y, according to an inequality of the form
+C
+C                 rms-norm of ( e(i)/EWT(i) ) <= 1,
+C
+C              where
 C
-C ISTATE = AN INDEX USED FOR INPUT AND OUTPUT TO SPECIFY THE
-C          THE STATE OF THE CALCULATION.
+C                 EWT(i) = RTOL(i)*ABS(Y(i)) + ATOL(i),
+C
+C              and the rms-norm (root-mean-square norm) here is
+C
+C                 rms-norm(v) = SQRT(sum v(i)**2 / NEQ).
+C
+C              Here EWT = (EWT(i)) is a vector of weights which must
+C              always be positive, and the values of RTOL and ATOL
+C              should all be nonnegative.  The following table gives the
+C              types (scalar/array) of RTOL and ATOL, and the
+C              corresponding form of EWT(i).
 C
-C          ON INPUT, THE VALUES OF ISTATE ARE AS FOLLOWS.
-C          1  MEANS THIS IS THE FIRST CALL FOR THE PROBLEM
-C             (INITIALIZATIONS WILL BE DONE).  SEE NOTE BELOW.
-C          2  MEANS THIS IS NOT THE FIRST CALL, AND THE CALCULATION
-C             IS TO CONTINUE NORMALLY, WITH NO CHANGE IN ANY INPUT
-C             PARAMETERS EXCEPT POSSIBLY TOUT AND ITASK.
-C             (IF ITOL, RTOL, AND/OR ATOL ARE CHANGED BETWEEN CALLS
-C             WITH ISTATE = 2, THE NEW VALUES WILL BE USED BUT NOT
-C             TESTED FOR LEGALITY.)
-C          3  MEANS THIS IS NOT THE FIRST CALL, AND THE
-C             CALCULATION IS TO CONTINUE NORMALLY, BUT WITH
-C             A CHANGE IN INPUT PARAMETERS OTHER THAN
-C             TOUT AND ITASK.  CHANGES ARE ALLOWED IN
-C             NEQ, ITOL, RTOL, ATOL, IOPT, LRW, LIW, MF, ML, MU,
-C             AND ANY OF THE OPTIONAL INPUTS EXCEPT H0.
-C             (SEE IWORK DESCRIPTION FOR ML AND MU.)
-C          NOTE..  A PRELIMINARY CALL WITH TOUT = T IS NOT COUNTED
-C          AS A FIRST CALL HERE, AS NO INITIALIZATION OR CHECKING OF
-C          INPUT IS DONE.  (SUCH A CALL IS SOMETIMES USEFUL FOR THE
-C          PURPOSE OF OUTPUTTING THE INITIAL CONDITIONS.)
-C          THUS THE FIRST CALL FOR WHICH TOUT .NE. T REQUIRES
-C          ISTATE = 1 ON INPUT.
+C              ITOL    RTOL      ATOL      EWT(i)
+C              ----    ------    ------    -----------------------------
+C              1       scalar    scalar    RTOL*ABS(Y(i)) + ATOL
+C              2       scalar    array     RTOL*ABS(Y(i)) + ATOL(i)
+C              3       array     scalar    RTOL(i)*ABS(Y(i)) + ATOL
+C              4       array     array     RTOL(i)*ABS(Y(i)) + ATOL(i)
+C
+C              When either of these parameters is a scalar, it need not
+C              be dimensioned in the user's calling program.
+C
+C              If none of the above choices (with ITOL, RTOL, and ATOL
+C              fixed throughout the problem) is suitable, more general
+C              error controls can be obtained by substituting
+C              user-supplied routines for the setting of EWT and/or for
+C              the norm calculation.  See Part 4 below.
+C
+C              If global errors are to be estimated by making a repeated
+C              run on the same problem with smaller tolerances, then all
+C              components of RTOL and ATOL (i.e., of EWT) should be
+C              scaled down uniformly.
 C
-C          ON OUTPUT, ISTATE HAS THE FOLLOWING VALUES AND MEANINGS.
-C           1  MEANS NOTHING WAS DONE, AS TOUT WAS EQUAL TO T WITH
-C              ISTATE = 1 ON INPUT.  (HOWEVER, AN INTERNAL COUNTER WAS
-C              SET TO DETECT AND PREVENT REPEATED CALLS OF THIS TYPE.)
-C           2  MEANS THE INTEGRATION WAS PERFORMED SUCCESSFULLY.
-C          -1  MEANS AN EXCESSIVE AMOUNT OF WORK (MORE THAN MXSTEP
-C              STEPS) WAS DONE ON THIS CALL, BEFORE COMPLETING THE
-C              REQUESTED TASK, BUT THE INTEGRATION WAS OTHERWISE
-C              SUCCESSFUL AS FAR AS T.  (MXSTEP IS AN OPTIONAL INPUT
-C              AND IS NORMALLY 500.)  TO CONTINUE, THE USER MAY
-C              SIMPLY RESET ISTATE TO A VALUE .GT. 1 AND CALL AGAIN
-C              (THE EXCESS WORK STEP COUNTER WILL BE RESET TO 0).
-C              IN ADDITION, THE USER MAY INCREASE MXSTEP TO AVOID
-C              THIS ERROR RETURN (SEE BELOW ON OPTIONAL INPUTS).
-C          -2  MEANS TOO MUCH ACCURACY WAS REQUESTED FOR THE PRECISION
-C              OF THE MACHINE BEING USED.  THIS WAS DETECTED BEFORE
-C              COMPLETING THE REQUESTED TASK, BUT THE INTEGRATION
-C              WAS SUCCESSFUL AS FAR AS T.  TO CONTINUE, THE TOLERANCE
-C              PARAMETERS MUST BE RESET, AND ISTATE MUST BE SET
-C              TO 3.  THE OPTIONAL OUTPUT TOLSF MAY BE USED FOR THIS
-C              PURPOSE.  (NOTE.. IF THIS CONDITION IS DETECTED BEFORE
-C              TAKING ANY STEPS, THEN AN ILLEGAL INPUT RETURN
-C              (ISTATE = -3) OCCURS INSTEAD.)
-C          -3  MEANS ILLEGAL INPUT WAS DETECTED, BEFORE TAKING ANY
-C              INTEGRATION STEPS.  SEE WRITTEN MESSAGE FOR DETAILS.
-C              NOTE..  IF THE SOLVER DETECTS AN INFINITE LOOP OF CALLS
-C              TO THE SOLVER WITH ILLEGAL INPUT, IT WILL CAUSE
-C              THE RUN TO STOP.
-C          -4  MEANS THERE WERE REPEATED ERROR TEST FAILURES ON
-C              ONE ATTEMPTED STEP, BEFORE COMPLETING THE REQUESTED
-C              TASK, BUT THE INTEGRATION WAS SUCCESSFUL AS FAR AS T.
-C              THE PROBLEM MAY HAVE A SINGULARITY, OR THE INPUT
-C              MAY BE INAPPROPRIATE.
-C          -5  MEANS THERE WERE REPEATED CONVERGENCE TEST FAILURES ON
-C              ONE ATTEMPTED STEP, BEFORE COMPLETING THE REQUESTED
-C              TASK, BUT THE INTEGRATION WAS SUCCESSFUL AS FAR AS T.
-C              THIS MAY BE CAUSED BY AN INACCURATE JACOBIAN MATRIX,
-C              IF ONE IS BEING USED.
-C          -6  MEANS EWT(I) BECAME ZERO FOR SOME I DURING THE
-C              INTEGRATION.  PURE RELATIVE ERROR CONTROL (ATOL(I)=0.0)
-C              WAS REQUESTED ON A VARIABLE WHICH HAS NOW VANISHED.
-C              THE INTEGRATION WAS SUCCESSFUL AS FAR AS T.
+C     ITASK    An index specifying the task to be performed.  Input
+C              only.  ITASK has the following values and meanings:
+C              1   Normal computation of output values of y(t) at
+C                  t = TOUT (by overshooting and interpolating).
+C              2   Take one step only and return.
+C              3   Stop at the first internal mesh point at or beyond
+C                  t = TOUT and return.
+C              4   Normal computation of output values of y(t) at
+C                  t = TOUT but without overshooting t = TCRIT.  TCRIT
+C                  must be input as RWORK(1).  TCRIT may be equal to or
+C                  beyond TOUT, but not behind it in the direction of
+C                  integration.  This option is useful if the problem
+C                  has a singularity at or beyond t = TCRIT.
+C              5   Take one step, without passing TCRIT, and return.
+C                  TCRIT must be input as RWORK(1).
+C
+C              Note:  If ITASK = 4 or 5 and the solver reaches TCRIT
+C              (within roundoff), it will return T = TCRIT (exactly) to
+C              indicate this (unless ITASK = 4 and TOUT comes before
+C              TCRIT, in which case answers at T = TOUT are returned
+C              first).
 C
-C          NOTE..  SINCE THE NORMAL OUTPUT VALUE OF ISTATE IS 2,
-C          IT DOES NOT NEED TO BE RESET FOR NORMAL CONTINUATION.
-C          ALSO, SINCE A NEGATIVE INPUT VALUE OF ISTATE WILL BE
-C          REGARDED AS ILLEGAL, A NEGATIVE OUTPUT VALUE REQUIRES THE
-C          USER TO CHANGE IT, AND POSSIBLY OTHER INPUTS, BEFORE
-C          CALLING THE SOLVER AGAIN.
+C     ISTATE   An index used for input and output to specify the state
+C              of the calculation.
 C
-C IOPT   = AN INTEGER FLAG TO SPECIFY WHETHER OR NOT ANY OPTIONAL
-C          INPUTS ARE BEING USED ON THIS CALL.  INPUT ONLY.
-C          THE OPTIONAL INPUTS ARE LISTED SEPARATELY BELOW.
-C          IOPT = 0 MEANS NO OPTIONAL INPUTS ARE BEING USED.
-C                   DEFAULT VALUES WILL BE USED IN ALL CASES.
-C          IOPT = 1 MEANS ONE OR MORE OPTIONAL INPUTS ARE BEING USED.
+C              On input, the values of ISTATE are as follows:
+C              1   This is the first call for the problem
+C                  (initializations will be done).  See "Note" below.
+C              2   This is not the first call, and the calculation is to
+C                  continue normally, with no change in any input
+C                  parameters except possibly TOUT and ITASK.  (If ITOL,
+C                  RTOL, and/or ATOL are changed between calls with
+C                  ISTATE = 2, the new values will be used but not
+C                  tested for legality.)
+C              3   This is not the first call, and the calculation is to
+C                  continue normally, but with a change in input
+C                  parameters other than TOUT and ITASK.  Changes are
+C                  allowed in NEQ, ITOL, RTOL, ATOL, IOPT, LRW, LIW, MF,
+C                  ML, MU, and any of the optional inputs except H0.
+C                  (See IWORK description for ML and MU.)
+C
+C              Note:  A preliminary call with TOUT = T is not counted as
+C              a first call here, as no initialization or checking of
+C              input is done.  (Such a call is sometimes useful for the
+C              purpose of outputting the initial conditions.)  Thus the
+C              first call for which TOUT .NE. T requires ISTATE = 1 on
+C              input.
 C
-C RWORK  = A REAL WORKING ARRAY (DOUBLE PRECISION).
-C          THE LENGTH OF RWORK MUST BE AT LEAST
-C             20 + NYH*(MAXORD + 1) + 3*NEQ + LWM    WHERE
-C          NYH    = THE INITIAL VALUE OF NEQ,
-C          MAXORD = 12 (IF METH = 1) OR 5 (IF METH = 2) (UNLESS A
-C                   SMALLER VALUE IS GIVEN AS AN OPTIONAL INPUT),
-C          LWM   = 0             IF MITER = 0,
-C          LWM   = NEQ**2 + 2    IF MITER IS 1 OR 2,
-C          LWM   = NEQ + 2       IF MITER = 3, AND
-C          LWM   = (2*ML+MU+1)*NEQ + 2 IF MITER IS 4 OR 5.
-C          (SEE THE MF DESCRIPTION FOR METH AND MITER.)
-C          THUS IF MAXORD HAS ITS DEFAULT VALUE AND NEQ IS CONSTANT,
-C          THIS LENGTH IS..
-C             20 + 16*NEQ                  FOR MF = 10,
-C             22 + 16*NEQ + NEQ**2         FOR MF = 11 OR 12,
-C             22 + 17*NEQ                  FOR MF = 13,
-C             22 + 17*NEQ + (2*ML+MU)*NEQ  FOR MF = 14 OR 15,
-C             20 +  9*NEQ                  FOR MF = 20,
-C             22 +  9*NEQ + NEQ**2         FOR MF = 21 OR 22,
-C             22 + 10*NEQ                  FOR MF = 23,
-C             22 + 10*NEQ + (2*ML+MU)*NEQ  FOR MF = 24 OR 25.
-C          THE FIRST 20 WORDS OF RWORK ARE RESERVED FOR CONDITIONAL
-C          AND OPTIONAL INPUTS AND OPTIONAL OUTPUTS.
+C              On output, ISTATE has the following values and meanings:
+C               1  Nothing was done, as TOUT was equal to T with
+C                  ISTATE = 1 on input.
+C               2  The integration was performed successfully.
+C              -1  An excessive amount of work (more than MXSTEP steps)
+C                  was done on this call, before completing the
+C                  requested task, but the integration was otherwise
+C                  successful as far as T. (MXSTEP is an optional input
+C                  and is normally 500.)  To continue, the user may
+C                  simply reset ISTATE to a value >1 and call again (the
+C                  excess work step counter will be reset to 0).  In
+C                  addition, the user may increase MXSTEP to avoid this
+C                  error return; see "Optional Inputs" below.
+C              -2  Too much accuracy was requested for the precision of
+C                  the machine being used.  This was detected before
+C                  completing the requested task, but the integration
+C                  was successful as far as T. To continue, the
+C                  tolerance parameters must be reset, and ISTATE must
+C                  be set to 3. The optional output TOLSF may be used
+C                  for this purpose.  (Note:  If this condition is
+C                  detected before taking any steps, then an illegal
+C                  input return (ISTATE = -3) occurs instead.)
+C              -3  Illegal input was detected, before taking any
+C                  integration steps.  See written message for details.
+C                  (Note:  If the solver detects an infinite loop of
+C                  calls to the solver with illegal input, it will cause
+C                  the run to stop.)
+C              -4  There were repeated error-test failures on one
+C                  attempted step, before completing the requested task,
+C                  but the integration was successful as far as T.  The
+C                  problem may have a singularity, or the input may be
+C                  inappropriate.
+C              -5  There were repeated convergence-test failures on one
+C                  attempted step, before completing the requested task,
+C                  but the integration was successful as far as T. This
+C                  may be caused by an inaccurate Jacobian matrix, if
+C                  one is being used.
+C              -6  EWT(i) became zero for some i during the integration.
+C                  Pure relative error control (ATOL(i)=0.0) was
+C                  requested on a variable which has now vanished.  The
+C                  integration was successful as far as T.
 C
-C          THE FOLLOWING WORD IN RWORK IS A CONDITIONAL INPUT..
-C            RWORK(1) = TCRIT = CRITICAL VALUE OF T WHICH THE SOLVER
-C                       IS NOT TO OVERSHOOT.  REQUIRED IF ITASK IS
-C                       4 OR 5, AND IGNORED OTHERWISE.  (SEE ITASK.)
+C              Note:  Since the normal output value of ISTATE is 2, it
+C              does not need to be reset for normal continuation.  Also,
+C              since a negative input value of ISTATE will be regarded
+C              as illegal, a negative output value requires the user to
+C              change it, and possibly other inputs, before calling the
+C              solver again.
 C
-C LRW    = THE LENGTH OF THE ARRAY RWORK, AS DECLARED BY THE USER.
-C          (THIS WILL BE CHECKED BY THE SOLVER.)
+C     IOPT     An integer flag to specify whether any optional inputs
+C              are being used on this call.  Input only.  The optional
+C              inputs are listed under a separate heading below.
+C              0   No optional inputs are being used.  Default values
+C                  will be used in all cases.
+C              1   One or more optional inputs are being used.
+C
+C     RWORK    A real working array (double precision).  The length of
+C              RWORK must be at least
 C
-C IWORK  = AN INTEGER WORK ARRAY.  THE LENGTH OF IWORK MUST BE AT LEAST
-C             20        IF MITER = 0 OR 3 (MF = 10, 13, 20, 23), OR
-C             20 + NEQ  OTHERWISE (MF = 11, 12, 14, 15, 21, 22, 24, 25).
-C          THE FIRST FEW WORDS OF IWORK ARE USED FOR CONDITIONAL AND
-C          OPTIONAL INPUTS AND OPTIONAL OUTPUTS.
+C                 20 + NYH*(MAXORD + 1) + 3*NEQ + LWM
+C
+C              where
+C                 NYH = the initial value of NEQ,
+C              MAXORD = 12 (if METH = 1) or 5 (if METH = 2) (unless a
+C                       smaller value is given as an optional input),
+C                 LWM = 0           if MITER = 0,
+C                 LWM = NEQ**2 + 2  if MITER = 1 or 2,
+C                 LWM = NEQ + 2     if MITER = 3, and
+C                 LWM = (2*ML + MU + 1)*NEQ + 2
+C                                   if MITER = 4 or 5.
+C              (See the MF description below for METH and MITER.)
 C
-C          THE FOLLOWING 2 WORDS IN IWORK ARE CONDITIONAL INPUTS..
-C            IWORK(1) = ML     THESE ARE THE LOWER AND UPPER
-C            IWORK(2) = MU     HALF-BANDWIDTHS, RESPECTIVELY, OF THE
-C                       BANDED JACOBIAN, EXCLUDING THE MAIN DIAGONAL.
-C                       THE BAND IS DEFINED BY THE MATRIX LOCATIONS
-C                       (I,J) WITH I-ML .LE. J .LE. I+MU.  ML AND MU
-C                       MUST SATISFY  0 .LE.  ML,MU  .LE. NEQ-1.
-C                       THESE ARE REQUIRED IF MITER IS 4 OR 5, AND
-C                       IGNORED OTHERWISE.  ML AND MU MAY IN FACT BE
-C                       THE BAND PARAMETERS FOR A MATRIX TO WHICH
-C                       DF/DY IS ONLY APPROXIMATELY EQUAL.
+C              Thus if MAXORD has its default value and NEQ is constant,
+C              this length is:
+C              20 + 16*NEQ                    for MF = 10,
+C              22 + 16*NEQ + NEQ**2           for MF = 11 or 12,
+C              22 + 17*NEQ                    for MF = 13,
+C              22 + 17*NEQ + (2*ML + MU)*NEQ  for MF = 14 or 15,
+C              20 +  9*NEQ                    for MF = 20,
+C              22 +  9*NEQ + NEQ**2           for MF = 21 or 22,
+C              22 + 10*NEQ                    for MF = 23,
+C              22 + 10*NEQ + (2*ML + MU)*NEQ  for MF = 24 or 25.
+C
+C              The first 20 words of RWORK are reserved for conditional
+C              and optional inputs and optional outputs.
 C
-C LIW    = THE LENGTH OF THE ARRAY IWORK, AS DECLARED BY THE USER.
-C          (THIS WILL BE CHECKED BY THE SOLVER.)
+C              The following word in RWORK is a conditional input:
+C              RWORK(1) = TCRIT, the critical value of t which the
+C                         solver is not to overshoot.  Required if ITASK
+C                         is 4 or 5, and ignored otherwise.  See ITASK.
 C
-C NOTE..  THE WORK ARRAYS MUST NOT BE ALTERED BETWEEN CALLS TO LSODE
-C FOR THE SAME PROBLEM, EXCEPT POSSIBLY FOR THE CONDITIONAL AND
-C OPTIONAL INPUTS, AND EXCEPT FOR THE LAST 3*NEQ WORDS OF RWORK.
-C THE LATTER SPACE IS USED FOR INTERNAL SCRATCH SPACE, AND SO IS
-C AVAILABLE FOR USE BY THE USER OUTSIDE LSODE BETWEEN CALLS, IF
-C DESIRED (BUT NOT FOR USE BY F OR JAC).
+C     LRW      The length of the array RWORK, as declared by the user.
+C              (This will be checked by the solver.)
+C
+C     IWORK    An integer work array.  Its length must be at least
+C              20       if MITER = 0 or 3 (MF = 10, 13, 20, 23), or
+C              20 + NEQ otherwise (MF = 11, 12, 14, 15, 21, 22, 24, 25).
+C              (See the MF description below for MITER.)  The first few
+C              words of IWORK are used for conditional and optional
+C              inputs and optional outputs.
 C
-C JAC    = THE NAME OF THE USER-SUPPLIED ROUTINE (MITER = 1 OR 4) TO
-C          COMPUTE THE JACOBIAN MATRIX, DF/DY, AS A FUNCTION OF
-C          THE SCALAR T AND THE VECTOR Y.  IT IS TO HAVE THE FORM
-C               SUBROUTINE JAC (NEQ, T, Y, ML, MU, PD, NROWPD)
-C               DIMENSION Y(1), PD(NROWPD,1)
-C          WHERE NEQ, T, Y, ML, MU, AND NROWPD ARE INPUT AND THE ARRAY
-C          PD IS TO BE LOADED WITH PARTIAL DERIVATIVES (ELEMENTS OF
-C          THE JACOBIAN MATRIX) ON OUTPUT.  PD MUST BE GIVEN A FIRST
-C          DIMENSION OF NROWPD.  T AND Y HAVE THE SAME MEANING AS IN
-C          SUBROUTINE F.  (IN THE DIMENSION STATEMENT ABOVE, 1 IS A
-C          DUMMY DIMENSION.. IT CAN BE REPLACED BY ANY VALUE.)
-C               IN THE FULL MATRIX CASE (MITER = 1), ML AND MU ARE
-C          IGNORED, AND THE JACOBIAN IS TO BE LOADED INTO PD IN
-C          COLUMNWISE MANNER, WITH DF(I)/DY(J) LOADED INTO PD(I,J).
-C               IN THE BAND MATRIX CASE (MITER = 4), THE ELEMENTS
-C          WITHIN THE BAND ARE TO BE LOADED INTO PD IN COLUMNWISE
-C          MANNER, WITH DIAGONAL LINES OF DF/DY LOADED INTO THE ROWS
-C          OF PD.  THUS DF(I)/DY(J) IS TO BE LOADED INTO PD(I-J+MU+1,J).
-C          ML AND MU ARE THE HALF-BANDWIDTH PARAMETERS (SEE IWORK).
-C          THE LOCATIONS IN PD IN THE TWO TRIANGULAR AREAS WHICH
-C          CORRESPOND TO NONEXISTENT MATRIX ELEMENTS CAN BE IGNORED
-C          OR LOADED ARBITRARILY, AS THEY ARE OVERWRITTEN BY LSODE.
-C               JAC NEED NOT PROVIDE DF/DY EXACTLY.  A CRUDE
-C          APPROXIMATION (POSSIBLY WITH A SMALLER BANDWIDTH) WILL DO.
-C               IN EITHER CASE, PD IS PRESET TO ZERO BY THE SOLVER,
-C          SO THAT ONLY THE NONZERO ELEMENTS NEED BE LOADED BY JAC.
-C          EACH CALL TO JAC IS PRECEDED BY A CALL TO F WITH THE SAME
-C          ARGUMENTS NEQ, T, AND Y.  THUS TO GAIN SOME EFFICIENCY,
-C          INTERMEDIATE QUANTITIES SHARED BY BOTH CALCULATIONS MAY BE
-C          SAVED IN A USER COMMON BLOCK BY F AND NOT RECOMPUTED BY JAC,
-C          IF DESIRED.  ALSO, JAC MAY ALTER THE Y ARRAY, IF DESIRED.
-C          JAC MUST BE DECLARED EXTERNAL IN THE CALLING PROGRAM.
-C               SUBROUTINE JAC MAY ACCESS USER-DEFINED QUANTITIES IN
-C          NEQ(2),... AND/OR IN Y(NEQ(1)+1),... IF NEQ IS AN ARRAY
-C          (DIMENSIONED IN JAC) AND/OR Y HAS LENGTH EXCEEDING NEQ(1).
-C          SEE THE DESCRIPTIONS OF NEQ AND Y ABOVE.
+C              The following two words in IWORK are conditional inputs:
+C              IWORK(1) = ML   These are the lower and upper half-
+C              IWORK(2) = MU   bandwidths, respectively, of the banded
+C                              Jacobian, excluding the main diagonal.
+C                         The band is defined by the matrix locations
+C                         (i,j) with i - ML <= j <= i + MU. ML and MU
+C                         must satisfy 0 <= ML,MU <= NEQ - 1. These are
+C                         required if MITER is 4 or 5, and ignored
+C                         otherwise.  ML and MU may in fact be the band
+C                         parameters for a matrix to which df/dy is only
+C                         approximately equal.
+C
+C     LIW      The length of the array IWORK, as declared by the user.
+C              (This will be checked by the solver.)
+C
+C     Note:  The work arrays must not be altered between calls to DLSODE
+C     for the same problem, except possibly for the conditional and
+C     optional inputs, and except for the last 3*NEQ words of RWORK.
+C     The latter space is used for internal scratch space, and so is
+C     available for use by the user outside DLSODE between calls, if
+C     desired (but not for use by F or JAC).
+C
+C     JAC      The name of the user-supplied routine (MITER = 1 or 4) to
+C              compute the Jacobian matrix, df/dy, as a function of the
+C              scalar t and the vector y.  (See the MF description below
+C              for MITER.)  It is to have the form
+C
+C                 SUBROUTINE JAC (NEQ, T, Y, ML, MU, PD, NROWPD)
+C                 DOUBLE PRECISION T, Y(*), PD(NROWPD,*)
+C
+C              where NEQ, T, Y, ML, MU, and NROWPD are input and the
+C              array PD is to be loaded with partial derivatives
+C              (elements of the Jacobian matrix) on output.  PD must be
+C              given a first dimension of NROWPD.  T and Y have the same
+C              meaning as in subroutine F.
+C
+C              In the full matrix case (MITER = 1), ML and MU are
+C              ignored, and the Jacobian is to be loaded into PD in
+C              columnwise manner, with df(i)/dy(j) loaded into PD(i,j).
+C
+C              In the band matrix case (MITER = 4), the elements within
+C              the band are to be loaded into PD in columnwise manner,
+C              with diagonal lines of df/dy loaded into the rows of PD.
+C              Thus df(i)/dy(j) is to be loaded into PD(i-j+MU+1,j).  ML
+C              and MU are the half-bandwidth parameters (see IWORK).
+C              The locations in PD in the two triangular areas which
+C              correspond to nonexistent matrix elements can be ignored
+C              or loaded arbitrarily, as they are overwritten by DLSODE.
+C
+C              JAC need not provide df/dy exactly. A crude approximation
+C              (possibly with a smaller bandwidth) will do.
+C
+C              In either case, PD is preset to zero by the solver, so
+C              that only the nonzero elements need be loaded by JAC.
+C              Each call to JAC is preceded by a call to F with the same
+C              arguments NEQ, T, and Y. Thus to gain some efficiency,
+C              intermediate quantities shared by both calculations may
+C              be saved in a user COMMON block by F and not recomputed
+C              by JAC, if desired.  Also, JAC may alter the Y array, if
+C              desired.  JAC must be declared EXTERNAL in the calling
+C              program.
+C
+C              Subroutine JAC may access user-defined quantities in
+C              NEQ(2),... and/or in Y(NEQ(1)+1),... if NEQ is an array
+C              (dimensioned in JAC) and/or Y has length exceeding
+C              NEQ(1).  See the descriptions of NEQ and Y above.
+C
+C     MF       The method flag.  Used only for input.  The legal values
+C              of MF are 10, 11, 12, 13, 14, 15, 20, 21, 22, 23, 24,
+C              and 25.  MF has decimal digits METH and MITER:
+C                 MF = 10*METH + MITER .
 C
-C MF     = THE METHOD FLAG.  USED ONLY FOR INPUT.  THE LEGAL VALUES OF
-C          MF ARE 10, 11, 12, 13, 14, 15, 20, 21, 22, 23, 24, AND 25.
-C          MF HAS DECIMAL DIGITS METH AND MITER.. MF = 10*METH + MITER.
-C          METH INDICATES THE BASIC LINEAR MULTISTEP METHOD..
-C            METH = 1 MEANS THE IMPLICIT ADAMS METHOD.
-C            METH = 2 MEANS THE METHOD BASED ON BACKWARD
-C                     DIFFERENTIATION FORMULAS (BDF-S).
-C          MITER INDICATES THE CORRECTOR ITERATION METHOD..
-C            MITER = 0 MEANS FUNCTIONAL ITERATION (NO JACOBIAN MATRIX
-C                      IS INVOLVED).
-C            MITER = 1 MEANS CHORD ITERATION WITH A USER-SUPPLIED
-C                      FULL (NEQ BY NEQ) JACOBIAN.
-C            MITER = 2 MEANS CHORD ITERATION WITH AN INTERNALLY
-C                      GENERATED (DIFFERENCE QUOTIENT) FULL JACOBIAN
-C                      (USING NEQ EXTRA CALLS TO F PER DF/DY VALUE).
-C            MITER = 3 MEANS CHORD ITERATION WITH AN INTERNALLY
-C                      GENERATED DIAGONAL JACOBIAN APPROXIMATION.
-C                      (USING 1 EXTRA CALL TO F PER DF/DY EVALUATION).
-C            MITER = 4 MEANS CHORD ITERATION WITH A USER-SUPPLIED
-C                      BANDED JACOBIAN.
-C            MITER = 5 MEANS CHORD ITERATION WITH AN INTERNALLY
-C                      GENERATED BANDED JACOBIAN (USING ML+MU+1 EXTRA
-C                      CALLS TO F PER DF/DY EVALUATION).
-C          IF MITER = 1 OR 4, THE USER MUST SUPPLY A SUBROUTINE JAC
-C          (THE NAME IS ARBITRARY) AS DESCRIBED ABOVE UNDER JAC.
-C          FOR OTHER VALUES OF MITER, A DUMMY ARGUMENT CAN BE USED.
-C-----------------------------------------------------------------------
-C OPTIONAL INPUTS.
+C              METH indicates the basic linear multistep method:
+C              1   Implicit Adams method.
+C              2   Method based on backward differentiation formulas
+C                  (BDF's).
 C
-C THE FOLLOWING IS A LIST OF THE OPTIONAL INPUTS PROVIDED FOR IN THE
-C CALL SEQUENCE.  (SEE ALSO PART II.)  FOR EACH SUCH INPUT VARIABLE,
-C THIS TABLE LISTS ITS NAME AS USED IN THIS DOCUMENTATION, ITS
-C LOCATION IN THE CALL SEQUENCE, ITS MEANING, AND THE DEFAULT VALUE.
-C THE USE OF ANY OF THESE INPUTS REQUIRES IOPT = 1, AND IN THAT
-C CASE ALL OF THESE INPUTS ARE EXAMINED.  A VALUE OF ZERO FOR ANY
-C OF THESE OPTIONAL INPUTS WILL CAUSE THE DEFAULT VALUE TO BE USED.
-C THUS TO USE A SUBSET OF THE OPTIONAL INPUTS, SIMPLY PRELOAD
-C LOCATIONS 5 TO 10 IN RWORK AND IWORK TO 0.0 AND 0 RESPECTIVELY, AND
-C THEN SET THOSE OF INTEREST TO NONZERO VALUES.
+C              MITER indicates the corrector iteration method:
+C              0   Functional iteration (no Jacobian matrix is
+C                  involved).
+C              1   Chord iteration with a user-supplied full (NEQ by
+C                  NEQ) Jacobian.
+C              2   Chord iteration with an internally generated
+C                  (difference quotient) full Jacobian (using NEQ
+C                  extra calls to F per df/dy value).
+C              3   Chord iteration with an internally generated
+C                  diagonal Jacobian approximation (using one extra call
+C                  to F per df/dy evaluation).
+C              4   Chord iteration with a user-supplied banded Jacobian.
+C              5   Chord iteration with an internally generated banded
+C                  Jacobian (using ML + MU + 1 extra calls to F per
+C                  df/dy evaluation).
 C
-C NAME    LOCATION      MEANING AND DEFAULT VALUE
+C              If MITER = 1 or 4, the user must supply a subroutine JAC
+C              (the name is arbitrary) as described above under JAC.
+C              For other values of MITER, a dummy argument can be used.
+C
+C     Optional Inputs
+C     ---------------
+C     The following is a list of the optional inputs provided for in the
+C     call sequence.  (See also Part 2.)  For each such input variable,
+C     this table lists its name as used in this documentation, its
+C     location in the call sequence, its meaning, and the default value.
+C     The use of any of these inputs requires IOPT = 1, and in that case
+C     all of these inputs are examined.  A value of zero for any of
+C     these optional inputs will cause the default value to be used.
+C     Thus to use a subset of the optional inputs, simply preload
+C     locations 5 to 10 in RWORK and IWORK to 0.0 and 0 respectively,
+C     and then set those of interest to nonzero values.
 C
-C H0      RWORK(5)  THE STEP SIZE TO BE ATTEMPTED ON THE FIRST STEP.
-C                   THE DEFAULT VALUE IS DETERMINED BY THE SOLVER.
-C
-C HMAX    RWORK(6)  THE MAXIMUM ABSOLUTE STEP SIZE ALLOWED.
-C                   THE DEFAULT VALUE IS INFINITE.
-C
-C HMIN    RWORK(7)  THE MINIMUM ABSOLUTE STEP SIZE ALLOWED.
-C                   THE DEFAULT VALUE IS 0.  (THIS LOWER BOUND IS NOT
-C                   ENFORCED ON THE FINAL STEP BEFORE REACHING TCRIT
-C                   WHEN ITASK = 4 OR 5.)
-C
-C MAXORD  IWORK(5)  THE MAXIMUM ORDER TO BE ALLOWED.  THE DEFAULT
-C                   VALUE IS 12 IF METH = 1, AND 5 IF METH = 2.
-C                   IF MAXORD EXCEEDS THE DEFAULT VALUE, IT WILL
-C                   BE REDUCED TO THE DEFAULT VALUE.
-C                   IF MAXORD IS CHANGED DURING THE PROBLEM, IT MAY
-C                   CAUSE THE CURRENT ORDER TO BE REDUCED.
+C     Name    Location   Meaning and default value
+C     ------  ---------  -----------------------------------------------
+C     H0      RWORK(5)   Step size to be attempted on the first step.
+C                        The default value is determined by the solver.
+C     HMAX    RWORK(6)   Maximum absolute step size allowed.  The
+C                        default value is infinite.
+C     HMIN    RWORK(7)   Minimum absolute step size allowed.  The
+C                        default value is 0.  (This lower bound is not
+C                        enforced on the final step before reaching
+C                        TCRIT when ITASK = 4 or 5.)
+C     MAXORD  IWORK(5)   Maximum order to be allowed.  The default value
+C                        is 12 if METH = 1, and 5 if METH = 2. (See the
+C                        MF description above for METH.)  If MAXORD
+C                        exceeds the default value, it will be reduced
+C                        to the default value.  If MAXORD is changed
+C                        during the problem, it may cause the current
+C                        order to be reduced.
+C     MXSTEP  IWORK(6)   Maximum number of (internally defined) steps
+C                        allowed during one call to the solver.  The
+C                        default value is 500.
+C     MXHNIL  IWORK(7)   Maximum number of messages printed (per
+C                        problem) warning that T + H = T on a step
+C                        (H = step size).  This must be positive to
+C                        result in a nondefault value.  The default
+C                        value is 10.
 C
-C MXSTEP  IWORK(6)  MAXIMUM NUMBER OF (INTERNALLY DEFINED) STEPS
-C                   ALLOWED DURING ONE CALL TO THE SOLVER.
-C                   THE DEFAULT VALUE IS 500.
-C
-C MXHNIL  IWORK(7)  MAXIMUM NUMBER OF MESSAGES PRINTED (PER PROBLEM)
-C                   WARNING THAT T + H = T ON A STEP (H = STEP SIZE).
-C                   THIS MUST BE POSITIVE TO RESULT IN A NON-DEFAULT
-C                   VALUE.  THE DEFAULT VALUE IS 10.
-C-----------------------------------------------------------------------
-C OPTIONAL OUTPUTS.
-C
-C AS OPTIONAL ADDITIONAL OUTPUT FROM LSODE, THE VARIABLES LISTED
-C BELOW ARE QUANTITIES RELATED TO THE PERFORMANCE OF LSODE
-C WHICH ARE AVAILABLE TO THE USER.  THESE ARE COMMUNICATED BY WAY OF
-C THE WORK ARRAYS, BUT ALSO HAVE INTERNAL MNEMONIC NAMES AS SHOWN.
-C EXCEPT WHERE STATED OTHERWISE, ALL OF THESE OUTPUTS ARE DEFINED
-C ON ANY SUCCESSFUL RETURN FROM LSODE, AND ON ANY RETURN WITH
-C ISTATE = -1, -2, -4, -5, OR -6.  ON AN ILLEGAL INPUT RETURN
-C (ISTATE = -3), THEY WILL BE UNCHANGED FROM THEIR EXISTING VALUES
-C (IF ANY), EXCEPT POSSIBLY FOR TOLSF, LENRW, AND LENIW.
-C ON ANY ERROR RETURN, OUTPUTS RELEVANT TO THE ERROR WILL BE DEFINED,
-C AS NOTED BELOW.
-C
-C NAME    LOCATION      MEANING
+C     Optional Outputs
+C     ----------------
+C     As optional additional output from DLSODE, the variables listed
+C     below are quantities related to the performance of DLSODE which 
+C     are available to the user.  These are communicated by way of the
+C     work arrays, but also have internal mnemonic names as shown. 
+C     Except where stated otherwise, all of these outputs are defined on
+C     any successful return from DLSODE, and on any return with ISTATE =
+C     -1, -2, -4, -5, or -6.  On an illegal input return (ISTATE = -3),
+C     they will be unchanged from their existing values (if any), except
+C     possibly for TOLSF, LENRW, and LENIW.  On any error return,
+C     outputs relevant to the error will be defined, as noted below.
 C
-C HU      RWORK(11) THE STEP SIZE IN T LAST USED (SUCCESSFULLY).
-C
-C HCUR    RWORK(12) THE STEP SIZE TO BE ATTEMPTED ON THE NEXT STEP.
-C
-C TCUR    RWORK(13) THE CURRENT VALUE OF THE INDEPENDENT VARIABLE
-C                   WHICH THE SOLVER HAS ACTUALLY REACHED, I.E. THE
-C                   CURRENT INTERNAL MESH POINT IN T.  ON OUTPUT, TCUR
-C                   WILL ALWAYS BE AT LEAST AS FAR AS THE ARGUMENT
-C                   T, BUT MAY BE FARTHER (IF INTERPOLATION WAS DONE).
-C
-C TOLSF   RWORK(14) A TOLERANCE SCALE FACTOR, GREATER THAN 1.0,
-C                   COMPUTED WHEN A REQUEST FOR TOO MUCH ACCURACY WAS
-C                   DETECTED (ISTATE = -3 IF DETECTED AT THE START OF
-C                   THE PROBLEM, ISTATE = -2 OTHERWISE).  IF ITOL IS
-C                   LEFT UNALTERED BUT RTOL AND ATOL ARE UNIFORMLY
-C                   SCALED UP BY A FACTOR OF TOLSF FOR THE NEXT CALL,
-C                   THEN THE SOLVER IS DEEMED LIKELY TO SUCCEED.
-C                   (THE USER MAY ALSO IGNORE TOLSF AND ALTER THE
-C                   TOLERANCE PARAMETERS IN ANY OTHER WAY APPROPRIATE.)
-C
-C NST     IWORK(11) THE NUMBER OF STEPS TAKEN FOR THE PROBLEM SO FAR.
-C
-C NFE     IWORK(12) THE NUMBER OF F EVALUATIONS FOR THE PROBLEM SO FAR.
+C     Name   Location   Meaning
+C     -----  ---------  ------------------------------------------------
+C     HU     RWORK(11)  Step size in t last used (successfully).
+C     HCUR   RWORK(12)  Step size to be attempted on the next step.
+C     TCUR   RWORK(13)  Current value of the independent variable which
+C                       the solver has actually reached, i.e., the
+C                       current internal mesh point in t. On output,
+C                       TCUR will always be at least as far as the
+C                       argument T, but may be farther (if interpolation
+C                       was done).
+C     TOLSF  RWORK(14)  Tolerance scale factor, greater than 1.0,
+C                       computed when a request for too much accuracy
+C                       was detected (ISTATE = -3 if detected at the
+C                       start of the problem, ISTATE = -2 otherwise).
+C                       If ITOL is left unaltered but RTOL and ATOL are
+C                       uniformly scaled up by a factor of TOLSF for the
+C                       next call, then the solver is deemed likely to
+C                       succeed.  (The user may also ignore TOLSF and
+C                       alter the tolerance parameters in any other way
+C                       appropriate.)
+C     NST    IWORK(11)  Number of steps taken for the problem so far.
+C     NFE    IWORK(12)  Number of F evaluations for the problem so far.
+C     NJE    IWORK(13)  Number of Jacobian evaluations (and of matrix LU
+C                       decompositions) for the problem so far.
+C     NQU    IWORK(14)  Method order last used (successfully).
+C     NQCUR  IWORK(15)  Order to be attempted on the next step.
+C     IMXER  IWORK(16)  Index of the component of largest magnitude in
+C                       the weighted local error vector ( e(i)/EWT(i) ),
+C                       on an error return with ISTATE = -4 or -5.
+C     LENRW  IWORK(17)  Length of RWORK actually required.  This is
+C                       defined on normal returns and on an illegal
+C                       input return for insufficient storage.
+C     LENIW  IWORK(18)  Length of IWORK actually required.  This is
+C                       defined on normal returns and on an illegal
+C                       input return for insufficient storage.
 C
-C NJE     IWORK(13) THE NUMBER OF JACOBIAN EVALUATIONS (AND OF MATRIX
-C                   LU DECOMPOSITIONS) FOR THE PROBLEM SO FAR.
-C
-C NQU     IWORK(14) THE METHOD ORDER LAST USED (SUCCESSFULLY).
-C
-C NQCUR   IWORK(15) THE ORDER TO BE ATTEMPTED ON THE NEXT STEP.
-C
-C IMXER   IWORK(16) THE INDEX OF THE COMPONENT OF LARGEST MAGNITUDE IN
-C                   THE WEIGHTED LOCAL ERROR VECTOR ( E(I)/EWT(I) ),
-C                   ON AN ERROR RETURN WITH ISTATE = -4 OR -5.
+C     The following two arrays are segments of the RWORK array which may
+C     also be of interest to the user as optional outputs.  For each
+C     array, the table below gives its internal name, its base address
+C     in RWORK, and its description.
 C
-C LENRW   IWORK(17) THE LENGTH OF RWORK ACTUALLY REQUIRED.
-C                   THIS IS DEFINED ON NORMAL RETURNS AND ON AN ILLEGAL
-C                   INPUT RETURN FOR INSUFFICIENT STORAGE.
+C     Name  Base address  Description
+C     ----  ------------  ----------------------------------------------
+C     YH    21            The Nordsieck history array, of size NYH by
+C                         (NQCUR + 1), where NYH is the initial value of
+C                         NEQ.  For j = 0,1,...,NQCUR, column j + 1 of
+C                         YH contains HCUR**j/factorial(j) times the jth
+C                         derivative of the interpolating polynomial
+C                         currently representing the solution, evaluated
+C                         at t = TCUR.
+C     ACOR  LENRW-NEQ+1   Array of size NEQ used for the accumulated
+C                         corrections on each step, scaled on output to
+C                         represent the estimated local error in Y on
+C                         the last step.  This is the vector e in the
+C                         description of the error control.  It is
+C                         defined only on successful return from DLSODE.
 C
-C LENIW   IWORK(18) THE LENGTH OF IWORK ACTUALLY REQUIRED.
-C                   THIS IS DEFINED ON NORMAL RETURNS AND ON AN ILLEGAL
-C                   INPUT RETURN FOR INSUFFICIENT STORAGE.
 C
-C THE FOLLOWING TWO ARRAYS ARE SEGMENTS OF THE RWORK ARRAY WHICH
-C MAY ALSO BE OF INTEREST TO THE USER AS OPTIONAL OUTPUTS.
-C FOR EACH ARRAY, THE TABLE BELOW GIVES ITS INTERNAL NAME,
-C ITS BASE ADDRESS IN RWORK, AND ITS DESCRIPTION.
+C                    Part 2.  Other Callable Routines
+C                    --------------------------------
 C
-C NAME    BASE ADDRESS      DESCRIPTION
+C     The following are optional calls which the user may make to gain
+C     additional capabilities in conjunction with DLSODE.
 C
-C YH      21             THE NORDSIECK HISTORY ARRAY, OF SIZE NYH BY
-C                        (NQCUR + 1), WHERE NYH IS THE INITIAL VALUE
-C                        OF NEQ.  FOR J = 0,1,...,NQCUR, COLUMN J+1
-C                        OF YH CONTAINS HCUR**J/FACTORIAL(J) TIMES
-C                        THE J-TH DERIVATIVE OF THE INTERPOLATING
-C                        POLYNOMIAL CURRENTLY REPRESENTING THE SOLUTION,
-C                        EVALUATED AT T = TCUR.
+C     Form of call              Function
+C     ------------------------  ----------------------------------------
+C     CALL XSETUN(LUN)          Set the logical unit number, LUN, for
+C                               output of messages from DLSODE, if the
+C                               default is not desired.  The default
+C                               value of LUN is 6. This call may be made
+C                               at any time and will take effect
+C                               immediately.
+C     CALL XSETF(MFLAG)         Set a flag to control the printing of
+C                               messages by DLSODE.  MFLAG = 0 means do
+C                               not print.  (Danger:  this risks losing
+C                               valuable information.)  MFLAG = 1 means
+C                               print (the default).  This call may be
+C                               made at any time and will take effect
+C                               immediately.
+C     CALL DSRCOM(RSAV,ISAV,JOB)  Saves and restores the contents of the
+C                               internal COMMON blocks used by DLSODE
+C                               (see Part 3 below).  RSAV must be a
+C                               real array of length 218 or more, and
+C                               ISAV must be an integer array of length
+C                               37 or more.  JOB = 1 means save COMMON
+C                               into RSAV/ISAV.  JOB = 2 means restore
+C                               COMMON from same.  DSRCOM is useful if
+C                               one is interrupting a run and restarting
+C                               later, or alternating between two or
+C                               more problems solved with DLSODE.
+C     CALL DINTDY(,,,,,)        Provide derivatives of y, of various
+C     (see below)               orders, at a specified point t, if
+C                               desired.  It may be called only after a
+C                               successful return from DLSODE.  Detailed
+C                               instructions follow.
 C
-C ACOR     LENRW-NEQ+1   ARRAY OF SIZE NEQ USED FOR THE ACCUMULATED
-C                        CORRECTIONS ON EACH STEP, SCALED ON OUTPUT
-C                        TO REPRESENT THE ESTIMATED LOCAL ERROR IN Y
-C                        ON THE LAST STEP.  THIS IS THE VECTOR E IN
-C                        THE DESCRIPTION OF THE ERROR CONTROL.  IT IS
-C                        DEFINED ONLY ON A SUCCESSFUL RETURN FROM LSODE.
-C
-C-----------------------------------------------------------------------
-C PART II.  OTHER ROUTINES CALLABLE.
+C     Detailed instructions for using DINTDY
+C     --------------------------------------
+C     The form of the CALL is:
 C
-C THE FOLLOWING ARE OPTIONAL CALLS WHICH THE USER MAY MAKE TO
-C GAIN ADDITIONAL CAPABILITIES IN CONJUNCTION WITH LSODE.
-C (THE ROUTINES XSETUN AND XSETF ARE DESIGNED TO CONFORM TO THE
-C SLATEC ERROR HANDLING PACKAGE.)
-C
-C     FORM OF CALL                  FUNCTION
-C   CALL XSETUN(LUN)          SET THE LOGICAL UNIT NUMBER, LUN, FOR
-C                             OUTPUT OF MESSAGES FROM LSODE, IF
-C                             THE DEFAULT IS NOT DESIRED.
-C                             THE DEFAULT VALUE OF LUN IS 6.
+C           CALL DINTDY (T, K, RWORK(21), NYH, DKY, IFLAG)
 C
-C   CALL XSETF(MFLAG)         SET A FLAG TO CONTROL THE PRINTING OF
-C                             MESSAGES BY LSODE.
-C                             MFLAG = 0 MEANS DO NOT PRINT. (DANGER..
-C                             THIS RISKS LOSING VALUABLE INFORMATION.)
-C                             MFLAG = 1 MEANS PRINT (THE DEFAULT).
+C     The input parameters are:
 C
-C                             EITHER OF THE ABOVE CALLS MAY BE MADE AT
-C                             ANY TIME AND WILL TAKE EFFECT IMMEDIATELY.
+C     T          Value of independent variable where answers are
+C                desired (normally the same as the T last returned by
+C                DLSODE).  For valid results, T must lie between
+C                TCUR - HU and TCUR.  (See "Optional Outputs" above
+C                for TCUR and HU.)
+C     K          Integer order of the derivative desired.  K must
+C                satisfy 0 <= K <= NQCUR, where NQCUR is the current
+C                order (see "Optional Outputs").  The capability
+C                corresponding to K = 0, i.e., computing y(t), is
+C                already provided by DLSODE directly.  Since
+C                NQCUR >= 1, the first derivative dy/dt is always
+C                available with DINTDY.
+C     RWORK(21)  The base address of the history array YH.
+C     NYH        Column length of YH, equal to the initial value of NEQ.
+C
+C     The output parameters are:
 C
-C   CALL SRCOM(RSAV,ISAV,JOB) SAVES AND RESTORES THE CONTENTS OF
-C                             THE INTERNAL COMMON BLOCKS USED BY
-C                             LSODE (SEE PART III BELOW).
-C                             RSAV MUST BE A REAL ARRAY OF LENGTH 218
-C                             OR MORE, AND ISAV MUST BE AN INTEGER
-C                             ARRAY OF LENGTH 41 OR MORE.
-C                             JOB=1 MEANS SAVE COMMON INTO RSAV/ISAV.
-C                             JOB=2 MEANS RESTORE COMMON FROM RSAV/ISAV.
-C                                SRCOM IS USEFUL IF ONE IS
-C                             INTERRUPTING A RUN AND RESTARTING
-C                             LATER, OR ALTERNATING BETWEEN TWO OR
-C                             MORE PROBLEMS SOLVED WITH LSODE.
+C     DKY        Real array of length NEQ containing the computed value
+C                of the Kth derivative of y(t).
+C     IFLAG      Integer flag, returned as 0 if K and T were legal,
+C                -1 if K was illegal, and -2 if T was illegal.
+C                On an error return, a message is also written.
+C
+C
+C                          Part 3.  Common Blocks
+C                          ----------------------
 C
-C   CALL INTDY(,,,,,)         PROVIDE DERIVATIVES OF Y, OF VARIOUS
-C        (SEE BELOW)          ORDERS, AT A SPECIFIED POINT T, IF
-C                             DESIRED.  IT MAY BE CALLED ONLY AFTER
-C                             A SUCCESSFUL RETURN FROM LSODE.
+C     If DLSODE is to be used in an overlay situation, the user must
+C     declare, in the primary overlay, the variables in:
+C     (1) the call sequence to DLSODE,
+C     (2) the internal COMMON block /DLS001/, of length 255 
+C         (218 double precision words followed by 37 integer words).
 C
-C THE DETAILED INSTRUCTIONS FOR USING INTDY ARE AS FOLLOWS.
-C THE FORM OF THE CALL IS..
-C
-C   CALL INTDY (T, K, RWORK(21), NYH, DKY, IFLAG)
-C
-C THE INPUT PARAMETERS ARE..
+C     If DLSODE is used on a system in which the contents of internal
+C     COMMON blocks are not preserved between calls, the user should
+C     declare the above COMMON block in his main program to insure that
+C     its contents are preserved.
 C
-C T         = VALUE OF INDEPENDENT VARIABLE WHERE ANSWERS ARE DESIRED
-C             (NORMALLY THE SAME AS THE T LAST RETURNED BY LSODE).
-C             FOR VALID RESULTS, T MUST LIE BETWEEN TCUR - HU AND TCUR.
-C             (SEE OPTIONAL OUTPUTS FOR TCUR AND HU.)
-C K         = INTEGER ORDER OF THE DERIVATIVE DESIRED.  K MUST SATISFY
-C             0 .LE. K .LE. NQCUR, WHERE NQCUR IS THE CURRENT ORDER
-C             (SEE OPTIONAL OUTPUTS).  THE CAPABILITY CORRESPONDING
-C             TO K = 0, I.E. COMPUTING Y(T), IS ALREADY PROVIDED
-C             BY LSODE DIRECTLY.  SINCE NQCUR .GE. 1, THE FIRST
-C             DERIVATIVE DY/DT IS ALWAYS AVAILABLE WITH INTDY.
-C RWORK(21) = THE BASE ADDRESS OF THE HISTORY ARRAY YH.
-C NYH       = COLUMN LENGTH OF YH, EQUAL TO THE INITIAL VALUE OF NEQ.
+C     If the solution of a given problem by DLSODE is to be interrupted
+C     and then later continued, as when restarting an interrupted run or
+C     alternating between two or more problems, the user should save,
+C     following the return from the last DLSODE call prior to the
+C     interruption, the contents of the call sequence variables and the
+C     internal COMMON block, and later restore these values before the
+C     next DLSODE call for that problem.   In addition, if XSETUN and/or
+C     XSETF was called for non-default handling of error messages, then
+C     these calls must be repeated.  To save and restore the COMMON
+C     block, use subroutine DSRCOM (see Part 2 above).
+C
+C
+C              Part 4.  Optionally Replaceable Solver Routines
+C              -----------------------------------------------
 C
-C THE OUTPUT PARAMETERS ARE..
+C     Below are descriptions of two routines in the DLSODE package which
+C     relate to the measurement of errors.  Either routine can be
+C     replaced by a user-supplied version, if desired.  However, since
+C     such a replacement may have a major impact on performance, it
+C     should be done only when absolutely necessary, and only with great
+C     caution.  (Note:  The means by which the package version of a
+C     routine is superseded by the user's version may be system-
+C     dependent.)
 C
-C DKY       = A REAL ARRAY OF LENGTH NEQ CONTAINING THE COMPUTED VALUE
-C             OF THE K-TH DERIVATIVE OF Y(T).
-C IFLAG     = INTEGER FLAG, RETURNED AS 0 IF K AND T WERE LEGAL,
-C             -1 IF K WAS ILLEGAL, AND -2 IF T WAS ILLEGAL.
-C             ON AN ERROR RETURN, A MESSAGE IS ALSO WRITTEN.
-C-----------------------------------------------------------------------
-C PART III.  COMMON BLOCKS.
+C     DEWSET
+C     ------
+C     The following subroutine is called just before each internal
+C     integration step, and sets the array of error weights, EWT, as
+C     described under ITOL/RTOL/ATOL above:
+C
+C           SUBROUTINE DEWSET (NEQ, ITOL, RTOL, ATOL, YCUR, EWT)
+C
+C     where NEQ, ITOL, RTOL, and ATOL are as in the DLSODE call
+C     sequence, YCUR contains the current dependent variable vector,
+C     and EWT is the array of weights set by DEWSET.
 C
-C IF LSODE IS TO BE USED IN AN OVERLAY SITUATION, THE USER
-C MUST DECLARE, IN THE PRIMARY OVERLAY, THE VARIABLES IN..
-C   (1) THE CALL SEQUENCE TO LSODE,
-C   (2) THE INTERNAL COMMON BLOCK
-C         /LS0001/  OF LENGTH  257  (218 DOUBLE PRECISION WORDS
-C                         FOLLOWED BY 39 INTEGER WORDS),
-C
-C IF LSODE IS USED ON A SYSTEM IN WHICH THE CONTENTS OF INTERNAL
-C COMMON BLOCKS ARE NOT PRESERVED BETWEEN CALLS, THE USER SHOULD
-C DECLARE THE ABOVE TWO COMMON BLOCKS IN HIS MAIN PROGRAM TO INSURE
-C THAT THEIR CONTENTS ARE PRESERVED.
+C     If the user supplies this subroutine, it must return in EWT(i)
+C     (i = 1,...,NEQ) a positive quantity suitable for comparing errors
+C     in Y(i) to.  The EWT array returned by DEWSET is passed to the
+C     DVNORM routine (see below), and also used by DLSODE in the
+C     computation of the optional output IMXER, the diagonal Jacobian
+C     approximation, and the increments for difference quotient
+C     Jacobians.
 C
-C IF THE SOLUTION OF A GIVEN PROBLEM BY LSODE IS TO BE INTERRUPTED
-C AND THEN LATER CONTINUED, SUCH AS WHEN RESTARTING AN INTERRUPTED RUN
-C OR ALTERNATING BETWEEN TWO OR MORE PROBLEMS, THE USER SHOULD SAVE,
-C FOLLOWING THE RETURN FROM THE LAST LSODE CALL PRIOR TO THE
-C INTERRUPTION, THE CONTENTS OF THE CALL SEQUENCE VARIABLES AND THE
-C INTERNAL COMMON BLOCKS, AND LATER RESTORE THESE VALUES BEFORE THE
-C NEXT LSODE CALL FOR THAT PROBLEM.  TO SAVE AND RESTORE THE COMMON
-C BLOCKS, USE SUBROUTINE SRCOM (SEE PART II ABOVE).
+C     In the user-supplied version of DEWSET, it may be desirable to use
+C     the current values of derivatives of y. Derivatives up to order NQ
+C     are available from the history array YH, described above under
+C     optional outputs.  In DEWSET, YH is identical to the YCUR array,
+C     extended to NQ + 1 columns with a column length of NYH and scale
+C     factors of H**j/factorial(j).  On the first call for the problem,
+C     given by NST = 0, NQ is 1 and H is temporarily set to 1.0.
+C     NYH is the initial value of NEQ.  The quantities NQ, H, and NST
+C     can be obtained by including in SEWSET the statements:
+C           DOUBLE PRECISION RLS
+C           COMMON /DLS001/ RLS(218),ILS(37)
+C           NQ = ILS(33)
+C           NST = ILS(34)
+C           H = RLS(212)
+C     Thus, for example, the current value of dy/dt can be obtained as
+C     YCUR(NYH+i)/H (i=1,...,NEQ) (and the division by H is unnecessary
+C     when NST = 0).
 C
-C-----------------------------------------------------------------------
-C PART IV.  OPTIONALLY REPLACEABLE SOLVER ROUTINES.
+C     DVNORM
+C     ------
+C     DVNORM is a real function routine which computes the weighted
+C     root-mean-square norm of a vector v:
+C
+C        d = DVNORM (n, v, w)
 C
-C BELOW ARE DESCRIPTIONS OF TWO ROUTINES IN THE LSODE PACKAGE WHICH
-C RELATE TO THE MEASUREMENT OF ERRORS.  EITHER ROUTINE CAN BE
-C REPLACED BY A USER-SUPPLIED VERSION, IF DESIRED.  HOWEVER, SINCE SUCH
-C A REPLACEMENT MAY HAVE A MAJOR IMPACT ON PERFORMANCE, IT SHOULD BE
-C DONE ONLY WHEN ABSOLUTELY NECESSARY, AND ONLY WITH GREAT CAUTION.
-C (NOTE.. THE MEANS BY WHICH THE PACKAGE VERSION OF A ROUTINE IS
-C SUPERSEDED BY THE USER-S VERSION MAY BE SYSTEM-DEPENDENT.)
+C     where:
+C     n = the length of the vector,
+C     v = real array of length n containing the vector,
+C     w = real array of length n containing weights,
+C     d = SQRT( (1/n) * sum(v(i)*w(i))**2 ).
+C
+C     DVNORM is called with n = NEQ and with w(i) = 1.0/EWT(i), where
+C     EWT is as set by subroutine DEWSET.
 C
-C (A) EWSET.
-C THE FOLLOWING SUBROUTINE IS CALLED JUST BEFORE EACH INTERNAL
-C INTEGRATION STEP, AND SETS THE ARRAY OF ERROR WEIGHTS, EWT, AS
-C DESCRIBED UNDER ITOL/RTOL/ATOL ABOVE..
-C     SUBROUTINE EWSET (NEQ, ITOL, RTOL, ATOL, YCUR, EWT)
-C WHERE NEQ, ITOL, RTOL, AND ATOL ARE AS IN THE LSODE CALL SEQUENCE,
-C YCUR CONTAINS THE CURRENT DEPENDENT VARIABLE VECTOR, AND
-C EWT IS THE ARRAY OF WEIGHTS SET BY EWSET.
-C
-C IF THE USER SUPPLIES THIS SUBROUTINE, IT MUST RETURN IN EWT(I)
-C (I = 1,...,NEQ) A POSITIVE QUANTITY SUITABLE FOR COMPARING ERRORS
-C IN Y(I) TO.  THE EWT ARRAY RETURNED BY EWSET IS PASSED TO THE
-C VNORM ROUTINE (SEE BELOW), AND ALSO USED BY LSODE IN THE COMPUTATION
-C OF THE OPTIONAL OUTPUT IMXER, THE DIAGONAL JACOBIAN APPROXIMATION,
-C AND THE INCREMENTS FOR DIFFERENCE QUOTIENT JACOBIANS.
-C
-C IN THE USER-SUPPLIED VERSION OF EWSET, IT MAY BE DESIRABLE TO USE
-C THE CURRENT VALUES OF DERIVATIVES OF Y.  DERIVATIVES UP TO ORDER NQ
-C ARE AVAILABLE FROM THE HISTORY ARRAY YH, DESCRIBED ABOVE UNDER
-C OPTIONAL OUTPUTS.  IN EWSET, YH IS IDENTICAL TO THE YCUR ARRAY,
-C EXTENDED TO NQ + 1 COLUMNS WITH A COLUMN LENGTH OF NYH AND SCALE
-C FACTORS OF H**J/FACTORIAL(J).  ON THE FIRST CALL FOR THE PROBLEM,
-C GIVEN BY NST = 0, NQ IS 1 AND H IS TEMPORARILY SET TO 1.0.
-C THE QUANTITIES NQ, NYH, H, AND NST CAN BE OBTAINED BY INCLUDING
-C IN EWSET THE STATEMENTS..
-C     DOUBLE PRECISION H, RLS
-C     COMMON /LS0001/ RLS(218),ILS(39)
-C     NQ = ILS(35)
-C     NYH = ILS(14)
-C     NST = ILS(36)
-C     H = RLS(212)
-C THUS, FOR EXAMPLE, THE CURRENT VALUE OF DY/DT CAN BE OBTAINED AS
-C YCUR(NYH+I)/H  (I=1,...,NEQ)  (AND THE DIVISION BY H IS
-C UNNECESSARY WHEN NST = 0).
+C     If the user supplies this function, it should return a nonnegative
+C     value of DVNORM suitable for use in the error control in DLSODE.
+C     None of the arguments should be altered by DVNORM.  For example, a
+C     user-supplied DVNORM routine might:
+C     - Substitute a max-norm of (v(i)*w(i)) for the rms-norm, or
+C     - Ignore some components of v in the norm, with the effect of
+C       suppressing the error control on those components of Y.
+C  ---------------------------------------------------------------------
+C***ROUTINES CALLED  DEWSET, DINTDY, D1MACH, DSTODE, DVNORM, XERRWD
+C***COMMON BLOCKS    DLS001
+C***REVISION HISTORY  (YYYYMMDD)
+C 19791129  DATE WRITTEN
+C 19791213  Minor changes to declarations; DELP init. in STODE.
+C 19800118  Treat NEQ as array; integer declarations added throughout;
+C           minor changes to prologue.
+C 19800306  Corrected TESCO(1,NQP1) setting in CFODE.
+C 19800519  Corrected access of YH on forced order reduction;
+C           numerous corrections to prologues and other comments.
+C 19800617  In main driver, added loading of SQRT(UROUND) in RWORK;
+C           minor corrections to main prologue.
+C 19800923  Added zero initialization of HU and NQU.
+C 19801218  Revised XERRWD routine; minor corrections to main prologue.
+C 19810401  Minor changes to comments and an error message.
+C 19810814  Numerous revisions: replaced EWT by 1/EWT; used flags
+C           JCUR, ICF, IERPJ, IERSL between STODE and subordinates;
+C           added tuning parameters CCMAX, MAXCOR, MSBP, MXNCF;
+C           reorganized returns from STODE; reorganized type decls.;
+C           fixed message length in XERRWD; changed default LUNIT to 6;
+C           changed Common lengths; changed comments throughout.
+C 19870330  Major update by ACH: corrected comments throughout;
+C           removed TRET from Common; rewrote EWSET with 4 loops;
+C           fixed t test in INTDY; added Cray directives in STODE;
+C           in STODE, fixed DELP init. and logic around PJAC call;
+C           combined routines to save/restore Common;
+C           passed LEVEL = 0 in error message calls (except run abort).
+C 19890426  Modified prologue to SLATEC/LDOC format.  (FNF)
+C 19890501  Many improvements to prologue.  (FNF)
+C 19890503  A few final corrections to prologue.  (FNF)
+C 19890504  Minor cosmetic changes.  (FNF)
+C 19890510  Corrected description of Y in Arguments section.  (FNF)
+C 19890517  Minor corrections to prologue.  (FNF)
+C 19920514  Updated with prologue edited 891025 by G. Shaw for manual.
+C 19920515  Converted source lines to upper case.  (FNF)
+C 19920603  Revised XERRWD calls using mixed upper-lower case.  (ACH)
+C 19920616  Revised prologue comment regarding CFT.  (ACH)
+C 19921116  Revised prologue comments regarding Common.  (ACH).
+C 19930326  Added comment about non-reentrancy.  (FNF)
+C 19930723  Changed D1MACH to DUMACH. (FNF)
+C 19930801  Removed ILLIN and NTREP from Common (affects driver logic);
+C           minor changes to prologue and internal comments;
+C           changed Hollerith strings to quoted strings; 
+C           changed internal comments to mixed case;
+C           replaced XERRWD with new version using character type;
+C           changed dummy dimensions from 1 to *. (ACH)
+C 19930809  Changed to generic intrinsic names; changed names of
+C           subprograms and Common blocks to DLSODE etc. (ACH)
+C 19930929  Eliminated use of REAL intrinsic; other minor changes. (ACH)
+C 20010412  Removed all 'own' variables from Common block /DLS001/
+C           (affects declarations in 6 routines). (ACH)
+C 20010509  Minor corrections to prologue. (ACH)
+C 20031105  Restored 'own' variables to Common block /DLS001/, to
+C           enable interrupt/restart feature. (ACH)
+C 20031112  Added SAVE statements for data-loaded constants.
 C
-C (B) VNORM.
-C THE FOLLOWING IS A REAL FUNCTION ROUTINE WHICH COMPUTES THE WEIGHTED
-C ROOT-MEAN-SQUARE NORM OF A VECTOR V..
-C     D = VNORM (N, V, W)
-C WHERE..
-C   N = THE LENGTH OF THE VECTOR,
-C   V = REAL ARRAY OF LENGTH N CONTAINING THE VECTOR,
-C   W = REAL ARRAY OF LENGTH N CONTAINING WEIGHTS,
-C   D = SQRT( (1/N) * SUM(V(I)*W(I))**2 ).
-C VNORM IS CALLED WITH N = NEQ AND WITH W(I) = 1.0/EWT(I), WHERE
-C EWT IS AS SET BY SUBROUTINE EWSET.
+C***END PROLOGUE  DLSODE
+C
+C*Internal Notes:
+C
+C Other Routines in the DLSODE Package.
 C
-C IF THE USER SUPPLIES THIS FUNCTION, IT SHOULD RETURN A NON-NEGATIVE
-C VALUE OF VNORM SUITABLE FOR USE IN THE ERROR CONTROL IN LSODE.
-C NONE OF THE ARGUMENTS SHOULD BE ALTERED BY VNORM.
-C FOR EXAMPLE, A USER-SUPPLIED VNORM ROUTINE MIGHT..
-C   -SUBSTITUTE A MAX-NORM OF (V(I)*W(I)) FOR THE RMS-NORM, OR
-C   -IGNORE SOME COMPONENTS OF V IN THE NORM, WITH THE EFFECT OF
-C    SUPPRESSING THE ERROR CONTROL ON THOSE COMPONENTS OF Y.
-C-----------------------------------------------------------------------
-C-----------------------------------------------------------------------
-C OTHER ROUTINES IN THE LSODE PACKAGE.
-C
-C IN ADDITION TO SUBROUTINE LSODE, THE LSODE PACKAGE INCLUDES THE
-C FOLLOWING SUBROUTINES AND FUNCTION ROUTINES..
-C  INTDY    COMPUTES AN INTERPOLATED VALUE OF THE Y VECTOR AT T = TOUT.
-C  STODE    IS THE CORE INTEGRATOR, WHICH DOES ONE STEP OF THE
-C           INTEGRATION AND THE ASSOCIATED ERROR CONTROL.
-C  CFODE    SETS ALL METHOD COEFFICIENTS AND TEST CONSTANTS.
-C  PREPJ    COMPUTES AND PREPROCESSES THE JACOBIAN MATRIX J = DF/DY
-C           AND THE NEWTON ITERATION MATRIX P = I - H*L0*J.
-C  SOLSY    MANAGES SOLUTION OF LINEAR SYSTEM IN CHORD ITERATION.
-C  EWSET    SETS THE ERROR WEIGHT VECTOR EWT BEFORE EACH STEP.
-C  VNORM    COMPUTES THE WEIGHTED R.M.S. NORM OF A VECTOR.
-C  SRCOM    IS A USER-CALLABLE ROUTINE TO SAVE AND RESTORE
-C           THE CONTENTS OF THE INTERNAL COMMON BLOCKS.
+C In addition to Subroutine DLSODE, the DLSODE package includes the
+C following subroutines and function routines:
+C  DINTDY   computes an interpolated value of the y vector at t = TOUT.
+C  DSTODE   is the core integrator, which does one step of the
+C           integration and the associated error control.
+C  DCFODE   sets all method coefficients and test constants.
+C  DPREPJ   computes and preprocesses the Jacobian matrix J = df/dy
+C           and the Newton iteration matrix P = I - h*l0*J.
+C  DSOLSY   manages solution of linear system in chord iteration.
+C  DEWSET   sets the error weight vector EWT before each step.
+C  DVNORM   computes the weighted R.M.S. norm of a vector.
+C  DSRCOM   is a user-callable routine to save and restore
+C           the contents of the internal Common block.
 C  DGETRF AND DGETRS   ARE ROUTINES FROM LAPACK FOR SOLVING FULL
 C           SYSTEMS OF LINEAR ALGEBRAIC EQUATIONS.
 C  DGBTRF AND DGBTRS   ARE ROUTINES FROM LAPACK FOR SOLVING BANDED
 C           LINEAR SYSTEMS.
-C  DAXPY, DSCAL, IDAMAX, AND DDOT   ARE BASIC LINEAR ALGEBRA MODULES
-C           (BLAS) USED BY THE ABOVE LINPACK ROUTINES.
-C  D1MACH   COMPUTES THE UNIT ROUNDOFF IN A MACHINE-INDEPENDENT MANNER.
-C  XERRWD, XSETUN, AND XSETF   HANDLE THE PRINTING OF ALL ERROR
-C           MESSAGES AND WARNINGS.  XERRWD IS MACHINE-DEPENDENT.
-C NOTE..  VNORM, IDAMAX, DDOT, AND D1MACH ARE FUNCTION ROUTINES.
-C ALL THE OTHERS ARE SUBROUTINES.
+C  D1MACH   computes the unit roundoff in a machine-independent manner.
+C  XERRWD, XSETUN, XSETF, IXSAV, IUMACH   handle the printing of all
+C           error messages and warnings.  XERRWD is machine-dependent.
+C Note: DVNORM, DUMACH, IXSAV, and IUMACH are function routines.
+C All the others are subroutines.
 C
-C THE INTRINSIC AND EXTERNAL ROUTINES USED BY LSODE ARE..
-C DABS, DMAX1, DMIN1, DBLE, MAX0, MIN0, MOD, DSIGN, DSQRT, AND WRITE.
-C
-C A BLOCK DATA SUBPROGRAM IS ALSO INCLUDED WITH THE PACKAGE,
-C FOR LOADING SOME OF THE VARIABLES IN INTERNAL COMMON.
+C**End
 C
-C-----------------------------------------------------------------------
-C THE FOLLOWING CARD IS FOR OPTIMIZED COMPILATION ON LLNL COMPILERS.
-CLLL. OPTIMIZE
-C-----------------------------------------------------------------------
-      EXTERNAL PREPJ, SOLSY
+C  Declare externals.
+      EXTERNAL DPREPJ, DSOLSY
+      DOUBLE PRECISION D1MACH, DVNORM
+C
+C  Declare all other variables.
       INTEGER ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
      1   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, NYH,
      2   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP
@@ -954,25 +1216,22 @@
       DOUBLE PRECISION CONIT, CRATE, EL, ELCO, HOLD, RMAX, TESCO,
      1   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND
       DOUBLE PRECISION ATOLI, AYI, BIG, EWTI, H0, HMAX, HMX, RH, RTOLI,
-     1   TCRIT, TDIST, TNEXT, TOL, TOLSF, TP, SIZE, SUM, W0,
-     2   D1MACH, VNORM
+     1   TCRIT, TDIST, TNEXT, TOL, TOLSF, TP, SIZE, SUM, W0
       DIMENSION MORD(2)
       LOGICAL IHIT
+      CHARACTER*80 MSG
+      SAVE MORD, MXSTP0, MXHNL0
 C-----------------------------------------------------------------------
-C THE FOLLOWING INTERNAL COMMON BLOCK CONTAINS
-C (A) VARIABLES WHICH ARE LOCAL TO ANY SUBROUTINE BUT WHOSE VALUES MUST
-C     BE PRESERVED BETWEEN CALLS TO THE ROUTINE (OWN VARIABLES), AND
-C (B) VARIABLES WHICH ARE COMMUNICATED BETWEEN SUBROUTINES.
-C THE STRUCTURE OF THE BLOCK IS AS FOLLOWS..  ALL REAL VARIABLES ARE
-C LISTED FIRST, FOLLOWED BY ALL INTEGERS.  WITHIN EACH TYPE, THE
-C VARIABLES ARE GROUPED WITH THOSE LOCAL TO SUBROUTINE LSODE FIRST,
-C THEN THOSE LOCAL TO SUBROUTINE STODE, AND FINALLY THOSE USED
-C FOR COMMUNICATION.  THE BLOCK IS DECLARED IN SUBROUTINES
-C LSODE, INTDY, STODE, PREPJ, AND SOLSY.  GROUPS OF VARIABLES ARE
-C REPLACED BY DUMMY ARRAYS IN THE COMMON DECLARATIONS IN ROUTINES
-C WHERE THOSE VARIABLES ARE NOT USED.
+C The following internal Common block contains
+C (a) variables which are local to any subroutine but whose values must
+C     be preserved between calls to the routine ("own" variables), and
+C (b) variables which are communicated between subroutines.
+C The block DLS001 is declared in subroutines DLSODE, DINTDY, DSTODE,
+C DPREPJ, and DSOLSY.
+C Groups of variables are replaced by dummy arrays in the Common
+C declarations in routines where those variables are not used.
 C-----------------------------------------------------------------------
-      COMMON /LS0001/ CONIT, CRATE, EL(13), ELCO(13,12),
+      COMMON /DLS001/ CONIT, CRATE, EL(13), ELCO(13,12),
      1   HOLD, RMAX, TESCO(3,12),
      1   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND,
      2   ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
@@ -983,13 +1242,15 @@
 C
       DATA  MORD(1),MORD(2)/12,5/, MXSTP0/500/, MXHNL0/10/
 C-----------------------------------------------------------------------
-C BLOCK A.
-C THIS CODE BLOCK IS EXECUTED ON EVERY CALL.
-C IT TESTS ISTATE AND ITASK FOR LEGALITY AND BRANCHES APPROPRIATELY.
-C IF ISTATE .GT. 1 BUT THE FLAG INIT SHOWS THAT INITIALIZATION HAS
-C NOT YET BEEN DONE, AN ERROR RETURN OCCURS.
-C IF ISTATE = 1 AND TOUT = T, JUMP TO BLOCK G AND RETURN IMMEDIATELY.
+C Block A.
+C This code block is executed on every call.
+C It tests ISTATE and ITASK for legality and branches appropriately.
+C If ISTATE .GT. 1 but the flag INIT shows that initialization has
+C not yet been done, an error return occurs.
+C If ISTATE = 1 and TOUT = T, return immediately.
 C-----------------------------------------------------------------------
+C
+C***FIRST EXECUTABLE STATEMENT  DLSODE
       IF (ISTATE .LT. 1 .OR. ISTATE .GT. 3) GO TO 601
       IF (ITASK .LT. 1 .OR. ITASK .GT. 5) GO TO 602
       IF (ISTATE .EQ. 1) GO TO 10
@@ -997,18 +1258,17 @@
       IF (ISTATE .EQ. 2) GO TO 200
       GO TO 20
  10   INIT = 0
-      IF (TOUT .EQ. T) GO TO 430
- 20   NTREP = 0
+      IF (TOUT .EQ. T) RETURN
 C-----------------------------------------------------------------------
-C BLOCK B.
-C THE NEXT CODE BLOCK IS EXECUTED FOR THE INITIAL CALL (ISTATE = 1),
-C OR FOR A CONTINUATION CALL WITH PARAMETER CHANGES (ISTATE = 3).
-C IT CONTAINS CHECKING OF ALL INPUTS AND VARIOUS INITIALIZATIONS.
+C Block B.
+C The next code block is executed for the initial call (ISTATE = 1),
+C or for a continuation call with parameter changes (ISTATE = 3).
+C It contains checking of all inputs and various initializations.
 C
-C FIRST CHECK LEGALITY OF THE NON-OPTIONAL INPUTS NEQ, ITOL, IOPT,
-C MF, ML, AND MU.
+C First check legality of the non-optional inputs NEQ, ITOL, IOPT,
+C MF, ML, and MU.
 C-----------------------------------------------------------------------
-      IF (NEQ(1) .LE. 0) GO TO 604
+ 20   IF (NEQ(1) .LE. 0) GO TO 604
       IF (ISTATE .EQ. 1) GO TO 25
       IF (NEQ(1) .GT. N) GO TO 605
  25   N = NEQ(1)
@@ -1024,7 +1284,7 @@
       IF (ML .LT. 0 .OR. ML .GE. N) GO TO 609
       IF (MU .LT. 0 .OR. MU .GE. N) GO TO 610
  30   CONTINUE
-C NEXT PROCESS AND CHECK THE OPTIONAL INPUTS. --------------------------
+C Next process and check the optional inputs. --------------------------
       IF (IOPT .EQ. 1) GO TO 40
       MAXORD = MORD(METH)
       MXSTEP = MXSTP0
@@ -1036,7 +1296,7 @@
  40   MAXORD = IWORK(5)
       IF (MAXORD .LT. 0) GO TO 611
       IF (MAXORD .EQ. 0) MAXORD = 100
-      MAXORD = MIN0(MAXORD,MORD(METH))
+      MAXORD = MIN(MAXORD,MORD(METH))
       MXSTEP = IWORK(6)
       IF (MXSTEP .LT. 0) GO TO 612
       IF (MXSTEP .EQ. 0) MXSTEP = MXSTP0
@@ -1053,10 +1313,10 @@
       HMIN = RWORK(7)
       IF (HMIN .LT. 0.0D0) GO TO 616
 C-----------------------------------------------------------------------
-C SET WORK ARRAY POINTERS AND CHECK LENGTHS LRW AND LIW.
-C POINTERS TO SEGMENTS OF RWORK AND IWORK ARE NAMED BY PREFIXING L TO
-C THE NAME OF THE SEGMENT.  E.G., THE SEGMENT YH STARTS AT RWORK(LYH).
-C SEGMENTS OF RWORK (IN ORDER) ARE DENOTED  YH, WM, EWT, SAVF, ACOR.
+C Set work array pointers and check lengths LRW and LIW.
+C Pointers to segments of RWORK and IWORK are named by prefixing L to
+C the name of the segment.  E.g., the segment YH starts at RWORK(LYH).
+C Segments of RWORK (in order) are denoted  YH, WM, EWT, SAVF, ACOR.
 C-----------------------------------------------------------------------
  60   LYH = 21
       IF (ISTATE .EQ. 1) NYH = N
@@ -1076,7 +1336,7 @@
       IWORK(18) = LENIW
       IF (LENRW .GT. LRW) GO TO 617
       IF (LENIW .GT. LIW) GO TO 618
-C CHECK RTOL AND ATOL FOR LEGALITY. ------------------------------------
+C Check RTOL and ATOL for legality. ------------------------------------
       RTOLI = RTOL(1)
       ATOLI = ATOL(1)
       DO 70 I = 1,N
@@ -1086,16 +1346,16 @@
         IF (ATOLI .LT. 0.0D0) GO TO 620
  70     CONTINUE
       IF (ISTATE .EQ. 1) GO TO 100
-C IF ISTATE = 3, SET FLAG TO SIGNAL PARAMETER CHANGES TO STODE. --------
+C If ISTATE = 3, set flag to signal parameter changes to DSTODE. -------
       JSTART = -1
       IF (NQ .LE. MAXORD) GO TO 90
-C MAXORD WAS REDUCED BELOW NQ.  COPY YH(*,MAXORD+2) INTO SAVF. ---------
+C MAXORD was reduced below NQ.  Copy YH(*,MAXORD+2) into SAVF. ---------
       DO 80 I = 1,N
  80     RWORK(I+LSAVF-1) = RWORK(I+LWM-1)
-C RELOAD WM(1) = RWORK(LWM), SINCE LWM MAY HAVE CHANGED. ---------------
- 90   IF (MITER .GT. 0) RWORK(LWM) = DSQRT(UROUND)
+C Reload WM(1) = RWORK(LWM), since LWM may have changed. ---------------
+ 90   IF (MITER .GT. 0) RWORK(LWM) = SQRT(UROUND)
       IF (N .EQ. NYH) GO TO 200
-C NEQ WAS REDUCED.  ZERO PART OF YH TO AVOID UNDEFINED REFERENCES. -----
+C NEQ was reduced.  Zero part of YH to avoid undefined references. -----
       I1 = LYH + L*NYH
       I2 = LYH + (MAXORD + 1)*NYH - 1
       IF (I1 .GT. I2) GO TO 200
@@ -1103,11 +1363,11 @@
  95     RWORK(I) = 0.0D0
       GO TO 200
 C-----------------------------------------------------------------------
-C BLOCK C.
-C THE NEXT BLOCK IS FOR THE INITIAL CALL ONLY (ISTATE = 1).
-C IT CONTAINS ALL REMAINING INITIALIZATIONS, THE INITIAL CALL TO F,
-C AND THE CALCULATION OF THE INITIAL STEP SIZE.
-C THE ERROR WEIGHTS IN EWT ARE INVERTED AFTER BEING LOADED.
+C Block C.
+C The next block is for the initial call only (ISTATE = 1).
+C It contains all remaining initializations, the initial call to F,
+C and the calculation of the initial step size.
+C The error weights in EWT are inverted after being loaded.
 C-----------------------------------------------------------------------
  100  UROUND = D1MACH(4)
       TN = T
@@ -1117,7 +1377,7 @@
       IF (H0 .NE. 0.0D0 .AND. (T + H0 - TCRIT)*H0 .GT. 0.0D0)
      1   H0 = TCRIT - T
  110  JSTART = 0
-      IF (MITER .GT. 0) RWORK(LWM) = DSQRT(UROUND)
+      IF (MITER .GT. 0) RWORK(LWM) = SQRT(UROUND)
       NHNIL = 0
       NST = 0
       NJE = 0
@@ -1128,80 +1388,75 @@
       MAXCOR = 3
       MSBP = 20
       MXNCF = 10
-C INITIAL CALL TO F.  (LF0 POINTS TO YH(*,2).) -------------------------
+C Initial call to F.  (LF0 points to YH(*,2).) -------------------------
       LF0 = LYH + NYH
-      IERR = 0
-      CALL F (NEQ, T, Y, RWORK(LF0), IERR)
-      IF (IERR .LT. 0) THEN
-        ISTATE = -13
-        RETURN
-      ENDIF
+      CALL F (NEQ, T, Y, RWORK(LF0))
       NFE = 1
-C LOAD THE INITIAL VALUE VECTOR IN YH. ---------------------------------
+C Load the initial value vector in YH. ---------------------------------
       DO 115 I = 1,N
  115    RWORK(I+LYH-1) = Y(I)
-C LOAD AND INVERT THE EWT ARRAY.  (H IS TEMPORARILY SET TO 1.0.) -------
+C Load and invert the EWT array.  (H is temporarily set to 1.0.) -------
       NQ = 1
       H = 1.0D0
-      CALL EWSET (N, ITOL, RTOL, ATOL, RWORK(LYH), RWORK(LEWT))
+      CALL DEWSET (N, ITOL, RTOL, ATOL, RWORK(LYH), RWORK(LEWT))
       DO 120 I = 1,N
         IF (RWORK(I+LEWT-1) .LE. 0.0D0) GO TO 621
  120    RWORK(I+LEWT-1) = 1.0D0/RWORK(I+LEWT-1)
 C-----------------------------------------------------------------------
-C THE CODING BELOW COMPUTES THE STEP SIZE, H0, TO BE ATTEMPTED ON THE
-C FIRST STEP, UNLESS THE USER HAS SUPPLIED A VALUE FOR THIS.
-C FIRST CHECK THAT TOUT - T DIFFERS SIGNIFICANTLY FROM ZERO.
-C A SCALAR TOLERANCE QUANTITY TOL IS COMPUTED, AS MAX(RTOL(I))
-C IF THIS IS POSITIVE, OR MAX(ATOL(I)/ABS(Y(I))) OTHERWISE, ADJUSTED
-C SO AS TO BE BETWEEN 100*UROUND AND 1.0E-3.
-C THEN THE COMPUTED VALUE H0 IS GIVEN BY..
+C The coding below computes the step size, H0, to be attempted on the
+C first step, unless the user has supplied a value for this.
+C First check that TOUT - T differs significantly from zero.
+C A scalar tolerance quantity TOL is computed, as MAX(RTOL(I))
+C if this is positive, or MAX(ATOL(I)/ABS(Y(I))) otherwise, adjusted
+C so as to be between 100*UROUND and 1.0E-3.
+C Then the computed value H0 is given by..
 C                                      NEQ
-C   H0**2 = TOL / ( W0**-2 + (1/NEQ) * SUM ( F(I)/YWT(I) )**2  )
+C   H0**2 = TOL / ( w0**-2 + (1/NEQ) * SUM ( f(i)/ywt(i) )**2  )
 C                                       1
-C WHERE   W0     = MAX ( ABS(T), ABS(TOUT) ),
-C         F(I)   = I-TH COMPONENT OF INITIAL VALUE OF F,
-C         YWT(I) = EWT(I)/TOL  (A WEIGHT FOR Y(I)).
-C THE SIGN OF H0 IS INFERRED FROM THE INITIAL VALUES OF TOUT AND T.
+C where   w0     = MAX ( ABS(T), ABS(TOUT) ),
+C         f(i)   = i-th component of initial value of f,
+C         ywt(i) = EWT(i)/TOL  (a weight for y(i)).
+C The sign of H0 is inferred from the initial values of TOUT and T.
 C-----------------------------------------------------------------------
       IF (H0 .NE. 0.0D0) GO TO 180
-      TDIST = DABS(TOUT - T)
-      W0 = DMAX1(DABS(T),DABS(TOUT))
+      TDIST = ABS(TOUT - T)
+      W0 = MAX(ABS(T),ABS(TOUT))
       IF (TDIST .LT. 2.0D0*UROUND*W0) GO TO 622
       TOL = RTOL(1)
       IF (ITOL .LE. 2) GO TO 140
       DO 130 I = 1,N
- 130    TOL = DMAX1(TOL,RTOL(I))
+ 130    TOL = MAX(TOL,RTOL(I))
  140  IF (TOL .GT. 0.0D0) GO TO 160
       ATOLI = ATOL(1)
       DO 150 I = 1,N
         IF (ITOL .EQ. 2 .OR. ITOL .EQ. 4) ATOLI = ATOL(I)
-        AYI = DABS(Y(I))
-        IF (AYI .NE. 0.0D0) TOL = DMAX1(TOL,ATOLI/AYI)
+        AYI = ABS(Y(I))
+        IF (AYI .NE. 0.0D0) TOL = MAX(TOL,ATOLI/AYI)
  150    CONTINUE
- 160  TOL = DMAX1(TOL,100.0D0*UROUND)
-      TOL = DMIN1(TOL,0.001D0)
-      SUM = VNORM (N, RWORK(LF0), RWORK(LEWT))
+ 160  TOL = MAX(TOL,100.0D0*UROUND)
+      TOL = MIN(TOL,0.001D0)
+      SUM = DVNORM (N, RWORK(LF0), RWORK(LEWT))
       SUM = 1.0D0/(TOL*W0*W0) + TOL*SUM**2
-      H0 = 1.0D0/DSQRT(SUM)
-      H0 = DMIN1(H0,TDIST)
-      H0 = DSIGN(H0,TOUT-T)
-C ADJUST H0 IF NECESSARY TO MEET HMAX BOUND. ---------------------------
- 180  RH = DABS(H0)*HMXI
+      H0 = 1.0D0/SQRT(SUM)
+      H0 = MIN(H0,TDIST)
+      H0 = SIGN(H0,TOUT-T)
+C Adjust H0 if necessary to meet HMAX bound. ---------------------------
+ 180  RH = ABS(H0)*HMXI
       IF (RH .GT. 1.0D0) H0 = H0/RH
-C LOAD H WITH H0 AND SCALE YH(*,2) BY H0. ------------------------------
+C Load H with H0 and scale YH(*,2) by H0. ------------------------------
       H = H0
       DO 190 I = 1,N
  190    RWORK(I+LF0-1) = H0*RWORK(I+LF0-1)
       GO TO 270
 C-----------------------------------------------------------------------
-C BLOCK D.
-C THE NEXT CODE BLOCK IS FOR CONTINUATION CALLS ONLY (ISTATE = 2 OR 3)
-C AND IS TO CHECK STOP CONDITIONS BEFORE TAKING A STEP.
+C Block D.
+C The next code block is for continuation calls only (ISTATE = 2 or 3)
+C and is to check stop conditions before taking a step.
 C-----------------------------------------------------------------------
  200  NSLAST = NST
       GO TO (210, 250, 220, 230, 240), ITASK
  210  IF ((TN - TOUT)*H .LT. 0.0D0) GO TO 250
-      CALL INTDY (TOUT, 0, RWORK(LYH), NYH, Y, IFLAG)
+      CALL DINTDY (TOUT, 0, RWORK(LYH), NYH, Y, IFLAG)
       IF (IFLAG .NE. 0) GO TO 627
       T = TOUT
       GO TO 420
@@ -1213,37 +1468,37 @@
       IF ((TN - TCRIT)*H .GT. 0.0D0) GO TO 624
       IF ((TCRIT - TOUT)*H .LT. 0.0D0) GO TO 625
       IF ((TN - TOUT)*H .LT. 0.0D0) GO TO 245
-      CALL INTDY (TOUT, 0, RWORK(LYH), NYH, Y, IFLAG)
+      CALL DINTDY (TOUT, 0, RWORK(LYH), NYH, Y, IFLAG)
       IF (IFLAG .NE. 0) GO TO 627
       T = TOUT
       GO TO 420
  240  TCRIT = RWORK(1)
       IF ((TN - TCRIT)*H .GT. 0.0D0) GO TO 624
- 245  HMX = DABS(TN) + DABS(H)
-      IHIT = DABS(TN - TCRIT) .LE. 100.0D0*UROUND*HMX
+ 245  HMX = ABS(TN) + ABS(H)
+      IHIT = ABS(TN - TCRIT) .LE. 100.0D0*UROUND*HMX
       IF (IHIT) GO TO 400
       TNEXT = TN + H*(1.0D0 + 4.0D0*UROUND)
       IF ((TNEXT - TCRIT)*H .LE. 0.0D0) GO TO 250
       H = (TCRIT - TN)*(1.0D0 - 4.0D0*UROUND)
       IF (ISTATE .EQ. 2) JSTART = -2
 C-----------------------------------------------------------------------
-C BLOCK E.
-C THE NEXT BLOCK IS NORMALLY EXECUTED FOR ALL CALLS AND CONTAINS
-C THE CALL TO THE ONE-STEP CORE INTEGRATOR STODE.
+C Block E.
+C The next block is normally executed for all calls and contains
+C the call to the one-step core integrator DSTODE.
 C
-C THIS IS A LOOPING POINT FOR THE INTEGRATION STEPS.
+C This is a looping point for the integration steps.
 C
-C FIRST CHECK FOR TOO MANY STEPS BEING TAKEN, UPDATE EWT (IF NOT AT
-C START OF PROBLEM), CHECK FOR TOO MUCH ACCURACY BEING REQUESTED, AND
-C CHECK FOR H BELOW THE ROUNDOFF LEVEL IN T.
+C First check for too many steps being taken, update EWT (if not at
+C start of problem), check for too much accuracy being requested, and
+C check for H below the roundoff level in T.
 C-----------------------------------------------------------------------
  250  CONTINUE
       IF ((NST-NSLAST) .GE. MXSTEP) GO TO 500
-      CALL EWSET (N, ITOL, RTOL, ATOL, RWORK(LYH), RWORK(LEWT))
+      CALL DEWSET (N, ITOL, RTOL, ATOL, RWORK(LYH), RWORK(LEWT))
       DO 260 I = 1,N
         IF (RWORK(I+LEWT-1) .LE. 0.0D0) GO TO 510
  260    RWORK(I+LEWT-1) = 1.0D0/RWORK(I+LEWT-1)
- 270  TOLSF = UROUND*VNORM (N, RWORK(LYH), RWORK(LEWT))
+ 270  TOLSF = UROUND*DVNORM (N, RWORK(LYH), RWORK(LEWT))
       IF (TOLSF .LE. 1.0D0) GO TO 280
       TOLSF = TOLSF*2.0D0
       IF (NST .EQ. 0) GO TO 626
@@ -1251,71 +1506,63 @@
  280  IF ((TN + H) .NE. TN) GO TO 290
       NHNIL = NHNIL + 1
       IF (NHNIL .GT. MXHNIL) GO TO 290
-      CALL XERRWD('LSODE--  WARNING..INTERNAL T (=R1) AND H (=R2) ARE',
-     1   50, 101, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD(
-     1  '      SUCH THAT IN THE MACHINE, T + H = T ON THE NEXT STEP  ',
-     1   60, 101, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      (H = STEP SIZE). SOLVER WILL CONTINUE ANYWAY',
-     1   50, 101, 0, 0, 0, 0, 2, TN, H)
+      MSG = 'DLSODE-  Warning..internal T (=R1) and H (=R2) are'
+      CALL XERRWD (MSG, 50, 101, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
+      MSG='      such that in the machine, T + H = T on the next step  '
+      CALL XERRWD (MSG, 60, 101, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
+      MSG = '      (H = step size). Solver will continue anyway'
+      CALL XERRWD (MSG, 50, 101, 0, 0, 0, 0, 2, TN, H)
       IF (NHNIL .LT. MXHNIL) GO TO 290
-      CALL XERRWD('LSODE--  ABOVE WARNING HAS BEEN ISSUED I1 TIMES.  ',
-     1   50, 102, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      IT WILL NOT BE ISSUED AGAIN FOR THIS PROBLEM',
-     1   50, 102, 0, 1, MXHNIL, 0, 0, 0.0D0, 0.0D0)
+      MSG = 'DLSODE-  Above warning has been issued I1 times.  '
+      CALL XERRWD (MSG, 50, 102, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
+      MSG = '      It will not be issued again for this problem'
+      CALL XERRWD (MSG, 50, 102, 0, 1, MXHNIL, 0, 0, 0.0D0, 0.0D0)
  290  CONTINUE
 C-----------------------------------------------------------------------
-C     CALL STODE(NEQ,Y,YH,NYH,YH,EWT,SAVF,ACOR,WM,IWM,F,JAC,PREPJ,SOLSY)
+C  CALL DSTODE(NEQ,Y,YH,NYH,YH,EWT,SAVF,ACOR,WM,IWM,F,JAC,DPREPJ,DSOLSY)
 C-----------------------------------------------------------------------
-      IERR = 0
-      CALL STODE (NEQ, Y, RWORK(LYH), NYH, RWORK(LYH), RWORK(LEWT),
+      CALL DSTODE (NEQ, Y, RWORK(LYH), NYH, RWORK(LYH), RWORK(LEWT),
      1   RWORK(LSAVF), RWORK(LACOR), RWORK(LWM), IWORK(LIWM),
-     2   F, JAC, PREPJ, SOLSY, IERR)
-      IF (IERR .LT. 0) THEN
-        ISTATE = -13
-        RETURN
-      ENDIF
+     2   F, JAC, DPREPJ, DSOLSY)
       KGO = 1 - KFLAG
       GO TO (300, 530, 540), KGO
 C-----------------------------------------------------------------------
-C BLOCK F.
-C THE FOLLOWING BLOCK HANDLES THE CASE OF A SUCCESSFUL RETURN FROM THE
-C CORE INTEGRATOR (KFLAG = 0).  TEST FOR STOP CONDITIONS.
+C Block F.
+C The following block handles the case of a successful return from the
+C core integrator (KFLAG = 0).  Test for stop conditions.
 C-----------------------------------------------------------------------
  300  INIT = 1
       GO TO (310, 400, 330, 340, 350), ITASK
-C ITASK = 1.  IF TOUT HAS BEEN REACHED, INTERPOLATE. -------------------
+C ITASK = 1.  If TOUT has been reached, interpolate. -------------------
  310  IF ((TN - TOUT)*H .LT. 0.0D0) GO TO 250
-      CALL INTDY (TOUT, 0, RWORK(LYH), NYH, Y, IFLAG)
+      CALL DINTDY (TOUT, 0, RWORK(LYH), NYH, Y, IFLAG)
       T = TOUT
       GO TO 420
-C ITASK = 3.  JUMP TO EXIT IF TOUT WAS REACHED. ------------------------
+C ITASK = 3.  Jump to exit if TOUT was reached. ------------------------
  330  IF ((TN - TOUT)*H .GE. 0.0D0) GO TO 400
       GO TO 250
-C ITASK = 4.  SEE IF TOUT OR TCRIT WAS REACHED.  ADJUST H IF NECESSARY.
+C ITASK = 4.  See if TOUT or TCRIT was reached.  Adjust H if necessary.
  340  IF ((TN - TOUT)*H .LT. 0.0D0) GO TO 345
-      CALL INTDY (TOUT, 0, RWORK(LYH), NYH, Y, IFLAG)
+      CALL DINTDY (TOUT, 0, RWORK(LYH), NYH, Y, IFLAG)
       T = TOUT
       GO TO 420
- 345  HMX = DABS(TN) + DABS(H)
-      IHIT = DABS(TN - TCRIT) .LE. 100.0D0*UROUND*HMX
+ 345  HMX = ABS(TN) + ABS(H)
+      IHIT = ABS(TN - TCRIT) .LE. 100.0D0*UROUND*HMX
       IF (IHIT) GO TO 400
       TNEXT = TN + H*(1.0D0 + 4.0D0*UROUND)
       IF ((TNEXT - TCRIT)*H .LE. 0.0D0) GO TO 250
       H = (TCRIT - TN)*(1.0D0 - 4.0D0*UROUND)
       JSTART = -2
       GO TO 250
-C ITASK = 5.  SEE IF TCRIT WAS REACHED AND JUMP TO EXIT. ---------------
- 350  HMX = DABS(TN) + DABS(H)
-      IHIT = DABS(TN - TCRIT) .LE. 100.0D0*UROUND*HMX
+C ITASK = 5.  See if TCRIT was reached and jump to exit. ---------------
+ 350  HMX = ABS(TN) + ABS(H)
+      IHIT = ABS(TN - TCRIT) .LE. 100.0D0*UROUND*HMX
 C-----------------------------------------------------------------------
-C BLOCK G.
-C THE FOLLOWING BLOCK HANDLES ALL SUCCESSFUL RETURNS FROM LSODE.
-C IF ITASK .NE. 1, Y IS LOADED FROM YH AND T IS SET ACCORDINGLY.
-C ISTATE IS SET TO 2, THE ILLEGAL INPUT COUNTER IS ZEROED, AND THE
-C OPTIONAL OUTPUTS ARE LOADED INTO THE WORK ARRAYS BEFORE RETURNING.
-C IF ISTATE = 1 AND TOUT = T, THERE IS A RETURN WITH NO ACTION TAKEN,
-C EXCEPT THAT IF THIS HAS HAPPENED REPEATEDLY, THE RUN IS TERMINATED.
+C Block G.
+C The following block handles all successful returns from DLSODE.
+C If ITASK .NE. 1, Y is loaded from YH and T is set accordingly.
+C ISTATE is set to 2, and the optional outputs are loaded into the
+C work arrays before returning.
 C-----------------------------------------------------------------------
  400  DO 410 I = 1,N
  410    Y(I) = RWORK(I+LYH-1)
@@ -1323,83 +1570,6 @@
       IF (ITASK .NE. 4 .AND. ITASK .NE. 5) GO TO 420
       IF (IHIT) T = TCRIT
  420  ISTATE = 2
-      ILLIN = 0
-      RWORK(11) = HU
-      RWORK(12) = H
-      RWORK(13) = TN
-      IWORK(11) = NST
-      IWORK(12) = NFE
-      IWORK(13) = NJE
-      IWORK(14) = NQU
-      IWORK(15) = NQ
-      RETURN
-C
- 430  NTREP = NTREP + 1
-      IF (NTREP .LT. 5) RETURN
-      CALL XERRWD(
-     1  'LSODE--  REPEATED CALLS WITH ISTATE = 1 AND TOUT = T (=R1)  ',
-     1   60, 301, 0, 0, 0, 0, 1, T, 0.0D0)
-      GO TO 800
-C-----------------------------------------------------------------------
-C BLOCK H.
-C THE FOLLOWING BLOCK HANDLES ALL UNSUCCESSFUL RETURNS OTHER THAN
-C THOSE FOR ILLEGAL INPUT.  FIRST THE ERROR MESSAGE ROUTINE IS CALLED.
-C IF THERE WAS AN ERROR TEST OR CONVERGENCE TEST FAILURE, IMXER IS SET.
-C THEN Y IS LOADED FROM YH, T IS SET TO TN, AND THE ILLEGAL INPUT
-C COUNTER ILLIN IS SET TO 0.  THE OPTIONAL OUTPUTS ARE LOADED INTO
-C THE WORK ARRAYS BEFORE RETURNING.
-C-----------------------------------------------------------------------
-C THE MAXIMUM NUMBER OF STEPS WAS TAKEN BEFORE REACHING TOUT. ----------
- 500  CALL XERRWD('LSODE--  AT CURRENT T (=R1), MXSTEP (=I1) STEPS   ',
-     1   50, 201, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      TAKEN ON THIS CALL BEFORE REACHING TOUT     ',
-     1   50, 201, 0, 1, MXSTEP, 0, 1, TN, 0.0D0)
-      ISTATE = -1
-      GO TO 580
-C EWT(I) .LE. 0.0 FOR SOME I (NOT AT START OF PROBLEM). ----------------
- 510  EWTI = RWORK(LEWT+I-1)
-      CALL XERRWD('LSODE--  AT T (=R1), EWT(I1) HAS BECOME R2 .LE. 0.',
-     1   50, 202, 0, 1, I, 0, 2, TN, EWTI)
-      ISTATE = -6
-      GO TO 580
-C TOO MUCH ACCURACY REQUESTED FOR MACHINE PRECISION. -------------------
- 520  CALL XERRWD('LSODE--  AT T (=R1), TOO MUCH ACCURACY REQUESTED  ',
-     1   50, 203, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      FOR PRECISION OF MACHINE..  SEE TOLSF (=R2) ',
-     1   50, 203, 0, 0, 0, 0, 2, TN, TOLSF)
-      RWORK(14) = TOLSF
-      ISTATE = -2
-      GO TO 580
-C KFLAG = -1.  ERROR TEST FAILED REPEATEDLY OR WITH ABS(H) = HMIN. -----
- 530  CALL XERRWD('LSODE--  AT T(=R1) AND STEP SIZE H(=R2), THE ERROR',
-     1   50, 204, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      TEST FAILED REPEATEDLY OR WITH ABS(H) = HMIN',
-     1   50, 204, 0, 0, 0, 0, 2, TN, H)
-      ISTATE = -4
-      GO TO 560
-C KFLAG = -2.  CONVERGENCE FAILED REPEATEDLY OR WITH ABS(H) = HMIN. ----
- 540  CALL XERRWD('LSODE--  AT T (=R1) AND STEP SIZE H (=R2), THE    ',
-     1   50, 205, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      CORRECTOR CONVERGENCE FAILED REPEATEDLY     ',
-     1   50, 205, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      OR WITH ABS(H) = HMIN   ',
-     1   30, 205, 0, 0, 0, 0, 2, TN, H)
-      ISTATE = -5
-C COMPUTE IMXER IF RELEVANT. -------------------------------------------
- 560  BIG = 0.0D0
-      IMXER = 1
-      DO 570 I = 1,N
-        SIZE = DABS(RWORK(I+LACOR-1)*RWORK(I+LEWT-1))
-        IF (BIG .GE. SIZE) GO TO 570
-        BIG = SIZE
-        IMXER = I
- 570    CONTINUE
-      IWORK(16) = IMXER
-C SET Y VECTOR, T, ILLIN, AND OPTIONAL OUTPUTS. ------------------------
- 580  DO 590 I = 1,N
- 590    Y(I) = RWORK(I+LYH-1)
-      T = TN
-      ILLIN = 0
       RWORK(11) = HU
       RWORK(12) = H
       RWORK(13) = TN
@@ -1410,116 +1580,178 @@
       IWORK(15) = NQ
       RETURN
 C-----------------------------------------------------------------------
-C BLOCK I.
-C THE FOLLOWING BLOCK HANDLES ALL ERROR RETURNS DUE TO ILLEGAL INPUT
-C (ISTATE = -3), AS DETECTED BEFORE CALLING THE CORE INTEGRATOR.
-C FIRST THE ERROR MESSAGE ROUTINE IS CALLED.  THEN IF THERE HAVE BEEN
-C 5 CONSECUTIVE SUCH RETURNS JUST BEFORE THIS CALL TO THE SOLVER,
-C THE RUN IS HALTED.
+C Block H.
+C The following block handles all unsuccessful returns other than
+C those for illegal input.  First the error message routine is called.
+C If there was an error test or convergence test failure, IMXER is set.
+C Then Y is loaded from YH and T is set to TN.  The optional outputs
+C are loaded into the work arrays before returning.
 C-----------------------------------------------------------------------
- 601  CALL XERRWD('LSODE--  ISTATE (=I1) ILLEGAL ',
-     1   30, 1, 0, 1, ISTATE, 0, 0, 0.0D0, 0.0D0)
-      GO TO 700
- 602  CALL XERRWD('LSODE--  ITASK (=I1) ILLEGAL  ',
-     1   30, 2, 0, 1, ITASK, 0, 0, 0.0D0, 0.0D0)
-      GO TO 700
- 603  CALL XERRWD('LSODE--  ISTATE .GT. 1 BUT LSODE NOT INITIALIZED  ',
-     1   50, 3, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      GO TO 700
- 604  CALL XERRWD('LSODE--  NEQ (=I1) .LT. 1     ',
-     1   30, 4, 0, 1, NEQ(1), 0, 0, 0.0D0, 0.0D0)
-      GO TO 700
- 605  CALL XERRWD('LSODE--  ISTATE = 3 AND NEQ INCREASED (I1 TO I2)  ',
-     1   50, 5, 0, 2, N, NEQ(1), 0, 0.0D0, 0.0D0)
-      GO TO 700
- 606  CALL XERRWD('LSODE--  ITOL (=I1) ILLEGAL   ',
-     1   30, 6, 0, 1, ITOL, 0, 0, 0.0D0, 0.0D0)
-      GO TO 700
- 607  CALL XERRWD('LSODE--  IOPT (=I1) ILLEGAL   ',
-     1   30, 7, 0, 1, IOPT, 0, 0, 0.0D0, 0.0D0)
-      GO TO 700
- 608  CALL XERRWD('LSODE--  MF (=I1) ILLEGAL     ',
-     1   30, 8, 0, 1, MF, 0, 0, 0.0D0, 0.0D0)
-      GO TO 700
- 609  CALL XERRWD('LSODE--  ML (=I1) ILLEGAL.. .LT.0 OR .GE.NEQ (=I2)',
-     1   50, 9, 0, 2, ML, NEQ(1), 0, 0.0D0, 0.0D0)
+C The maximum number of steps was taken before reaching TOUT. ----------
+ 500  MSG = 'DLSODE-  At current T (=R1), MXSTEP (=I1) steps   '
+      CALL XERRWD (MSG, 50, 201, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
+      MSG = '      taken on this call before reaching TOUT     '
+      CALL XERRWD (MSG, 50, 201, 0, 1, MXSTEP, 0, 1, TN, 0.0D0)
+      ISTATE = -1
+      GO TO 580
+C EWT(I) .LE. 0.0 for some I (not at start of problem). ----------------
+ 510  EWTI = RWORK(LEWT+I-1)
+      MSG = 'DLSODE-  At T (=R1), EWT(I1) has become R2 .LE. 0.'
+      CALL XERRWD (MSG, 50, 202, 0, 1, I, 0, 2, TN, EWTI)
+      ISTATE = -6
+      GO TO 580
+C Too much accuracy requested for machine precision. -------------------
+ 520  MSG = 'DLSODE-  At T (=R1), too much accuracy requested  '
+      CALL XERRWD (MSG, 50, 203, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
+      MSG = '      for precision of machine..  see TOLSF (=R2) '
+      CALL XERRWD (MSG, 50, 203, 0, 0, 0, 0, 2, TN, TOLSF)
+      RWORK(14) = TOLSF
+      ISTATE = -2
+      GO TO 580
+C KFLAG = -1.  Error test failed repeatedly or with ABS(H) = HMIN. -----
+ 530  MSG = 'DLSODE-  At T(=R1) and step size H(=R2), the error'
+      CALL XERRWD (MSG, 50, 204, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
+      MSG = '      test failed repeatedly or with ABS(H) = HMIN'
+      CALL XERRWD (MSG, 50, 204, 0, 0, 0, 0, 2, TN, H)
+      ISTATE = -4
+      GO TO 560
+C KFLAG = -2.  Convergence failed repeatedly or with ABS(H) = HMIN. ----
+ 540  MSG = 'DLSODE-  At T (=R1) and step size H (=R2), the    '
+      CALL XERRWD (MSG, 50, 205, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
+      MSG = '      corrector convergence failed repeatedly     '
+      CALL XERRWD (MSG, 50, 205, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
+      MSG = '      or with ABS(H) = HMIN   '
+      CALL XERRWD (MSG, 30, 205, 0, 0, 0, 0, 2, TN, H)
+      ISTATE = -5
+C Compute IMXER if relevant. -------------------------------------------
+ 560  BIG = 0.0D0
+      IMXER = 1
+      DO 570 I = 1,N
+        SIZE = ABS(RWORK(I+LACOR-1)*RWORK(I+LEWT-1))
+        IF (BIG .GE. SIZE) GO TO 570
+        BIG = SIZE
+        IMXER = I
+ 570    CONTINUE
+      IWORK(16) = IMXER
+C Set Y vector, T, and optional outputs. -------------------------------
+ 580  DO 590 I = 1,N
+ 590    Y(I) = RWORK(I+LYH-1)
+      T = TN
+      RWORK(11) = HU
+      RWORK(12) = H
+      RWORK(13) = TN
+      IWORK(11) = NST
+      IWORK(12) = NFE
+      IWORK(13) = NJE
+      IWORK(14) = NQU
+      IWORK(15) = NQ
+      RETURN
+C-----------------------------------------------------------------------
+C Block I.
+C The following block handles all error returns due to illegal input
+C (ISTATE = -3), as detected before calling the core integrator.
+C First the error message routine is called.  If the illegal input 
+C is a negative ISTATE, the run is aborted (apparent infinite loop).
+C-----------------------------------------------------------------------
+ 601  MSG = 'DLSODE-  ISTATE (=I1) illegal '
+      CALL XERRWD (MSG, 30, 1, 0, 1, ISTATE, 0, 0, 0.0D0, 0.0D0)
+      IF (ISTATE .LT. 0) GO TO 800
       GO TO 700
- 610  CALL XERRWD('LSODE--  MU (=I1) ILLEGAL.. .LT.0 OR .GE.NEQ (=I2)',
-     1   50, 10, 0, 2, MU, NEQ(1), 0, 0.0D0, 0.0D0)
+ 602  MSG = 'DLSODE-  ITASK (=I1) illegal  '
+      CALL XERRWD (MSG, 30, 2, 0, 1, ITASK, 0, 0, 0.0D0, 0.0D0)
+      GO TO 700
+ 603  MSG = 'DLSODE-  ISTATE .GT. 1 but DLSODE not initialized '
+      CALL XERRWD (MSG, 50, 3, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
       GO TO 700
- 611  CALL XERRWD('LSODE--  MAXORD (=I1) .LT. 0  ',
-     1   30, 11, 0, 1, MAXORD, 0, 0, 0.0D0, 0.0D0)
+ 604  MSG = 'DLSODE-  NEQ (=I1) .LT. 1     '
+      CALL XERRWD (MSG, 30, 4, 0, 1, NEQ(1), 0, 0, 0.0D0, 0.0D0)
+      GO TO 700
+ 605  MSG = 'DLSODE-  ISTATE = 3 and NEQ increased (I1 to I2)  '
+      CALL XERRWD (MSG, 50, 5, 0, 2, N, NEQ(1), 0, 0.0D0, 0.0D0)
+      GO TO 700
+ 606  MSG = 'DLSODE-  ITOL (=I1) illegal   '
+      CALL XERRWD (MSG, 30, 6, 0, 1, ITOL, 0, 0, 0.0D0, 0.0D0)
       GO TO 700
- 612  CALL XERRWD('LSODE--  MXSTEP (=I1) .LT. 0  ',
-     1   30, 12, 0, 1, MXSTEP, 0, 0, 0.0D0, 0.0D0)
+ 607  MSG = 'DLSODE-  IOPT (=I1) illegal   '
+      CALL XERRWD (MSG, 30, 7, 0, 1, IOPT, 0, 0, 0.0D0, 0.0D0)
+      GO TO 700
+ 608  MSG = 'DLSODE-  MF (=I1) illegal     '
+      CALL XERRWD (MSG, 30, 8, 0, 1, MF, 0, 0, 0.0D0, 0.0D0)
       GO TO 700
- 613  CALL XERRWD('LSODE--  MXHNIL (=I1) .LT. 0  ',
-     1   30, 13, 0, 1, MXHNIL, 0, 0, 0.0D0, 0.0D0)
+ 609  MSG = 'DLSODE-  ML (=I1) illegal.. .LT.0 or .GE.NEQ (=I2)'
+      CALL XERRWD (MSG, 50, 9, 0, 2, ML, NEQ(1), 0, 0.0D0, 0.0D0)
       GO TO 700
- 614  CALL XERRWD('LSODE--  TOUT (=R1) BEHIND T (=R2)      ',
-     1   40, 14, 0, 0, 0, 0, 2, TOUT, T)
-      CALL XERRWD('      INTEGRATION DIRECTION IS GIVEN BY H0 (=R1)  ',
-     1   50, 14, 0, 0, 0, 0, 1, H0, 0.0D0)
+ 610  MSG = 'DLSODE-  MU (=I1) illegal.. .LT.0 or .GE.NEQ (=I2)'
+      CALL XERRWD (MSG, 50, 10, 0, 2, MU, NEQ(1), 0, 0.0D0, 0.0D0)
+      GO TO 700
+ 611  MSG = 'DLSODE-  MAXORD (=I1) .LT. 0  '
+      CALL XERRWD (MSG, 30, 11, 0, 1, MAXORD, 0, 0, 0.0D0, 0.0D0)
       GO TO 700
- 615  CALL XERRWD('LSODE--  HMAX (=R1) .LT. 0.0  ',
-     1   30, 15, 0, 0, 0, 0, 1, HMAX, 0.0D0)
+ 612  MSG = 'DLSODE-  MXSTEP (=I1) .LT. 0  '
+      CALL XERRWD (MSG, 30, 12, 0, 1, MXSTEP, 0, 0, 0.0D0, 0.0D0)
+      GO TO 700
+ 613  MSG = 'DLSODE-  MXHNIL (=I1) .LT. 0  '
+      CALL XERRWD (MSG, 30, 13, 0, 1, MXHNIL, 0, 0, 0.0D0, 0.0D0)
       GO TO 700
- 616  CALL XERRWD('LSODE--  HMIN (=R1) .LT. 0.0  ',
-     1   30, 16, 0, 0, 0, 0, 1, HMIN, 0.0D0)
+ 614  MSG = 'DLSODE-  TOUT (=R1) behind T (=R2)      '
+      CALL XERRWD (MSG, 40, 14, 0, 0, 0, 0, 2, TOUT, T)
+      MSG = '      Integration direction is given by H0 (=R1)  '
+      CALL XERRWD (MSG, 50, 14, 0, 0, 0, 0, 1, H0, 0.0D0)
       GO TO 700
- 617  CALL XERRWD(
-     1  'LSODE--  RWORK LENGTH NEEDED, LENRW (=I1), EXCEEDS LRW (=I2)',
-     1   60, 17, 0, 2, LENRW, LRW, 0, 0.0D0, 0.0D0)
+ 615  MSG = 'DLSODE-  HMAX (=R1) .LT. 0.0  '
+      CALL XERRWD (MSG, 30, 15, 0, 0, 0, 0, 1, HMAX, 0.0D0)
       GO TO 700
- 618  CALL XERRWD(
-     1  'LSODE--  IWORK LENGTH NEEDED, LENIW (=I1), EXCEEDS LIW (=I2)',
-     1   60, 18, 0, 2, LENIW, LIW, 0, 0.0D0, 0.0D0)
+ 616  MSG = 'DLSODE-  HMIN (=R1) .LT. 0.0  '
+      CALL XERRWD (MSG, 30, 16, 0, 0, 0, 0, 1, HMIN, 0.0D0)
+      GO TO 700
+ 617  CONTINUE
+      MSG='DLSODE-  RWORK length needed, LENRW (=I1), exceeds LRW (=I2)'
+      CALL XERRWD (MSG, 60, 17, 0, 2, LENRW, LRW, 0, 0.0D0, 0.0D0)
       GO TO 700
- 619  CALL XERRWD('LSODE--  RTOL(I1) IS R1 .LT. 0.0        ',
-     1   40, 19, 0, 1, I, 0, 1, RTOLI, 0.0D0)
+ 618  CONTINUE
+      MSG='DLSODE-  IWORK length needed, LENIW (=I1), exceeds LIW (=I2)'
+      CALL XERRWD (MSG, 60, 18, 0, 2, LENIW, LIW, 0, 0.0D0, 0.0D0)
       GO TO 700
- 620  CALL XERRWD('LSODE--  ATOL(I1) IS R1 .LT. 0.0        ',
-     1   40, 20, 0, 1, I, 0, 1, ATOLI, 0.0D0)
+ 619  MSG = 'DLSODE-  RTOL(I1) is R1 .LT. 0.0        '
+      CALL XERRWD (MSG, 40, 19, 0, 1, I, 0, 1, RTOLI, 0.0D0)
+      GO TO 700
+ 620  MSG = 'DLSODE-  ATOL(I1) is R1 .LT. 0.0        '
+      CALL XERRWD (MSG, 40, 20, 0, 1, I, 0, 1, ATOLI, 0.0D0)
       GO TO 700
  621  EWTI = RWORK(LEWT+I-1)
-      CALL XERRWD('LSODE--  EWT(I1) IS R1 .LE. 0.0         ',
-     1   40, 21, 0, 1, I, 0, 1, EWTI, 0.0D0)
+      MSG = 'DLSODE-  EWT(I1) is R1 .LE. 0.0         '
+      CALL XERRWD (MSG, 40, 21, 0, 1, I, 0, 1, EWTI, 0.0D0)
       GO TO 700
- 622  CALL XERRWD(
-     1  'LSODE--  TOUT (=R1) TOO CLOSE TO T(=R2) TO START INTEGRATION',
-     1   60, 22, 0, 0, 0, 0, 2, TOUT, T)
+ 622  CONTINUE
+      MSG='DLSODE-  TOUT (=R1) too close to T(=R2) to start integration'
+      CALL XERRWD (MSG, 60, 22, 0, 0, 0, 0, 2, TOUT, T)
       GO TO 700
- 623  CALL XERRWD(
-     1  'LSODE--  ITASK = I1 AND TOUT (=R1) BEHIND TCUR - HU (= R2)  ',
-     1   60, 23, 0, 1, ITASK, 0, 2, TOUT, TP)
+ 623  CONTINUE
+      MSG='DLSODE-  ITASK = I1 and TOUT (=R1) behind TCUR - HU (= R2)  '
+      CALL XERRWD (MSG, 60, 23, 0, 1, ITASK, 0, 2, TOUT, TP)
       GO TO 700
- 624  CALL XERRWD(
-     1  'LSODE--  ITASK = 4 OR 5 AND TCRIT (=R1) BEHIND TCUR (=R2)   ',
-     1   60, 24, 0, 0, 0, 0, 2, TCRIT, TN)
+ 624  CONTINUE
+      MSG='DLSODE-  ITASK = 4 OR 5 and TCRIT (=R1) behind TCUR (=R2)   '
+      CALL XERRWD (MSG, 60, 24, 0, 0, 0, 0, 2, TCRIT, TN)
       GO TO 700
- 625  CALL XERRWD(
-     1  'LSODE--  ITASK = 4 OR 5 AND TCRIT (=R1) BEHIND TOUT (=R2)   ',
-     1   60, 25, 0, 0, 0, 0, 2, TCRIT, TOUT)
+ 625  CONTINUE
+      MSG='DLSODE-  ITASK = 4 or 5 and TCRIT (=R1) behind TOUT (=R2)   '
+      CALL XERRWD (MSG, 60, 25, 0, 0, 0, 0, 2, TCRIT, TOUT)
       GO TO 700
- 626  CALL XERRWD('LSODE--  AT START OF PROBLEM, TOO MUCH ACCURACY   ',
-     1   50, 26, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD(
-     1  '      REQUESTED FOR PRECISION OF MACHINE..  SEE TOLSF (=R1) ',
-     1   60, 26, 0, 0, 0, 0, 1, TOLSF, 0.0D0)
+ 626  MSG = 'DLSODE-  At start of problem, too much accuracy   '
+      CALL XERRWD (MSG, 50, 26, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
+      MSG='      requested for precision of machine..  See TOLSF (=R1) '
+      CALL XERRWD (MSG, 60, 26, 0, 0, 0, 0, 1, TOLSF, 0.0D0)
       RWORK(14) = TOLSF
       GO TO 700
- 627  CALL XERRWD('LSODE--  TROUBLE FROM INTDY. ITASK = I1, TOUT = R1',
-     1   50, 27, 0, 1, ITASK, 0, 1, TOUT, 0.0D0)
+ 627  MSG = 'DLSODE-  Trouble in DINTDY.  ITASK = I1, TOUT = R1'
+      CALL XERRWD (MSG, 50, 27, 0, 1, ITASK, 0, 1, TOUT, 0.0D0)
 C
- 700  IF (ILLIN .EQ. 5) GO TO 710
-      ILLIN = ILLIN + 1
-      ISTATE = -3
+ 700  ISTATE = -3
       RETURN
- 710  CALL XERRWD('LSODE--  REPEATED OCCURRENCES OF ILLEGAL INPUT    ',
-     1   50, 302, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
 C
- 800  CALL XERRWD('LSODE--  RUN ABORTED.. APPARENT INFINITE LOOP     ',
-     1   50, 303, 2, 0, 0, 0, 0, 0.0D0, 0.0D0)
+ 800  MSG = 'DLSODE-  Run aborted.. apparent infinite loop     '
+      CALL XERRWD (MSG, 50, 303, 2, 0, 0, 0, 0, 0.0D0, 0.0D0)
       RETURN
-C----------------------- END OF SUBROUTINE LSODE -----------------------
+C----------------------- END OF SUBROUTINE DLSODE ----------------------
       END
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/external/odepack/dprepj.f	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,196 @@
+      SUBROUTINE DPREPJ (NEQ, Y, YH, NYH, EWT, FTEM, SAVF, WM, IWM,
+     1   F, JAC)
+C***BEGIN PROLOGUE  DPREPJ
+C***SUBSIDIARY
+C***PURPOSE  Compute and process Newton iteration matrix.
+C***TYPE      DOUBLE PRECISION (SPREPJ-S, DPREPJ-D)
+C***AUTHOR  Hindmarsh, Alan C., (LLNL)
+C***DESCRIPTION
+C
+C  DPREPJ is called by DSTODE to compute and process the matrix
+C  P = I - h*el(1)*J , where J is an approximation to the Jacobian.
+C  Here J is computed by the user-supplied routine JAC if
+C  MITER = 1 or 4, or by finite differencing if MITER = 2, 3, or 5.
+C  If MITER = 3, a diagonal approximation to J is used.
+C  J is stored in WM and replaced by P.  If MITER .ne. 3, P is then
+C  subjected to LU decomposition in preparation for later solution
+C  of linear systems with P as coefficient matrix.  This is done
+C  by DGETRF if MITER = 1 or 2, and by DGBTRF if MITER = 4 or 5.
+C
+C  In addition to variables described in DSTODE and DLSODE prologues,
+C  communication with DPREPJ uses the following:
+C  Y     = array containing predicted values on entry.
+C  FTEM  = work array of length N (ACOR in DSTODE).
+C  SAVF  = array containing f evaluated at predicted y.
+C  WM    = real work space for matrices.  On output it contains the
+C          inverse diagonal matrix if MITER = 3 and the LU decomposition
+C          of P if MITER is 1, 2 , 4, or 5.
+C          Storage of matrix elements starts at WM(3).
+C          WM also contains the following matrix-related data:
+C          WM(1) = SQRT(UROUND), used in numerical Jacobian increments.
+C          WM(2) = H*EL0, saved for later use if MITER = 3.
+C  IWM   = integer work space containing pivot information, starting at
+C          IWM(21), if MITER is 1, 2, 4, or 5.  IWM also contains band
+C          parameters ML = IWM(1) and MU = IWM(2) if MITER is 4 or 5.
+C  EL0   = EL(1) (input).
+C  IERPJ = output error flag,  = 0 if no trouble, .gt. 0 if
+C          P matrix found to be singular.
+C  JCUR  = output flag = 1 to indicate that the Jacobian matrix
+C          (or approximation) is now current.
+C  This routine also uses the COMMON variables EL0, H, TN, UROUND,
+C  MITER, N, NFE, and NJE.
+C
+C***SEE ALSO  DLSODE
+C***ROUTINES CALLED  DGBTRF, DGETRF, DVNORM
+C***COMMON BLOCKS    DLS001
+C***REVISION HISTORY  (YYMMDD)
+C   791129  DATE WRITTEN
+C   890501  Modified prologue to SLATEC/LDOC format.  (FNF)
+C   890504  Minor cosmetic changes.  (FNF)
+C   930809  Renamed to allow single/double precision versions. (ACH)
+C   010418  Reduced size of Common block /DLS001/. (ACH)
+C   031105  Restored 'own' variables to Common block /DLS001/, to
+C           enable interrupt/restart feature. (ACH)
+C***END PROLOGUE  DPREPJ
+C**End
+      EXTERNAL F, JAC
+      INTEGER NEQ, NYH, IWM
+      DOUBLE PRECISION Y, YH, EWT, FTEM, SAVF, WM
+      DIMENSION NEQ(*), Y(*), YH(NYH,*), EWT(*), FTEM(*), SAVF(*),
+     1   WM(*), IWM(*)
+      INTEGER ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
+     2   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
+      INTEGER ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
+     1   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, CNYH,
+     2   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP
+      DOUBLE PRECISION CONIT, CRATE, EL, ELCO, HOLD, RMAX, TESCO,
+     1   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND
+      COMMON /DLS001/ CONIT, CRATE, EL(13), ELCO(13,12),
+     1   HOLD, RMAX, TESCO(3,12),
+     2   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND,
+     2   ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
+     3   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, CNYH,
+     3   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP,
+     4   ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
+     5   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
+      INTEGER I, I1, I2, IER, II, J, J1, JJ, LENP,
+     1   MBA, MBAND, MEB1, MEBAND, ML, ML3, MU, NP1
+      DOUBLE PRECISION CON, DI, FAC, HL0, R, R0, SRUR, YI, YJ, YJJ,
+     1   DVNORM
+C
+C***FIRST EXECUTABLE STATEMENT  DPREPJ
+      NJE = NJE + 1
+      IERPJ = 0
+      JCUR = 1
+      HL0 = H*EL0
+      GO TO (100, 200, 300, 400, 500), MITER
+C If MITER = 1, call JAC and multiply by scalar. -----------------------
+ 100  LENP = N*N
+      DO 110 I = 1,LENP
+ 110    WM(I+2) = 0.0D0
+      CALL JAC (NEQ, TN, Y, 0, 0, WM(3), N)
+      CON = -HL0
+      DO 120 I = 1,LENP
+ 120    WM(I+2) = WM(I+2)*CON
+      GO TO 240
+C If MITER = 2, make N calls to F to approximate J. --------------------
+ 200  FAC = DVNORM (N, SAVF, EWT)
+      R0 = 1000.0D0*ABS(H)*UROUND*N*FAC
+      IF (R0 .EQ. 0.0D0) R0 = 1.0D0
+      SRUR = WM(1)
+      J1 = 2
+      DO 230 J = 1,N
+        YJ = Y(J)
+        R = MAX(SRUR*ABS(YJ),R0/EWT(J))
+        Y(J) = Y(J) + R
+        FAC = -HL0/R
+        CALL F (NEQ, TN, Y, FTEM)
+        DO 220 I = 1,N
+ 220      WM(I+J1) = (FTEM(I) - SAVF(I))*FAC
+        Y(J) = YJ
+        J1 = J1 + N
+ 230    CONTINUE
+      NFE = NFE + N
+C Add identity matrix. -------------------------------------------------
+ 240  J = 3
+      NP1 = N + 1
+      DO 250 I = 1,N
+        WM(J) = WM(J) + 1.0D0
+ 250    J = J + NP1
+C Do LU decomposition on P. --------------------------------------------
+      CALL DGETRF ( N, N, WM(3), N, IWM(21), IER)
+      IF (IER .NE. 0) IERPJ = 1
+      RETURN
+C If MITER = 3, construct a diagonal approximation to J and P. ---------
+ 300  WM(2) = HL0
+      R = EL0*0.1D0
+      DO 310 I = 1,N
+ 310    Y(I) = Y(I) + R*(H*SAVF(I) - YH(I,2))
+      CALL F (NEQ, TN, Y, WM(3))
+      NFE = NFE + 1
+      DO 320 I = 1,N
+        R0 = H*SAVF(I) - YH(I,2)
+        DI = 0.1D0*R0 - H*(WM(I+2) - SAVF(I))
+        WM(I+2) = 1.0D0
+        IF (ABS(R0) .LT. UROUND/EWT(I)) GO TO 320
+        IF (ABS(DI) .EQ. 0.0D0) GO TO 330
+        WM(I+2) = 0.1D0*R0/DI
+ 320    CONTINUE
+      RETURN
+ 330  IERPJ = 1
+      RETURN
+C If MITER = 4, call JAC and multiply by scalar. -----------------------
+ 400  ML = IWM(1)
+      MU = IWM(2)
+      ML3 = ML + 3
+      MBAND = ML + MU + 1
+      MEBAND = MBAND + ML
+      LENP = MEBAND*N
+      DO 410 I = 1,LENP
+ 410    WM(I+2) = 0.0D0
+      CALL JAC (NEQ, TN, Y, ML, MU, WM(ML3), MEBAND)
+      CON = -HL0
+      DO 420 I = 1,LENP
+ 420    WM(I+2) = WM(I+2)*CON
+      GO TO 570
+C If MITER = 5, make MBAND calls to F to approximate J. ----------------
+ 500  ML = IWM(1)
+      MU = IWM(2)
+      MBAND = ML + MU + 1
+      MBA = MIN(MBAND,N)
+      MEBAND = MBAND + ML
+      MEB1 = MEBAND - 1
+      SRUR = WM(1)
+      FAC = DVNORM (N, SAVF, EWT)
+      R0 = 1000.0D0*ABS(H)*UROUND*N*FAC
+      IF (R0 .EQ. 0.0D0) R0 = 1.0D0
+      DO 560 J = 1,MBA
+        DO 530 I = J,N,MBAND
+          YI = Y(I)
+          R = MAX(SRUR*ABS(YI),R0/EWT(I))
+ 530      Y(I) = Y(I) + R
+        CALL F (NEQ, TN, Y, FTEM)
+        DO 550 JJ = J,N,MBAND
+          Y(JJ) = YH(JJ,1)
+          YJJ = Y(JJ)
+          R = MAX(SRUR*ABS(YJJ),R0/EWT(JJ))
+          FAC = -HL0/R
+          I1 = MAX(JJ-MU,1)
+          I2 = MIN(JJ+ML,N)
+          II = JJ*MEB1 - ML + 2
+          DO 540 I = I1,I2
+ 540        WM(II+I) = (FTEM(I) - SAVF(I))*FAC
+ 550      CONTINUE
+ 560    CONTINUE
+      NFE = NFE + MBA
+C Add identity matrix. -------------------------------------------------
+ 570  II = MBAND + 2
+      DO 580 I = 1,N
+        WM(II) = WM(II) + 1.0D0
+ 580    II = II + MEBAND
+C Do LU decomposition of P. --------------------------------------------
+      CALL DGBTRF ( N, N, ML, MU, WM(3), MEBAND, IWM(21), IER)
+      IF (IER .NE. 0) IERPJ = 1
+      RETURN
+C----------------------- END OF SUBROUTINE DPREPJ ----------------------
+      END
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/external/odepack/dsolsy.f	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,95 @@
+      SUBROUTINE DSOLSY (WM, IWM, X, TEM)
+C***BEGIN PROLOGUE  DSOLSY
+C***SUBSIDIARY
+C***PURPOSE  ODEPACK linear system solver.
+C***TYPE      DOUBLE PRECISION (SSOLSY-S, DSOLSY-D)
+C***AUTHOR  Hindmarsh, Alan C., (LLNL)
+C***DESCRIPTION
+C
+C  This routine manages the solution of the linear system arising from
+C  a chord iteration.  It is called if MITER .ne. 0.
+C  If MITER is 1 or 2, it calls DGETRS to accomplish this.
+C  If MITER = 3 it updates the coefficient h*EL0 in the diagonal
+C  matrix, and then computes the solution.
+C  If MITER is 4 or 5, it calls DGBTRS.
+C  Communication with DSOLSY uses the following variables:
+C  WM    = real work space containing the inverse diagonal matrix if
+C          MITER = 3 and the LU decomposition of the matrix otherwise.
+C          Storage of matrix elements starts at WM(3).
+C          WM also contains the following matrix-related data:
+C          WM(1) = SQRT(UROUND) (not used here),
+C          WM(2) = HL0, the previous value of h*EL0, used if MITER = 3.
+C  IWM   = integer work space containing pivot information, starting at
+C          IWM(21), if MITER is 1, 2, 4, or 5.  IWM also contains band
+C          parameters ML = IWM(1) and MU = IWM(2) if MITER is 4 or 5.
+C  X     = the right-hand side vector on input, and the solution vector
+C          on output, of length N.
+C  TEM   = vector of work space of length N, not used in this version.
+C  IERSL = output flag (in COMMON).  IERSL = 0 if no trouble occurred.
+C          IERSL = 1 if a singular matrix arose with MITER = 3.
+C  This routine also uses the COMMON variables EL0, H, MITER, and N.
+C
+C***SEE ALSO  DLSODE
+C***ROUTINES CALLED  DGBTRS, DGETRS
+C***COMMON BLOCKS    DLS001
+C***REVISION HISTORY  (YYMMDD)
+C   791129  DATE WRITTEN
+C   890501  Modified prologue to SLATEC/LDOC format.  (FNF)
+C   890503  Minor cosmetic changes.  (FNF)
+C   930809  Renamed to allow single/double precision versions. (ACH)
+C   010418  Reduced size of Common block /DLS001/. (ACH)
+C   031105  Restored 'own' variables to Common block /DLS001/, to
+C           enable interrupt/restart feature. (ACH)
+C***END PROLOGUE  DSOLSY
+C**End
+      INTEGER IWM
+      DOUBLE PRECISION WM, X, TEM
+      DIMENSION WM(*), IWM(*), X(*), TEM(*)
+      INTEGER ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
+     1   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, NYH,
+     2   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP
+      INTEGER ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
+     2   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
+      DOUBLE PRECISION CONIT, CRATE, EL, ELCO, HOLD, RMAX, TESCO,
+     2   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND
+      COMMON /DLS001/ CONIT, CRATE, EL(13), ELCO(13,12),
+     1   HOLD, RMAX, TESCO(3,12),
+     2   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND,
+     2   ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
+     3   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, NYH,
+     3   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP,
+     4   ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
+     5   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
+      INTEGER I, MEBAND, ML, MU
+      INTEGER INLPCK
+      DOUBLE PRECISION DI, HL0, PHL0, R
+C
+C***FIRST EXECUTABLE STATEMENT  DSOLSY
+      IERSL = 0
+      GO TO (100, 100, 300, 400, 400), MITER
+ 100  CALL DGETRS ( 'N', N, 1, WM(3), N, IWM(21), X, N, INLPCK)
+      RETURN
+C
+ 300  PHL0 = WM(2)
+      HL0 = H*EL0
+      WM(2) = HL0
+      IF (HL0 .EQ. PHL0) GO TO 330
+      R = HL0/PHL0
+      DO 320 I = 1,N
+        DI = 1.0D0 - R*(1.0D0 - 1.0D0/WM(I+2))
+        IF (ABS(DI) .EQ. 0.0D0) GO TO 390
+ 320    WM(I+2) = 1.0D0/DI
+ 330  DO 340 I = 1,N
+ 340    X(I) = WM(I+2)*X(I)
+      RETURN
+ 390  IERSL = 1
+      RETURN
+C
+ 400  ML = IWM(1)
+      MU = IWM(2)
+      MEBAND = 2*ML + MU + 1
+      CALL DGBTRS ( 'N', N, ML, MU, 1, WM(3), MEBAND, IWM(21), X, N,
+     * INLPCK)
+      RETURN
+C----------------------- END OF SUBROUTINE DSOLSY ----------------------
+      END
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/external/odepack/dstode.f	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,499 @@
+      SUBROUTINE DSTODE (NEQ, Y, YH, NYH, YH1, EWT, SAVF, ACOR,
+     1   WM, IWM, F, JAC, PJAC, SLVS)
+C***BEGIN PROLOGUE  DSTODE
+C***SUBSIDIARY
+C***PURPOSE  Performs one step of an ODEPACK integration.
+C***TYPE      DOUBLE PRECISION (SSTODE-S, DSTODE-D)
+C***AUTHOR  Hindmarsh, Alan C., (LLNL)
+C***DESCRIPTION
+C
+C  DSTODE performs one step of the integration of an initial value
+C  problem for a system of ordinary differential equations.
+C  Note:  DSTODE is independent of the value of the iteration method
+C  indicator MITER, when this is .ne. 0, and hence is independent
+C  of the type of chord method used, or the Jacobian structure.
+C  Communication with DSTODE is done with the following variables:
+C
+C  NEQ    = integer array containing problem size in NEQ(1), and
+C           passed as the NEQ argument in all calls to F and JAC.
+C  Y      = an array of length .ge. N used as the Y argument in
+C           all calls to F and JAC.
+C  YH     = an NYH by LMAX array containing the dependent variables
+C           and their approximate scaled derivatives, where
+C           LMAX = MAXORD + 1.  YH(i,j+1) contains the approximate
+C           j-th derivative of y(i), scaled by h**j/factorial(j)
+C           (j = 0,1,...,NQ).  on entry for the first step, the first
+C           two columns of YH must be set from the initial values.
+C  NYH    = a constant integer .ge. N, the first dimension of YH.
+C  YH1    = a one-dimensional array occupying the same space as YH.
+C  EWT    = an array of length N containing multiplicative weights
+C           for local error measurements.  Local errors in Y(i) are
+C           compared to 1.0/EWT(i) in various error tests.
+C  SAVF   = an array of working storage, of length N.
+C           Also used for input of YH(*,MAXORD+2) when JSTART = -1
+C           and MAXORD .lt. the current order NQ.
+C  ACOR   = a work array of length N, used for the accumulated
+C           corrections.  On a successful return, ACOR(i) contains
+C           the estimated one-step local error in Y(i).
+C  WM,IWM = real and integer work arrays associated with matrix
+C           operations in chord iteration (MITER .ne. 0).
+C  PJAC   = name of routine to evaluate and preprocess Jacobian matrix
+C           and P = I - h*el0*JAC, if a chord method is being used.
+C  SLVS   = name of routine to solve linear system in chord iteration.
+C  CCMAX  = maximum relative change in h*el0 before PJAC is called.
+C  H      = the step size to be attempted on the next step.
+C           H is altered by the error control algorithm during the
+C           problem.  H can be either positive or negative, but its
+C           sign must remain constant throughout the problem.
+C  HMIN   = the minimum absolute value of the step size h to be used.
+C  HMXI   = inverse of the maximum absolute value of h to be used.
+C           HMXI = 0.0 is allowed and corresponds to an infinite hmax.
+C           HMIN and HMXI may be changed at any time, but will not
+C           take effect until the next change of h is considered.
+C  TN     = the independent variable. TN is updated on each step taken.
+C  JSTART = an integer used for input only, with the following
+C           values and meanings:
+C                0  perform the first step.
+C            .gt.0  take a new step continuing from the last.
+C               -1  take the next step with a new value of H, MAXORD,
+C                     N, METH, MITER, and/or matrix parameters.
+C               -2  take the next step with a new value of H,
+C                     but with other inputs unchanged.
+C           On return, JSTART is set to 1 to facilitate continuation.
+C  KFLAG  = a completion code with the following meanings:
+C                0  the step was succesful.
+C               -1  the requested error could not be achieved.
+C               -2  corrector convergence could not be achieved.
+C               -3  fatal error in PJAC or SLVS.
+C           A return with KFLAG = -1 or -2 means either
+C           abs(H) = HMIN or 10 consecutive failures occurred.
+C           On a return with KFLAG negative, the values of TN and
+C           the YH array are as of the beginning of the last
+C           step, and H is the last step size attempted.
+C  MAXORD = the maximum order of integration method to be allowed.
+C  MAXCOR = the maximum number of corrector iterations allowed.
+C  MSBP   = maximum number of steps between PJAC calls (MITER .gt. 0).
+C  MXNCF  = maximum number of convergence failures allowed.
+C  METH/MITER = the method flags.  See description in driver.
+C  N      = the number of first-order differential equations.
+C  The values of CCMAX, H, HMIN, HMXI, TN, JSTART, KFLAG, MAXORD,
+C  MAXCOR, MSBP, MXNCF, METH, MITER, and N are communicated via COMMON.
+C
+C***SEE ALSO  DLSODE
+C***ROUTINES CALLED  DCFODE, DVNORM
+C***COMMON BLOCKS    DLS001
+C***REVISION HISTORY  (YYMMDD)
+C   791129  DATE WRITTEN
+C   890501  Modified prologue to SLATEC/LDOC format.  (FNF)
+C   890503  Minor cosmetic changes.  (FNF)
+C   930809  Renamed to allow single/double precision versions. (ACH)
+C   010418  Reduced size of Common block /DLS001/. (ACH)
+C   031105  Restored 'own' variables to Common block /DLS001/, to
+C           enable interrupt/restart feature. (ACH)
+C***END PROLOGUE  DSTODE
+C**End
+      EXTERNAL F, JAC, PJAC, SLVS
+      INTEGER NEQ, NYH, IWM
+      DOUBLE PRECISION Y, YH, YH1, EWT, SAVF, ACOR, WM
+      DIMENSION NEQ(*), Y(*), YH(NYH,*), YH1(*), EWT(*), SAVF(*),
+     1   ACOR(*), WM(*), IWM(*)
+      INTEGER ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
+     1   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, CNYH,
+     2   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP
+      INTEGER ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
+     1   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
+      INTEGER I, I1, IREDO, IRET, J, JB, M, NCF, NEWQ
+      DOUBLE PRECISION CONIT, CRATE, EL, ELCO, HOLD, RMAX, TESCO,
+     2   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND
+      DOUBLE PRECISION DCON, DDN, DEL, DELP, DSM, DUP, EXDN, EXSM, EXUP,
+     1   R, RH, RHDN, RHSM, RHUP, TOLD, DVNORM
+      COMMON /DLS001/ CONIT, CRATE, EL(13), ELCO(13,12),
+     1   HOLD, RMAX, TESCO(3,12),
+     2   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND,
+     2   ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
+     3   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, CNYH,
+     3   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP,
+     4   ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
+     5   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
+C
+C***FIRST EXECUTABLE STATEMENT  DSTODE
+      KFLAG = 0
+      TOLD = TN
+      NCF = 0
+      IERPJ = 0
+      IERSL = 0
+      JCUR = 0
+      ICF = 0
+      DELP = 0.0D0
+      IF (JSTART .GT. 0) GO TO 200
+      IF (JSTART .EQ. -1) GO TO 100
+      IF (JSTART .EQ. -2) GO TO 160
+C-----------------------------------------------------------------------
+C On the first call, the order is set to 1, and other variables are
+C initialized.  RMAX is the maximum ratio by which H can be increased
+C in a single step.  It is initially 1.E4 to compensate for the small
+C initial H, but then is normally equal to 10.  If a failure
+C occurs (in corrector convergence or error test), RMAX is set to 2
+C for the next increase.
+C-----------------------------------------------------------------------
+      LMAX = MAXORD + 1
+      NQ = 1
+      L = 2
+      IALTH = 2
+      RMAX = 10000.0D0
+      RC = 0.0D0
+      EL0 = 1.0D0
+      CRATE = 0.7D0
+      HOLD = H
+      MEO = METH
+      NSLP = 0
+      IPUP = MITER
+      IRET = 3
+      GO TO 140
+C-----------------------------------------------------------------------
+C The following block handles preliminaries needed when JSTART = -1.
+C IPUP is set to MITER to force a matrix update.
+C If an order increase is about to be considered (IALTH = 1),
+C IALTH is reset to 2 to postpone consideration one more step.
+C If the caller has changed METH, DCFODE is called to reset
+C the coefficients of the method.
+C If the caller has changed MAXORD to a value less than the current
+C order NQ, NQ is reduced to MAXORD, and a new H chosen accordingly.
+C If H is to be changed, YH must be rescaled.
+C If H or METH is being changed, IALTH is reset to L = NQ + 1
+C to prevent further changes in H for that many steps.
+C-----------------------------------------------------------------------
+ 100  IPUP = MITER
+      LMAX = MAXORD + 1
+      IF (IALTH .EQ. 1) IALTH = 2
+      IF (METH .EQ. MEO) GO TO 110
+      CALL DCFODE (METH, ELCO, TESCO)
+      MEO = METH
+      IF (NQ .GT. MAXORD) GO TO 120
+      IALTH = L
+      IRET = 1
+      GO TO 150
+ 110  IF (NQ .LE. MAXORD) GO TO 160
+ 120  NQ = MAXORD
+      L = LMAX
+      DO 125 I = 1,L
+ 125    EL(I) = ELCO(I,NQ)
+      NQNYH = NQ*NYH
+      RC = RC*EL(1)/EL0
+      EL0 = EL(1)
+      CONIT = 0.5D0/(NQ+2)
+      DDN = DVNORM (N, SAVF, EWT)/TESCO(1,L)
+      EXDN = 1.0D0/L
+      RHDN = 1.0D0/(1.3D0*DDN**EXDN + 0.0000013D0)
+      RH = MIN(RHDN,1.0D0)
+      IREDO = 3
+      IF (H .EQ. HOLD) GO TO 170
+      RH = MIN(RH,ABS(H/HOLD))
+      H = HOLD
+      GO TO 175
+C-----------------------------------------------------------------------
+C DCFODE is called to get all the integration coefficients for the
+C current METH.  Then the EL vector and related constants are reset
+C whenever the order NQ is changed, or at the start of the problem.
+C-----------------------------------------------------------------------
+ 140  CALL DCFODE (METH, ELCO, TESCO)
+ 150  DO 155 I = 1,L
+ 155    EL(I) = ELCO(I,NQ)
+      NQNYH = NQ*NYH
+      RC = RC*EL(1)/EL0
+      EL0 = EL(1)
+      CONIT = 0.5D0/(NQ+2)
+      GO TO (160, 170, 200), IRET
+C-----------------------------------------------------------------------
+C If H is being changed, the H ratio RH is checked against
+C RMAX, HMIN, and HMXI, and the YH array rescaled.  IALTH is set to
+C L = NQ + 1 to prevent a change of H for that many steps, unless
+C forced by a convergence or error test failure.
+C-----------------------------------------------------------------------
+ 160  IF (H .EQ. HOLD) GO TO 200
+      RH = H/HOLD
+      H = HOLD
+      IREDO = 3
+      GO TO 175
+ 170  RH = MAX(RH,HMIN/ABS(H))
+ 175  RH = MIN(RH,RMAX)
+      RH = RH/MAX(1.0D0,ABS(H)*HMXI*RH)
+      R = 1.0D0
+      DO 180 J = 2,L
+        R = R*RH
+        DO 180 I = 1,N
+ 180      YH(I,J) = YH(I,J)*R
+      H = H*RH
+      RC = RC*RH
+      IALTH = L
+      IF (IREDO .EQ. 0) GO TO 690
+C-----------------------------------------------------------------------
+C This section computes the predicted values by effectively
+C multiplying the YH array by the Pascal Triangle matrix.
+C RC is the ratio of new to old values of the coefficient  H*EL(1).
+C When RC differs from 1 by more than CCMAX, IPUP is set to MITER
+C to force PJAC to be called, if a Jacobian is involved.
+C In any case, PJAC is called at least every MSBP steps.
+C-----------------------------------------------------------------------
+ 200  IF (ABS(RC-1.0D0) .GT. CCMAX) IPUP = MITER
+      IF (NST .GE. NSLP+MSBP) IPUP = MITER
+      TN = TN + H
+      I1 = NQNYH + 1
+      DO 215 JB = 1,NQ
+        I1 = I1 - NYH
+Cdir$ ivdep
+        DO 210 I = I1,NQNYH
+ 210      YH1(I) = YH1(I) + YH1(I+NYH)
+ 215    CONTINUE
+C-----------------------------------------------------------------------
+C Up to MAXCOR corrector iterations are taken.  A convergence test is
+C made on the R.M.S. norm of each correction, weighted by the error
+C weight vector EWT.  The sum of the corrections is accumulated in the
+C vector ACOR(i).  The YH array is not altered in the corrector loop.
+C-----------------------------------------------------------------------
+ 220  M = 0
+      DO 230 I = 1,N
+ 230    Y(I) = YH(I,1)
+      CALL F (NEQ, TN, Y, SAVF)
+      NFE = NFE + 1
+      IF (IPUP .LE. 0) GO TO 250
+C-----------------------------------------------------------------------
+C If indicated, the matrix P = I - h*el(1)*J is reevaluated and
+C preprocessed before starting the corrector iteration.  IPUP is set
+C to 0 as an indicator that this has been done.
+C-----------------------------------------------------------------------
+      CALL PJAC (NEQ, Y, YH, NYH, EWT, ACOR, SAVF, WM, IWM, F, JAC)
+      IPUP = 0
+      RC = 1.0D0
+      NSLP = NST
+      CRATE = 0.7D0
+      IF (IERPJ .NE. 0) GO TO 430
+ 250  DO 260 I = 1,N
+ 260    ACOR(I) = 0.0D0
+ 270  IF (MITER .NE. 0) GO TO 350
+C-----------------------------------------------------------------------
+C In the case of functional iteration, update Y directly from
+C the result of the last function evaluation.
+C-----------------------------------------------------------------------
+      DO 290 I = 1,N
+        SAVF(I) = H*SAVF(I) - YH(I,2)
+ 290    Y(I) = SAVF(I) - ACOR(I)
+      DEL = DVNORM (N, Y, EWT)
+      DO 300 I = 1,N
+        Y(I) = YH(I,1) + EL(1)*SAVF(I)
+ 300    ACOR(I) = SAVF(I)
+      GO TO 400
+C-----------------------------------------------------------------------
+C In the case of the chord method, compute the corrector error,
+C and solve the linear system with that as right-hand side and
+C P as coefficient matrix.
+C-----------------------------------------------------------------------
+ 350  DO 360 I = 1,N
+ 360    Y(I) = H*SAVF(I) - (YH(I,2) + ACOR(I))
+      CALL SLVS (WM, IWM, Y, SAVF)
+      IF (IERSL .LT. 0) GO TO 430
+      IF (IERSL .GT. 0) GO TO 410
+      DEL = DVNORM (N, Y, EWT)
+      DO 380 I = 1,N
+        ACOR(I) = ACOR(I) + Y(I)
+ 380    Y(I) = YH(I,1) + EL(1)*ACOR(I)
+C-----------------------------------------------------------------------
+C Test for convergence.  If M.gt.0, an estimate of the convergence
+C rate constant is stored in CRATE, and this is used in the test.
+C-----------------------------------------------------------------------
+ 400  IF (M .NE. 0) CRATE = MAX(0.2D0*CRATE,DEL/DELP)
+      DCON = DEL*MIN(1.0D0,1.5D0*CRATE)/(TESCO(2,NQ)*CONIT)
+      IF (DCON .LE. 1.0D0) GO TO 450
+      M = M + 1
+      IF (M .EQ. MAXCOR) GO TO 410
+      IF (M .GE. 2 .AND. DEL .GT. 2.0D0*DELP) GO TO 410
+      DELP = DEL
+      CALL F (NEQ, TN, Y, SAVF)
+      NFE = NFE + 1
+      GO TO 270
+C-----------------------------------------------------------------------
+C The corrector iteration failed to converge.
+C If MITER .ne. 0 and the Jacobian is out of date, PJAC is called for
+C the next try.  Otherwise the YH array is retracted to its values
+C before prediction, and H is reduced, if possible.  If H cannot be
+C reduced or MXNCF failures have occurred, exit with KFLAG = -2.
+C-----------------------------------------------------------------------
+ 410  IF (MITER .EQ. 0 .OR. JCUR .EQ. 1) GO TO 430
+      ICF = 1
+      IPUP = MITER
+      GO TO 220
+ 430  ICF = 2
+      NCF = NCF + 1
+      RMAX = 2.0D0
+      TN = TOLD
+      I1 = NQNYH + 1
+      DO 445 JB = 1,NQ
+        I1 = I1 - NYH
+Cdir$ ivdep
+        DO 440 I = I1,NQNYH
+ 440      YH1(I) = YH1(I) - YH1(I+NYH)
+ 445    CONTINUE
+      IF (IERPJ .LT. 0 .OR. IERSL .LT. 0) GO TO 680
+      IF (ABS(H) .LE. HMIN*1.00001D0) GO TO 670
+      IF (NCF .EQ. MXNCF) GO TO 670
+      RH = 0.25D0
+      IPUP = MITER
+      IREDO = 1
+      GO TO 170
+C-----------------------------------------------------------------------
+C The corrector has converged.  JCUR is set to 0
+C to signal that the Jacobian involved may need updating later.
+C The local error test is made and control passes to statement 500
+C if it fails.
+C-----------------------------------------------------------------------
+ 450  JCUR = 0
+      IF (M .EQ. 0) DSM = DEL/TESCO(2,NQ)
+      IF (M .GT. 0) DSM = DVNORM (N, ACOR, EWT)/TESCO(2,NQ)
+      IF (DSM .GT. 1.0D0) GO TO 500
+C-----------------------------------------------------------------------
+C After a successful step, update the YH array.
+C Consider changing H if IALTH = 1.  Otherwise decrease IALTH by 1.
+C If IALTH is then 1 and NQ .lt. MAXORD, then ACOR is saved for
+C use in a possible order increase on the next step.
+C If a change in H is considered, an increase or decrease in order
+C by one is considered also.  A change in H is made only if it is by a
+C factor of at least 1.1.  If not, IALTH is set to 3 to prevent
+C testing for that many steps.
+C-----------------------------------------------------------------------
+      KFLAG = 0
+      IREDO = 0
+      NST = NST + 1
+      HU = H
+      NQU = NQ
+      DO 470 J = 1,L
+        DO 470 I = 1,N
+ 470      YH(I,J) = YH(I,J) + EL(J)*ACOR(I)
+      IALTH = IALTH - 1
+      IF (IALTH .EQ. 0) GO TO 520
+      IF (IALTH .GT. 1) GO TO 700
+      IF (L .EQ. LMAX) GO TO 700
+      DO 490 I = 1,N
+ 490    YH(I,LMAX) = ACOR(I)
+      GO TO 700
+C-----------------------------------------------------------------------
+C The error test failed.  KFLAG keeps track of multiple failures.
+C Restore TN and the YH array to their previous values, and prepare
+C to try the step again.  Compute the optimum step size for this or
+C one lower order.  After 2 or more failures, H is forced to decrease
+C by a factor of 0.2 or less.
+C-----------------------------------------------------------------------
+ 500  KFLAG = KFLAG - 1
+      TN = TOLD
+      I1 = NQNYH + 1
+      DO 515 JB = 1,NQ
+        I1 = I1 - NYH
+Cdir$ ivdep
+        DO 510 I = I1,NQNYH
+ 510      YH1(I) = YH1(I) - YH1(I+NYH)
+ 515    CONTINUE
+      RMAX = 2.0D0
+      IF (ABS(H) .LE. HMIN*1.00001D0) GO TO 660
+      IF (KFLAG .LE. -3) GO TO 640
+      IREDO = 2
+      RHUP = 0.0D0
+      GO TO 540
+C-----------------------------------------------------------------------
+C Regardless of the success or failure of the step, factors
+C RHDN, RHSM, and RHUP are computed, by which H could be multiplied
+C at order NQ - 1, order NQ, or order NQ + 1, respectively.
+C In the case of failure, RHUP = 0.0 to avoid an order increase.
+C The largest of these is determined and the new order chosen
+C accordingly.  If the order is to be increased, we compute one
+C additional scaled derivative.
+C-----------------------------------------------------------------------
+ 520  RHUP = 0.0D0
+      IF (L .EQ. LMAX) GO TO 540
+      DO 530 I = 1,N
+ 530    SAVF(I) = ACOR(I) - YH(I,LMAX)
+      DUP = DVNORM (N, SAVF, EWT)/TESCO(3,NQ)
+      EXUP = 1.0D0/(L+1)
+      RHUP = 1.0D0/(1.4D0*DUP**EXUP + 0.0000014D0)
+ 540  EXSM = 1.0D0/L
+      RHSM = 1.0D0/(1.2D0*DSM**EXSM + 0.0000012D0)
+      RHDN = 0.0D0
+      IF (NQ .EQ. 1) GO TO 560
+      DDN = DVNORM (N, YH(1,L), EWT)/TESCO(1,NQ)
+      EXDN = 1.0D0/NQ
+      RHDN = 1.0D0/(1.3D0*DDN**EXDN + 0.0000013D0)
+ 560  IF (RHSM .GE. RHUP) GO TO 570
+      IF (RHUP .GT. RHDN) GO TO 590
+      GO TO 580
+ 570  IF (RHSM .LT. RHDN) GO TO 580
+      NEWQ = NQ
+      RH = RHSM
+      GO TO 620
+ 580  NEWQ = NQ - 1
+      RH = RHDN
+      IF (KFLAG .LT. 0 .AND. RH .GT. 1.0D0) RH = 1.0D0
+      GO TO 620
+ 590  NEWQ = L
+      RH = RHUP
+      IF (RH .LT. 1.1D0) GO TO 610
+      R = EL(L)/L
+      DO 600 I = 1,N
+ 600    YH(I,NEWQ+1) = ACOR(I)*R
+      GO TO 630
+ 610  IALTH = 3
+      GO TO 700
+ 620  IF ((KFLAG .EQ. 0) .AND. (RH .LT. 1.1D0)) GO TO 610
+      IF (KFLAG .LE. -2) RH = MIN(RH,0.2D0)
+C-----------------------------------------------------------------------
+C If there is a change of order, reset NQ, l, and the coefficients.
+C In any case H is reset according to RH and the YH array is rescaled.
+C Then exit from 690 if the step was OK, or redo the step otherwise.
+C-----------------------------------------------------------------------
+      IF (NEWQ .EQ. NQ) GO TO 170
+ 630  NQ = NEWQ
+      L = NQ + 1
+      IRET = 2
+      GO TO 150
+C-----------------------------------------------------------------------
+C Control reaches this section if 3 or more failures have occured.
+C If 10 failures have occurred, exit with KFLAG = -1.
+C It is assumed that the derivatives that have accumulated in the
+C YH array have errors of the wrong order.  Hence the first
+C derivative is recomputed, and the order is set to 1.  Then
+C H is reduced by a factor of 10, and the step is retried,
+C until it succeeds or H reaches HMIN.
+C-----------------------------------------------------------------------
+ 640  IF (KFLAG .EQ. -10) GO TO 660
+      RH = 0.1D0
+      RH = MAX(HMIN/ABS(H),RH)
+      H = H*RH
+      DO 645 I = 1,N
+ 645    Y(I) = YH(I,1)
+      CALL F (NEQ, TN, Y, SAVF)
+      NFE = NFE + 1
+      DO 650 I = 1,N
+ 650    YH(I,2) = H*SAVF(I)
+      IPUP = MITER
+      IALTH = 5
+      IF (NQ .EQ. 1) GO TO 200
+      NQ = 1
+      L = 2
+      IRET = 3
+      GO TO 150
+C-----------------------------------------------------------------------
+C All returns are made through this section.  H is saved in HOLD
+C to allow the caller to change H on the next step.
+C-----------------------------------------------------------------------
+ 660  KFLAG = -1
+      GO TO 720
+ 670  KFLAG = -2
+      GO TO 720
+ 680  KFLAG = -3
+      GO TO 720
+ 690  RMAX = 10.0D0
+ 700  R = 1.0D0/TESCO(2,NQU)
+      DO 710 I = 1,N
+ 710    ACOR(I) = ACOR(I)*R
+ 720  HOLD = H
+      JSTART = 1
+      RETURN
+C----------------------- END OF SUBROUTINE DSTODE ----------------------
+      END
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/external/odepack/dvnorm.f	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,34 @@
+      DOUBLE PRECISION FUNCTION DVNORM (N, V, W)
+C***BEGIN PROLOGUE  DVNORM
+C***SUBSIDIARY
+C***PURPOSE  Weighted root-mean-square vector norm.
+C***TYPE      DOUBLE PRECISION (SVNORM-S, DVNORM-D)
+C***AUTHOR  Hindmarsh, Alan C., (LLNL)
+C***DESCRIPTION
+C
+C  This function routine computes the weighted root-mean-square norm
+C  of the vector of length N contained in the array V, with weights
+C  contained in the array W of length N:
+C    DVNORM = SQRT( (1/N) * SUM( V(i)*W(i) )**2 )
+C
+C***SEE ALSO  DLSODE
+C***ROUTINES CALLED  (NONE)
+C***REVISION HISTORY  (YYMMDD)
+C   791129  DATE WRITTEN
+C   890501  Modified prologue to SLATEC/LDOC format.  (FNF)
+C   890503  Minor cosmetic changes.  (FNF)
+C   930809  Renamed to allow single/double precision versions. (ACH)
+C***END PROLOGUE  DVNORM
+C**End
+      INTEGER N,   I
+      DOUBLE PRECISION V, W,   SUM
+      DIMENSION V(N), W(N)
+C
+C***FIRST EXECUTABLE STATEMENT  DVNORM
+      SUM = 0.0D0
+      DO 10 I = 1,N
+ 10     SUM = SUM + (V(I)*W(I))**2
+      DVNORM = SQRT(SUM/N)
+      RETURN
+C----------------------- END OF FUNCTION DVNORM ------------------------
+      END
--- a/liboctave/external/odepack/ewset.f	Thu Nov 19 13:05:51 2020 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-      SUBROUTINE EWSET (N, ITOL, RTOL, ATOL, YCUR, EWT)
-CLLL. OPTIMIZE
-C-----------------------------------------------------------------------
-C THIS SUBROUTINE SETS THE ERROR WEIGHT VECTOR EWT ACCORDING TO
-C     EWT(I) = RTOL(I)*ABS(YCUR(I)) + ATOL(I),  I = 1,...,N,
-C WITH THE SUBSCRIPT ON RTOL AND/OR ATOL POSSIBLY REPLACED BY 1 ABOVE,
-C DEPENDING ON THE VALUE OF ITOL.
-C-----------------------------------------------------------------------
-      INTEGER N, ITOL
-      INTEGER I
-      DOUBLE PRECISION RTOL, ATOL, YCUR, EWT
-      DIMENSION RTOL(*), ATOL(*), YCUR(N), EWT(N)
-C
-      GO TO (10, 20, 30, 40), ITOL
- 10   CONTINUE
-      DO 15 I = 1,N
- 15     EWT(I) = RTOL(1)*DABS(YCUR(I)) + ATOL(1)
-      RETURN
- 20   CONTINUE
-      DO 25 I = 1,N
- 25     EWT(I) = RTOL(1)*DABS(YCUR(I)) + ATOL(I)
-      RETURN
- 30   CONTINUE
-      DO 35 I = 1,N
- 35     EWT(I) = RTOL(I)*DABS(YCUR(I)) + ATOL(1)
-      RETURN
- 40   CONTINUE
-      DO 45 I = 1,N
- 45     EWT(I) = RTOL(I)*DABS(YCUR(I)) + ATOL(I)
-      RETURN
-C----------------------- END OF SUBROUTINE EWSET -----------------------
-      END
--- a/liboctave/external/odepack/intdy.f	Thu Nov 19 13:05:51 2020 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-      SUBROUTINE INTDY (T, K, YH, NYH, DKY, IFLAG)
-CLLL. OPTIMIZE
-      INTEGER K, NYH, IFLAG
-      INTEGER ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
-     1   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, CNYH,
-     2   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP
-      INTEGER ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
-     2   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
-      INTEGER I, IC, J, JB, JB2, JJ, JJ1, JP1
-      DOUBLE PRECISION T, YH, DKY
-      DOUBLE PRECISION CONIT, CRATE, EL, ELCO, HOLD, RMAX, TESCO,
-     1   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND
-      DOUBLE PRECISION C, R, S, TP
-      DIMENSION YH(NYH,*), DKY(*)
-      COMMON /LS0001/ CONIT, CRATE, EL(13), ELCO(13,12),
-     1   HOLD, RMAX, TESCO(3,12),
-     2   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND,
-     2   ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
-     3   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, CNYH,
-     3   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP,
-     4   ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
-     5   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
-C-----------------------------------------------------------------------
-C INTDY COMPUTES INTERPOLATED VALUES OF THE K-TH DERIVATIVE OF THE
-C DEPENDENT VARIABLE VECTOR Y, AND STORES IT IN DKY.  THIS ROUTINE
-C IS CALLED WITHIN THE PACKAGE WITH K = 0 AND T = TOUT, BUT MAY
-C ALSO BE CALLED BY THE USER FOR ANY K UP TO THE CURRENT ORDER.
-C (SEE DETAILED INSTRUCTIONS IN THE USAGE DOCUMENTATION.)
-C-----------------------------------------------------------------------
-C THE COMPUTED VALUES IN DKY ARE GOTTEN BY INTERPOLATION USING THE
-C NORDSIECK HISTORY ARRAY YH.  THIS ARRAY CORRESPONDS UNIQUELY TO A
-C VECTOR-VALUED POLYNOMIAL OF DEGREE NQCUR OR LESS, AND DKY IS SET
-C TO THE K-TH DERIVATIVE OF THIS POLYNOMIAL AT T.
-C THE FORMULA FOR DKY IS..
-C              Q
-C  DKY(I)  =  SUM  C(J,K) * (T - TN)**(J-K) * H**(-J) * YH(I,J+1)
-C             J=K
-C WHERE  C(J,K) = J*(J-1)*...*(J-K+1), Q = NQCUR, TN = TCUR, H = HCUR.
-C THE QUANTITIES  NQ = NQCUR, L = NQ+1, N = NEQ, TN, AND H ARE
-C COMMUNICATED BY COMMON.  THE ABOVE SUM IS DONE IN REVERSE ORDER.
-C IFLAG IS RETURNED NEGATIVE IF EITHER K OR T IS OUT OF BOUNDS.
-C-----------------------------------------------------------------------
-      IFLAG = 0
-      IF (K .LT. 0 .OR. K .GT. NQ) GO TO 80
-      TP = TN - HU -  100.0D0*UROUND*(TN + HU)
-      IF ((T-TP)*(T-TN) .GT. 0.0D0) GO TO 90
-C
-      S = (T - TN)/H
-      IC = 1
-      IF (K .EQ. 0) GO TO 15
-      JJ1 = L - K
-      DO 10 JJ = JJ1,NQ
- 10     IC = IC*JJ
- 15   C = DBLE(IC)
-      DO 20 I = 1,N
- 20     DKY(I) = C*YH(I,L)
-      IF (K .EQ. NQ) GO TO 55
-      JB2 = NQ - K
-      DO 50 JB = 1,JB2
-        J = NQ - JB
-        JP1 = J + 1
-        IC = 1
-        IF (K .EQ. 0) GO TO 35
-        JJ1 = JP1 - K
-        DO 30 JJ = JJ1,J
- 30       IC = IC*JJ
- 35     C = DBLE(IC)
-        DO 40 I = 1,N
- 40       DKY(I) = C*YH(I,JP1) + S*DKY(I)
- 50     CONTINUE
-      IF (K .EQ. 0) RETURN
- 55   R = H**(-K)
-      DO 60 I = 1,N
- 60     DKY(I) = R*DKY(I)
-      RETURN
-C
- 80   CALL XERRWD('INTDY--  K (=I1) ILLEGAL      ',
-     1   30, 51, 0, 1, K, 0, 0, 0.0D0, 0.0D0)
-      IFLAG = -1
-      RETURN
- 90   CALL XERRWD('INTDY--  T (=R1) ILLEGAL      ',
-     1   30, 52, 0, 0, 0, 0, 1, T, 0.0D0)
-      CALL XERRWD(
-     1  '      T NOT IN INTERVAL TCUR - HU (= R1) TO TCUR (=R2)      ',
-     1   60, 52, 0, 0, 0, 0, 2, TP, TN)
-      IFLAG = -2
-      RETURN
-C----------------------- END OF SUBROUTINE INTDY -----------------------
-      END
--- a/liboctave/external/odepack/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/external/odepack/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -1,12 +1,12 @@
 EXTERNAL_SOURCES += \
-  %reldir%/cfode.f \
+  %reldir%/dcfode.f \
+  %reldir%/dewset.f \
+  %reldir%/dintdy.f \
   %reldir%/dlsode.f \
-  %reldir%/ewset.f \
-  %reldir%/intdy.f \
-  %reldir%/prepj.f \
-  %reldir%/solsy.f \
-  %reldir%/stode.f \
-  %reldir%/vnorm.f \
+  %reldir%/dprepj.f \
+  %reldir%/dsolsy.f \
+  %reldir%/dstode.f \
+  %reldir%/dvnorm.f \
   %reldir%/scfode.f \
   %reldir%/sewset.f \
   %reldir%/sintdy.f \
--- a/liboctave/external/odepack/prepj.f	Thu Nov 19 13:05:51 2020 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,182 +0,0 @@
-      SUBROUTINE PREPJ (NEQ, Y, YH, NYH, EWT, FTEM, SAVF, WM, IWM,
-     1   F, JAC, IERR)
-CLLL. OPTIMIZE
-      EXTERNAL F, JAC
-      INTEGER NEQ, NYH, IWM
-      INTEGER ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
-     1   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, CNYH,
-     2   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP
-      INTEGER ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
-     2   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
-      INTEGER I, I1, I2, IER, II, J, J1, JJ, LENP,
-     1   MBA, MBAND, MEB1, MEBAND, ML, ML3, MU, NP1
-      DOUBLE PRECISION Y, YH, EWT, FTEM, SAVF, WM
-      DOUBLE PRECISION CONIT, CRATE, EL, ELCO, HOLD, RMAX, TESCO,
-     1   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND
-      DOUBLE PRECISION CON, DI, FAC, HL0, R, R0, SRUR, YI, YJ, YJJ,
-     1   VNORM
-      DIMENSION NEQ(*), Y(*), YH(NYH,*), EWT(*), FTEM(*), SAVF(*),
-     1   WM(*), IWM(*)
-      COMMON /LS0001/ CONIT, CRATE, EL(13), ELCO(13,12),
-     1   HOLD, RMAX, TESCO(3,12),
-     2   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND,
-     2   ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
-     3   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, CNYH,
-     3   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP,
-     4   ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
-     5   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
-C-----------------------------------------------------------------------
-C PREPJ IS CALLED BY STODE TO COMPUTE AND PROCESS THE MATRIX
-C P = I - H*EL(1)*J , WHERE J IS AN APPROXIMATION TO THE JACOBIAN.
-C HERE J IS COMPUTED BY THE USER-SUPPLIED ROUTINE JAC IF
-C MITER = 1 OR 4, OR BY FINITE DIFFERENCING IF MITER = 2, 3, OR 5.
-C IF MITER = 3, A DIAGONAL APPROXIMATION TO J IS USED.
-C J IS STORED IN WM AND REPLACED BY P.  IF MITER .NE. 3, P IS THEN
-C SUBJECTED TO LU DECOMPOSITION IN PREPARATION FOR LATER SOLUTION
-C OF LINEAR SYSTEMS WITH P AS COEFFICIENT MATRIX. THIS IS DONE
-C BY DGETRF IF MITER = 1 OR 2, AND BY DGBTRF IF MITER = 4 OR 5.
-C
-C IN ADDITION TO VARIABLES DESCRIBED PREVIOUSLY, COMMUNICATION
-C WITH PREPJ USES THE FOLLOWING..
-C Y     = ARRAY CONTAINING PREDICTED VALUES ON ENTRY.
-C FTEM  = WORK ARRAY OF LENGTH N (ACOR IN STODE).
-C SAVF  = ARRAY CONTAINING F EVALUATED AT PREDICTED Y.
-C WM    = REAL WORK SPACE FOR MATRICES.  ON OUTPUT IT CONTAINS THE
-C         INVERSE DIAGONAL MATRIX IF MITER = 3 AND THE LU DECOMPOSITION
-C         OF P IF MITER IS 1, 2 , 4, OR 5.
-C         STORAGE OF MATRIX ELEMENTS STARTS AT WM(3).
-C         WM ALSO CONTAINS THE FOLLOWING MATRIX-RELATED DATA..
-C         WM(1) = SQRT(UROUND), USED IN NUMERICAL JACOBIAN INCREMENTS.
-C         WM(2) = H*EL0, SAVED FOR LATER USE IF MITER = 3.
-C IWM   = INTEGER WORK SPACE CONTAINING PIVOT INFORMATION, STARTING AT
-C         IWM(21), IF MITER IS 1, 2, 4, OR 5.  IWM ALSO CONTAINS BAND
-C         PARAMETERS ML = IWM(1) AND MU = IWM(2) IF MITER IS 4 OR 5.
-C EL0   = EL(1) (INPUT).
-C IERPJ = OUTPUT ERROR FLAG,  = 0 IF NO TROUBLE, .GT. 0 IF
-C         P MATRIX FOUND TO BE SINGULAR.
-C JCUR  = OUTPUT FLAG = 1 TO INDICATE THAT THE JACOBIAN MATRIX
-C         (OR APPROXIMATION) IS NOW CURRENT.
-C THIS ROUTINE ALSO USES THE COMMON VARIABLES EL0, H, TN, UROUND,
-C MITER, N, NFE, AND NJE.
-C-----------------------------------------------------------------------
-      NJE = NJE + 1
-      IERPJ = 0
-      JCUR = 1
-      HL0 = H*EL0
-      GO TO (100, 200, 300, 400, 500), MITER
-C IF MITER = 1, CALL JAC AND MULTIPLY BY SCALAR. -----------------------
- 100  LENP = N*N
-      DO 110 I = 1,LENP
- 110    WM(I+2) = 0.0D0
-      CALL JAC (NEQ, TN, Y, 0, 0, WM(3), N)
-      CON = -HL0
-      DO 120 I = 1,LENP
- 120    WM(I+2) = WM(I+2)*CON
-      GO TO 240
-C IF MITER = 2, MAKE N CALLS TO F TO APPROXIMATE J. --------------------
- 200  FAC = VNORM (N, SAVF, EWT)
-      R0 = 1000.0D0*DABS(H)*UROUND*DBLE(N)*FAC
-      IF (R0 .EQ. 0.0D0) R0 = 1.0D0
-      SRUR = WM(1)
-      J1 = 2
-      DO 230 J = 1,N
-        YJ = Y(J)
-        R = DMAX1(SRUR*DABS(YJ),R0/EWT(J))
-        Y(J) = Y(J) + R
-        FAC = -HL0/R
-        IERR = 0
-        CALL F (NEQ, TN, Y, FTEM, IERR)
-        IF (IERR .LT. 0) RETURN
-        DO 220 I = 1,N
- 220      WM(I+J1) = (FTEM(I) - SAVF(I))*FAC
-        Y(J) = YJ
-        J1 = J1 + N
- 230    CONTINUE
-      NFE = NFE + N
-C ADD IDENTITY MATRIX. -------------------------------------------------
- 240  J = 3
-      NP1 = N + 1
-      DO 250 I = 1,N
-        WM(J) = WM(J) + 1.0D0
- 250    J = J + NP1
-C DO LU DECOMPOSITION ON P. --------------------------------------------
-      CALL DGETRF ( N, N, WM(3), N, IWM(21), IER)
-      IF (IER .NE. 0) IERPJ = 1
-      RETURN
-C IF MITER = 3, CONSTRUCT A DIAGONAL APPROXIMATION TO J AND P. ---------
- 300  WM(2) = HL0
-      R = EL0*0.1D0
-      DO 310 I = 1,N
- 310    Y(I) = Y(I) + R*(H*SAVF(I) - YH(I,2))
-      IERR = 0
-      CALL F (NEQ, TN, Y, WM(3), IERR)
-      IF (IERR .LT. 0) RETURN
-      NFE = NFE + 1
-      DO 320 I = 1,N
-        R0 = H*SAVF(I) - YH(I,2)
-        DI = 0.1D0*R0 - H*(WM(I+2) - SAVF(I))
-        WM(I+2) = 1.0D0
-        IF (DABS(R0) .LT. UROUND/EWT(I)) GO TO 320
-        IF (DABS(DI) .EQ. 0.0D0) GO TO 330
-        WM(I+2) = 0.1D0*R0/DI
- 320    CONTINUE
-      RETURN
- 330  IERPJ = 1
-      RETURN
-C IF MITER = 4, CALL JAC AND MULTIPLY BY SCALAR. -----------------------
- 400  ML = IWM(1)
-      MU = IWM(2)
-      ML3 = ML + 3
-      MBAND = ML + MU + 1
-      MEBAND = MBAND + ML
-      LENP = MEBAND*N
-      DO 410 I = 1,LENP
- 410    WM(I+2) = 0.0D0
-      CALL JAC (NEQ, TN, Y, ML, MU, WM(ML3), MEBAND)
-      CON = -HL0
-      DO 420 I = 1,LENP
- 420    WM(I+2) = WM(I+2)*CON
-      GO TO 570
-C IF MITER = 5, MAKE MBAND CALLS TO F TO APPROXIMATE J. ----------------
- 500  ML = IWM(1)
-      MU = IWM(2)
-      MBAND = ML + MU + 1
-      MBA = MIN0(MBAND,N)
-      MEBAND = MBAND + ML
-      MEB1 = MEBAND - 1
-      SRUR = WM(1)
-      FAC = VNORM (N, SAVF, EWT)
-      R0 = 1000.0D0*DABS(H)*UROUND*DBLE(N)*FAC
-      IF (R0 .EQ. 0.0D0) R0 = 1.0D0
-      DO 560 J = 1,MBA
-        DO 530 I = J,N,MBAND
-          YI = Y(I)
-          R = DMAX1(SRUR*DABS(YI),R0/EWT(I))
- 530      Y(I) = Y(I) + R
-        IERR = 0
-        CALL F (NEQ, TN, Y, FTEM, IERR)
-        IF (IERR .LT. 0) RETURN
-        DO 550 JJ = J,N,MBAND
-          Y(JJ) = YH(JJ,1)
-          YJJ = Y(JJ)
-          R = DMAX1(SRUR*DABS(YJJ),R0/EWT(JJ))
-          FAC = -HL0/R
-          I1 = MAX0(JJ-MU,1)
-          I2 = MIN0(JJ+ML,N)
-          II = JJ*MEB1 - ML + 2
-          DO 540 I = I1,I2
- 540        WM(II+I) = (FTEM(I) - SAVF(I))*FAC
- 550      CONTINUE
- 560    CONTINUE
-      NFE = NFE + MBA
-C ADD IDENTITY MATRIX. -------------------------------------------------
- 570  II = MBAND + 2
-      DO 580 I = 1,N
-        WM(II) = WM(II) + 1.0D0
- 580    II = II + MEBAND
-C DO LU DECOMPOSITION OF P. --------------------------------------------
-      CALL DGBTRF ( N, N, ML, MU, WM(3), MEBAND, IWM(21), IER)
-      IF (IER .NE. 0) IERPJ = 1
-      RETURN
-C----------------------- END OF SUBROUTINE PREPJ -----------------------
-      END
--- a/liboctave/external/odepack/sintdy.f	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/external/odepack/sintdy.f	Thu Nov 19 13:08:00 2020 -0800
@@ -96,15 +96,14 @@
  60     DKY(I) = R*DKY(I)
       RETURN
 C
- 80   CALL XERRWD('SINTDY-  K (=I1) illegal      ',
-     1     30, 51, 0, 1, K, 0, 0, 0.0D0, 0.0D0)
+ 80   MSG = 'SINTDY-  K (=I1) illegal      '
+      CALL XERRWV (MSG, 30, 51, 0, 1, K, 0, 0, 0.0E0, 0.0E0)
       IFLAG = -1
       RETURN
- 90   CALL XERRWD('SINTDY-  T (=R1) illegal      ',
-     1     30, 52, 0, 0, 0, 0, 1, DBLE (T), 0.0D0)
-      CALL XERRWD(
-     1   '      T not in interval TCUR - HU (= R1) to TCUR (=R2)      ',
-     1    60, 52, 0, 0, 0, 0, 2, DBLE (TP), DBLE (TN))
+ 90   MSG = 'SINTDY-  T (=R1) illegal      '
+      CALL XERRWV (MSG, 30, 52, 0, 0, 0, 0, 1, T, 0.0E0)
+      MSG='      T not in interval TCUR - HU (= R1) to TCUR (=R2)      '
+      CALL XERRWV (MSG, 60, 52, 0, 0, 0, 0, 2, TP, TN)
       IFLAG = -2
       RETURN
 C----------------------- END OF SUBROUTINE SINTDY ----------------------
--- a/liboctave/external/odepack/slsode.f	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/external/odepack/slsode.f	Thu Nov 19 13:08:00 2020 -0800
@@ -1,4 +1,3 @@
-*DECK SLSODE
       SUBROUTINE SLSODE (F, NEQ, Y, T, TOUT, ITOL, RTOL, ATOL, ITASK,
      1                  ISTATE, IOPT, RWORK, LRW, IWORK, LIW, JAC, MF)
       EXTERNAL F, JAC
@@ -1115,7 +1114,7 @@
 C     - Ignore some components of v in the norm, with the effect of
 C       suppressing the error control on those components of Y.
 C  ---------------------------------------------------------------------
-C***ROUTINES CALLED  SEWSET, SINTDY, R1MACH, SSTODE, SVNORM, XERRWD
+C***ROUTINES CALLED  SEWSET, SINTDY, R1MACH, SSTODE, SVNORM, XERRWV
 C***COMMON BLOCKS    SLS001
 C***REVISION HISTORY  (YYYYMMDD)
 C 19791129  DATE WRITTEN
@@ -1195,8 +1194,8 @@
 C  DGBTRF AND DGBTRS   ARE ROUTINES FROM LAPACK FOR SOLVING BANDED
 C           LINEAR SYSTEMS.
 C  R1MACH   computes the unit roundoff in a machine-independent manner.
-C  XERRWD, XSETUN, XSETF, IXSAV, IUMACH   handle the printing of all
-C           error messages and warnings.  XERRWD is machine-dependent.
+C  XERRWV, XSETUN, XSETF, IXSAV, IUMACH   handle the printing of all
+C           error messages and warnings.  XERRWV is machine-dependent.
 C Note: SVNORM, R1MACH, IXSAV, and IUMACH are function routines.
 C All the others are subroutines.
 C
@@ -1507,18 +1506,17 @@
  280  IF ((TN + H) .NE. TN) GO TO 290
       NHNIL = NHNIL + 1
       IF (NHNIL .GT. MXHNIL) GO TO 290
-      CALL XERRWD('SLSODE-  Warning..internal T (=R1) and H (=R2) are',
-     1     50, 101, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD(
-     1  '      such that in the machine, T + H = T on the next step  ',
-     1     60, 101, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      (H = step size). Solver will continue anyway',
-     1     50, 101, 0, 0, 0, 0, 2, DBLE (TN), DBLE (H))
+      MSG = 'SLSODE-  Warning..internal T (=R1) and H (=R2) are'
+      CALL XERRWV (MSG, 50, 101, 0, 0, 0, 0, 0, 0.0E0, 0.0E0)
+      MSG='      such that in the machine, T + H = T on the next step  '
+      CALL XERRWV (MSG, 60, 101, 0, 0, 0, 0, 0, 0.0E0, 0.0E0)
+      MSG = '      (H = step size). Solver will continue anyway'
+      CALL XERRWV (MSG, 50, 101, 0, 0, 0, 0, 2, TN, H)
       IF (NHNIL .LT. MXHNIL) GO TO 290
-      CALL XERRWD('SLSODE-  Above warning has been issued I1 times.  ',
-     1     50, 102, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      It will not be issued again for this problem',
-     1     50, 102, 0, 1, MXHNIL, 0, 0, 0.0D0, 0.0D0)
+      MSG = 'SLSODE-  Above warning has been issued I1 times.  '
+      CALL XERRWV (MSG, 50, 102, 0, 0, 0, 0, 0, 0.0E0, 0.0E0)
+      MSG = '      It will not be issued again for this problem'
+      CALL XERRWV (MSG, 50, 102, 0, 1, MXHNIL, 0, 0, 0.0E0, 0.0E0)
  290  CONTINUE
 C-----------------------------------------------------------------------
 C  CALL SSTODE(NEQ,Y,YH,NYH,YH,EWT,SAVF,ACOR,WM,IWM,F,JAC,SPREPJ,SSOLSY)
@@ -1590,40 +1588,40 @@
 C are loaded into the work arrays before returning.
 C-----------------------------------------------------------------------
 C The maximum number of steps was taken before reaching TOUT. ----------
- 500  CALL XERRWD('SLSODE-  At current T (=R1), MXSTEP (=I1) steps   ',
-     1 50, 201, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      taken on this call before reaching TOUT     ',
-     1     50, 201, 0, 1, MXSTEP, 0, 1, DBLE (TN), 0.0D0)
+ 500  MSG = 'SLSODE-  At current T (=R1), MXSTEP (=I1) steps   '
+      CALL XERRWV (MSG, 50, 201, 0, 0, 0, 0, 0, 0.0E0, 0.0E0)
+      MSG = '      taken on this call before reaching TOUT     '
+      CALL XERRWV (MSG, 50, 201, 0, 1, MXSTEP, 0, 1, TN, 0.0E0)
       ISTATE = -1
       GO TO 580
 C EWT(I) .LE. 0.0 for some I (not at start of problem). ----------------
  510  EWTI = RWORK(LEWT+I-1)
-      CALL XERRWD('SLSODE-  At T (=R1), EWT(I1) has become R2 .LE. 0.',
-     1 50, 202, 0, 1, I, 0, 2, DBLE (TN), DBLE (EWTI))
+      MSG = 'SLSODE-  At T (=R1), EWT(I1) has become R2 .LE. 0.'
+      CALL XERRWV (MSG, 50, 202, 0, 1, I, 0, 2, TN, EWTI)
       ISTATE = -6
       GO TO 580
 C Too much accuracy requested for machine precision. -------------------
- 520  CALL XERRWD('SLSODE-  At T (=R1), too much accuracy requested  ',
-     1     50, 203, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      for precision of machine..  see TOLSF (=R2) ',
-     1     50, 203, 0, 0, 0, 0, 2, DBLE (TN), DBLE (TOLSF))
+ 520  MSG = 'SLSODE-  At T (=R1), too much accuracy requested  '
+      CALL XERRWV (MSG, 50, 203, 0, 0, 0, 0, 0, 0.0E0, 0.0E0)
+      MSG = '      for precision of machine..  see TOLSF (=R2) '
+      CALL XERRWV (MSG, 50, 203, 0, 0, 0, 0, 2, TN, TOLSF)
       RWORK(14) = TOLSF
       ISTATE = -2
       GO TO 580
 C KFLAG = -1.  Error test failed repeatedly or with ABS(H) = HMIN. -----
- 530  CALL XERRWD('SLSODE-  At T(=R1) and step size H(=R2), the error',
-     1     50, 204, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      test failed repeatedly or with ABS(H) = HMIN',
-     1     50, 204, 0, 0, 0, 0, 2, DBLE (TN), DBLE (H))
+ 530  MSG = 'SLSODE-  At T(=R1) and step size H(=R2), the error'
+      CALL XERRWV (MSG, 50, 204, 0, 0, 0, 0, 0, 0.0E0, 0.0E0)
+      MSG = '      test failed repeatedly or with ABS(H) = HMIN'
+      CALL XERRWV (MSG, 50, 204, 0, 0, 0, 0, 2, TN, H)
       ISTATE = -4
       GO TO 560
 C KFLAG = -2.  Convergence failed repeatedly or with ABS(H) = HMIN. ----
- 540  CALL XERRWD('SLSODE-  At T (=R1) and step size H (=R2), the    ',
-     1     50, 205, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      corrector convergence failed repeatedly     ',
-     1     50, 205, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      or with ABS(H) = HMIN   ',
-     1     30, 205, 0, 0, 0, 0, 2, DBLE (TN), DBLE (H))
+ 540  MSG = 'SLSODE-  At T (=R1) and step size H (=R2), the    '
+      CALL XERRWV (MSG, 50, 205, 0, 0, 0, 0, 0, 0.0E0, 0.0E0)
+      MSG = '      corrector convergence failed repeatedly     '
+      CALL XERRWV (MSG, 50, 205, 0, 0, 0, 0, 0, 0.0E0, 0.0E0)
+      MSG = '      or with ABS(H) = HMIN   '
+      CALL XERRWV (MSG, 30, 205, 0, 0, 0, 0, 2, TN, H)
       ISTATE = -5
 C Compute IMXER if relevant. -------------------------------------------
  560  BIG = 0.0E0
@@ -1655,106 +1653,105 @@
 C First the error message routine is called.  If the illegal input
 C is a negative ISTATE, the run is aborted (apparent infinite loop).
 C-----------------------------------------------------------------------
- 601  CALL XERRWD('SLSODE-  ISTATE (=I1) illegal ',
-     1     30, 1, 0, 1, ISTATE, 0, 0, 0.0D0, 0.0D0)
+ 601  MSG = 'SLSODE-  ISTATE (=I1) illegal '
+      CALL XERRWV (MSG, 30, 1, 0, 1, ISTATE, 0, 0, 0.0E0, 0.0E0)
       IF (ISTATE .LT. 0) GO TO 800
       GO TO 700
- 602  CALL XERRWD('SLSODE-  ITASK (=I1) illegal  ',
-     1     30, 2, 0, 1, ITASK, 0, 0, 0.0D0, 0.0D0)
+ 602  MSG = 'SLSODE-  ITASK (=I1) illegal  '
+      CALL XERRWV (MSG, 30, 2, 0, 1, ITASK, 0, 0, 0.0E0, 0.0E0)
       GO TO 700
- 603  CALL XERRWD('SLSODE-  ISTATE .GT. 1 but SLSODE not initialized ',
-     1     50, 3, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
+ 603  MSG = 'SLSODE-  ISTATE .GT. 1 but SLSODE not initialized '
+      CALL XERRWV (MSG, 50, 3, 0, 0, 0, 0, 0, 0.0E0, 0.0E0)
       GO TO 700
- 604  CALL XERRWD('SLSODE-  NEQ (=I1) .LT. 1     ',
-     1     30, 4, 0, 1, NEQ(1), 0, 0, 0.0D0, 0.0D0)
+ 604  MSG = 'SLSODE-  NEQ (=I1) .LT. 1     '
+      CALL XERRWV (MSG, 30, 4, 0, 1, NEQ(1), 0, 0, 0.0E0, 0.0E0)
       GO TO 700
- 605  CALL XERRWD('SLSODE-  ISTATE = 3 and NEQ increased (I1 to I2)  ',
-     1     50, 5, 0, 2, N, NEQ(1), 0, 0.0D0, 0.0D0)
+ 605  MSG = 'SLSODE-  ISTATE = 3 and NEQ increased (I1 to I2)  '
+      CALL XERRWV (MSG, 50, 5, 0, 2, N, NEQ(1), 0, 0.0E0, 0.0E0)
       GO TO 700
- 606  CALL XERRWD('SLSODE-  ITOL (=I1) illegal   ',
-     1     30, 6, 0, 1, ITOL, 0, 0, 0.0D0, 0.0D0)
+ 606  MSG = 'SLSODE-  ITOL (=I1) illegal   '
+      CALL XERRWV (MSG, 30, 6, 0, 1, ITOL, 0, 0, 0.0E0, 0.0E0)
       GO TO 700
- 607  CALL XERRWD('SLSODE-  IOPT (=I1) illegal   ',
-     1     30, 7, 0, 1, IOPT, 0, 0, 0.0D0, 0.0D0)
+ 607  MSG = 'SLSODE-  IOPT (=I1) illegal   '
+      CALL XERRWV (MSG, 30, 7, 0, 1, IOPT, 0, 0, 0.0E0, 0.0E0)
       GO TO 700
- 608  CALL XERRWD('SLSODE-  MF (=I1) illegal     ',
-     1     30, 8, 0, 1, MF, 0, 0, 0.0D0, 0.0D0)
+ 608  MSG = 'SLSODE-  MF (=I1) illegal     '
+      CALL XERRWV (MSG, 30, 8, 0, 1, MF, 0, 0, 0.0E0, 0.0E0)
       GO TO 700
- 609  CALL XERRWD('SLSODE-  ML (=I1) illegal.. .LT.0 or .GE.NEQ (=I2)',
-     1     50, 9, 0, 2, ML, NEQ(1), 0, 0.0D0, 0.0D0)
+ 609  MSG = 'SLSODE-  ML (=I1) illegal.. .LT.0 or .GE.NEQ (=I2)'
+      CALL XERRWV (MSG, 50, 9, 0, 2, ML, NEQ(1), 0, 0.0E0, 0.0E0)
       GO TO 700
- 610  CALL XERRWD('SLSODE-  MU (=I1) illegal.. .LT.0 or .GE.NEQ (=I2)',
-     1     50, 10, 0, 2, MU, NEQ(1), 0, 0.0D0, 0.0D0)
+ 610  MSG = 'SLSODE-  MU (=I1) illegal.. .LT.0 or .GE.NEQ (=I2)'
+      CALL XERRWV (MSG, 50, 10, 0, 2, MU, NEQ(1), 0, 0.0E0, 0.0E0)
       GO TO 700
- 611  CALL XERRWD('SLSODE-  MAXORD (=I1) .LT. 0  ',
-     1     30, 11, 0, 1, MAXORD, 0, 0, 0.0D0, 0.0D0)
+ 611  MSG = 'SLSODE-  MAXORD (=I1) .LT. 0  '
+      CALL XERRWV (MSG, 30, 11, 0, 1, MAXORD, 0, 0, 0.0E0, 0.0E0)
       GO TO 700
- 612  CALL XERRWD('SLSODE-  MXSTEP (=I1) .LT. 0  ',
-     1 30, 12, 0, 1, MXSTEP, 0, 0, 0.0D0, 0.0D0)
+ 612  MSG = 'SLSODE-  MXSTEP (=I1) .LT. 0  '
+      CALL XERRWV (MSG, 30, 12, 0, 1, MXSTEP, 0, 0, 0.0E0, 0.0E0)
       GO TO 700
- 613  CALL XERRWD('SLSODE-  MXHNIL (=I1) .LT. 0  ',
-     1     30, 13, 0, 1, MXHNIL, 0, 0, 0.0D0, 0.0D0)
+ 613  MSG = 'SLSODE-  MXHNIL (=I1) .LT. 0  '
+      CALL XERRWV (MSG, 30, 13, 0, 1, MXHNIL, 0, 0, 0.0E0, 0.0E0)
       GO TO 700
- 614  CALL XERRWD('SLSODE-  TOUT (=R1) behind T (=R2)      ',
-     1     40, 14, 0, 0, 0, 0, 2, DBLE (TOUT), DBLE (T))
-      CALL XERRWD('      Integration direction is given by H0 (=R1)  ',
-     1     50, 14, 0, 0, 0, 0, 1, DBLE (H0), 0.0D0)
+ 614  MSG = 'SLSODE-  TOUT (=R1) behind T (=R2)      '
+      CALL XERRWV (MSG, 40, 14, 0, 0, 0, 0, 2, TOUT, T)
+      MSG = '      Integration direction is given by H0 (=R1)  '
+      CALL XERRWV (MSG, 50, 14, 0, 0, 0, 0, 1, H0, 0.0E0)
       GO TO 700
- 615  CALL XERRWD('SLSODE-  HMAX (=R1) .LT. 0.0  ',
-     1     30, 15, 0, 0, 0, 0, 1, DBLE (HMAX), 0.0D0)
+ 615  MSG = 'SLSODE-  HMAX (=R1) .LT. 0.0  '
+      CALL XERRWV (MSG, 30, 15, 0, 0, 0, 0, 1, HMAX, 0.0E0)
       GO TO 700
- 616  CALL XERRWD('SLSODE-  HMIN (=R1) .LT. 0.0  ',
-     1     30, 16, 0, 0, 0, 0, 1, DBLE (HMIN), 0.0D0)
+ 616  MSG = 'SLSODE-  HMIN (=R1) .LT. 0.0  '
+      CALL XERRWV (MSG, 30, 16, 0, 0, 0, 0, 1, HMIN, 0.0E0)
       GO TO 700
- 617  CALL XERRWD(
-     1  'SLSODE-  RWORK length needed, LENRW (=I1), exceeds LRW (=I2)',
-     1   60, 17, 0, 2, LENRW, LRW, 0, 0.0D0, 0.0D0)
+ 617  CONTINUE
+      MSG='SLSODE-  RWORK length needed, LENRW (=I1), exceeds LRW (=I2)'
+      CALL XERRWV (MSG, 60, 17, 0, 2, LENRW, LRW, 0, 0.0E0, 0.0E0)
       GO TO 700
- 618  CALL XERRWD(
-     1   'SLSODE-  IWORK length needed, LENIW (=I1), exceeds LIW (=I2)',
-     1    60, 18, 0, 2, LENIW, LIW, 0, 0.0D0, 0.0D0)
+ 618  CONTINUE
+      MSG='SLSODE-  IWORK length needed, LENIW (=I1), exceeds LIW (=I2)'
+      CALL XERRWV (MSG, 60, 18, 0, 2, LENIW, LIW, 0, 0.0E0, 0.0E0)
       GO TO 700
- 619  CALL XERRWD('SLSODE-  RTOL(I1) is R1 .LT. 0.0        ',
-     1     40, 19, 0, 1, I, 0, 1, DBLE (RTOLI), 0.0D0)
+ 619  MSG = 'SLSODE-  RTOL(I1) is R1 .LT. 0.0        '
+      CALL XERRWV (MSG, 40, 19, 0, 1, I, 0, 1, RTOLI, 0.0E0)
       GO TO 700
- 620  CALL XERRWD('SLSODE-  ATOL(I1) is R1 .LT. 0.0        ',
-     1     40, 20, 0, 1, I, 0, 1, DBLE (ATOLI), 0.0D0)
+ 620  MSG = 'SLSODE-  ATOL(I1) is R1 .LT. 0.0        '
+      CALL XERRWV (MSG, 40, 20, 0, 1, I, 0, 1, ATOLI, 0.0E0)
       GO TO 700
  621  EWTI = RWORK(LEWT+I-1)
-      CALL XERRWD('SLSODE-  EWT(I1) is R1 .LE. 0.0         ',
-     1     40, 21, 0, 1, I, 0, 1, DBLE (EWTI), 0.0D0)
+      MSG = 'SLSODE-  EWT(I1) is R1 .LE. 0.0         '
+      CALL XERRWV (MSG, 40, 21, 0, 1, I, 0, 1, EWTI, 0.0E0)
       GO TO 700
- 622  CALL XERRWD(
-     1   'SLSODE-  TOUT (=R1) too close to T(=R2) to start integration',
-     1     60, 22, 0, 0, 0, 0, 2, DBLE (TOUT), DBLE (T))
+ 622  CONTINUE
+      MSG='SLSODE-  TOUT (=R1) too close to T(=R2) to start integration'
+      CALL XERRWV (MSG, 60, 22, 0, 0, 0, 0, 2, TOUT, T)
       GO TO 700
- 623  CALL XERRWD(
-     1 'SLSODE-  ITASK = I1 and TOUT (=R1) behind TCUR - HU (= R2)  ',
-     1     60, 23, 0, 1, ITASK, 0, 2, DBLE (TOUT), DBLE (TP))
+ 623  CONTINUE
+      MSG='SLSODE-  ITASK = I1 and TOUT (=R1) behind TCUR - HU (= R2)  '
+      CALL XERRWV (MSG, 60, 23, 0, 1, ITASK, 0, 2, TOUT, TP)
       GO TO 700
- 624  CALL XERRWD(
-     1   'SLSODE-  ITASK = 4 OR 5 and TCRIT (=R1) behind TCUR (=R2)   ',
-     1    60, 24, 0, 0, 0, 0, 2, DBLE (TCRIT), DBLE (TN))
+ 624  CONTINUE
+      MSG='SLSODE-  ITASK = 4 OR 5 and TCRIT (=R1) behind TCUR (=R2)   '
+      CALL XERRWV (MSG, 60, 24, 0, 0, 0, 0, 2, TCRIT, TN)
       GO TO 700
- 625  CALL XERRWD(
-     1  'SLSODE-  ITASK = 4 or 5 and TCRIT (=R1) behind TOUT (=R2)   ',
-     1   60, 25, 0, 0, 0, 0, 2, DBLE (TCRIT), DBLE (TOUT))
+ 625  CONTINUE
+      MSG='SLSODE-  ITASK = 4 or 5 and TCRIT (=R1) behind TOUT (=R2)   '
+      CALL XERRWV (MSG, 60, 25, 0, 0, 0, 0, 2, TCRIT, TOUT)
       GO TO 700
- 626  CALL XERRWD('SLSODE-  At start of problem, too much accuracy   ',
-     1     50, 26, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD(
-     1   '      requested for precision of machine..  See TOLSF (=R1) ',
-     1    60, 26, 0, 0, 0, 0, 1, DBLE (TOLSF), 0.0D0)
+ 626  MSG = 'SLSODE-  At start of problem, too much accuracy   '
+      CALL XERRWV (MSG, 50, 26, 0, 0, 0, 0, 0, 0.0E0, 0.0E0)
+      MSG='      requested for precision of machine..  See TOLSF (=R1) '
+      CALL XERRWV (MSG, 60, 26, 0, 0, 0, 0, 1, TOLSF, 0.0E0)
       RWORK(14) = TOLSF
       GO TO 700
- 627  CALL XERRWD('SLSODE-  Trouble in SINTDY.  ITASK = I1, TOUT = R1',
-     1     50, 27, 0, 1, ITASK, 0, 1, DBLE (TOUT), 0.0D0)
+ 627  MSG = 'SLSODE-  Trouble in SINTDY.  ITASK = I1, TOUT = R1'
+      CALL XERRWV (MSG, 50, 27, 0, 1, ITASK, 0, 1, TOUT, 0.0E0)
 C
  700  ISTATE = -3
       RETURN
 C
- 800  CALL XERRWD('SLSODE-  Run aborted.. apparent infinite loop     ',
-     1     50, 303, 2, 0, 0, 0, 0, 0.0D0, 0.0D0)
+ 800  MSG = 'SLSODE-  Run aborted.. apparent infinite loop     '
+      CALL XERRWV (MSG, 50, 303, 2, 0, 0, 0, 0, 0.0E0, 0.0E0)
       RETURN
 C----------------------- END OF SUBROUTINE SLSODE ----------------------
       END
--- a/liboctave/external/odepack/solsy.f	Thu Nov 19 13:05:51 2020 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-      SUBROUTINE SOLSY (WM, IWM, X, TEM)
-CLLL. OPTIMIZE
-      INTEGER IWM
-      INTEGER ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
-     1   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, NYH,
-     2   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP
-      INTEGER ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
-     2   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
-      INTEGER I, MEBAND, ML, MU
-      DOUBLE PRECISION WM, X, TEM
-      DOUBLE PRECISION CONIT, CRATE, EL, ELCO, HOLD, RMAX, TESCO,
-     1   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND
-      DOUBLE PRECISION DI, HL0, PHL0, R
-      DIMENSION WM(*), IWM(*), X(*), TEM(*)
-      COMMON /LS0001/ CONIT, CRATE, EL(13), ELCO(13,12),
-     1   HOLD, RMAX, TESCO(3,12),
-     2   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND,
-     2   ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
-     3   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, NYH,
-     3   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP,
-     4   ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
-     5   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
-C-----------------------------------------------------------------------
-C THIS ROUTINE MANAGES THE SOLUTION OF THE LINEAR SYSTEM ARISING FROM
-C A CHORD ITERATION.  IT IS CALLED IF MITER .NE. 0.
-C IF MITER IS 1 OR 2, IT CALLS DGETRS TO ACCOMPLISH THIS.
-C IF MITER = 3 IT UPDATES THE COEFFICIENT H*EL0 IN THE DIAGONAL
-C MATRIX, AND THEN COMPUTES THE SOLUTION.
-C IF MITER IS 4 OR 5, IT CALLS DGBTRS.
-C COMMUNICATION WITH SOLSY USES THE FOLLOWING VARIABLES..
-C WM    = REAL WORK SPACE CONTAINING THE INVERSE DIAGONAL MATRIX IF
-C         MITER = 3 AND THE LU DECOMPOSITION OF THE MATRIX OTHERWISE.
-C         STORAGE OF MATRIX ELEMENTS STARTS AT WM(3).
-C         WM ALSO CONTAINS THE FOLLOWING MATRIX-RELATED DATA..
-C         WM(1) = SQRT(UROUND) (NOT USED HERE),
-C         WM(2) = HL0, THE PREVIOUS VALUE OF H*EL0, USED IF MITER = 3.
-C IWM   = INTEGER WORK SPACE CONTAINING PIVOT INFORMATION, STARTING AT
-C         IWM(21), IF MITER IS 1, 2, 4, OR 5.  IWM ALSO CONTAINS BAND
-C         PARAMETERS ML = IWM(1) AND MU = IWM(2) IF MITER IS 4 OR 5.
-C X     = THE RIGHT-HAND SIDE VECTOR ON INPUT, AND THE SOLUTION VECTOR
-C         ON OUTPUT, OF LENGTH N.
-C TEM   = VECTOR OF WORK SPACE OF LENGTH N, NOT USED IN THIS VERSION.
-C IERSL = OUTPUT FLAG (IN COMMON).  IERSL = 0 IF NO TROUBLE OCCURRED.
-C         IERSL = 1 IF A SINGULAR MATRIX AROSE WITH MITER = 3.
-C THIS ROUTINE ALSO USES THE COMMON VARIABLES EL0, H, MITER, AND N.
-C-----------------------------------------------------------------------
-      IERSL = 0
-      GO TO (100, 100, 300, 400, 400), MITER
- 100  CALL DGETRS ( 'N', N, 1, WM(3), N, IWM(21), X, N, INLPCK)
-      RETURN
-C
- 300  PHL0 = WM(2)
-      HL0 = H*EL0
-      WM(2) = HL0
-      IF (HL0 .EQ. PHL0) GO TO 330
-      R = HL0/PHL0
-      DO 320 I = 1,N
-        DI = 1.0D0 - R*(1.0D0 - 1.0D0/WM(I+2))
-        IF (DABS(DI) .EQ. 0.0D0) GO TO 390
- 320    WM(I+2) = 1.0D0/DI
- 330  DO 340 I = 1,N
- 340    X(I) = WM(I+2)*X(I)
-      RETURN
- 390  IERSL = 1
-      RETURN
-C
- 400  ML = IWM(1)
-      MU = IWM(2)
-      MEBAND = 2*ML + MU + 1
-      CALL DGBTRS ( 'N', N, ML, MU, 1, WM(3), MEBAND, IWM(21), X, N,
-     * INLPCK)
-      RETURN
-C----------------------- END OF SUBROUTINE SOLSY -----------------------
-      END
--- a/liboctave/external/odepack/ssolsy.f	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/external/odepack/ssolsy.f	Thu Nov 19 13:08:00 2020 -0800
@@ -61,6 +61,7 @@
      4   LYH, LEWT, LACOR, LSAVF, LWM, LIWM, METH, MITER,
      5   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
       INTEGER I, MEBAND, ML, MU
+      INTEGER INLPCK
       REAL DI, HL0, PHL0, R
 C
 C***FIRST EXECUTABLE STATEMENT  SSOLSY
--- a/liboctave/external/odepack/stode.f	Thu Nov 19 13:05:51 2020 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,487 +0,0 @@
-      SUBROUTINE STODE (NEQ, Y, YH, NYH, YH1, EWT, SAVF, ACOR,
-     1   WM, IWM, F, JAC, PJAC, SLVS, IERR)
-CLLL. OPTIMIZE
-      EXTERNAL F, JAC, PJAC, SLVS
-      INTEGER NEQ, NYH, IWM
-      INTEGER ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
-     1   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, CNYH,
-     2   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP
-      INTEGER ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
-     1   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
-      INTEGER I, I1, IREDO, IRET, J, JB, M, NCF, NEWQ
-      DOUBLE PRECISION Y, YH, YH1, EWT, SAVF, ACOR, WM
-      DOUBLE PRECISION CONIT, CRATE, EL, ELCO, HOLD, RMAX, TESCO,
-     2   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND
-      DOUBLE PRECISION DCON, DDN, DEL, DELP, DSM, DUP, EXDN, EXSM, EXUP,
-     1   R, RH, RHDN, RHSM, RHUP, TOLD, VNORM
-      DIMENSION NEQ(*), Y(*), YH(NYH,*), YH1(*), EWT(*), SAVF(*),
-     1   ACOR(*), WM(*), IWM(*)
-      COMMON /LS0001/ CONIT, CRATE, EL(13), ELCO(13,12),
-     1   HOLD, RMAX, TESCO(3,12),
-     2   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND,
-     2   ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
-     3   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, CNYH,
-     3   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP,
-     4   ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
-     5   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
-C-----------------------------------------------------------------------
-C STODE PERFORMS ONE STEP OF THE INTEGRATION OF AN INITIAL VALUE
-C PROBLEM FOR A SYSTEM OF ORDINARY DIFFERENTIAL EQUATIONS.
-C NOTE.. STODE IS INDEPENDENT OF THE VALUE OF THE ITERATION METHOD
-C INDICATOR MITER, WHEN THIS IS .NE. 0, AND HENCE IS INDEPENDENT
-C OF THE TYPE OF CHORD METHOD USED, OR THE JACOBIAN STRUCTURE.
-C COMMUNICATION WITH STODE IS DONE WITH THE FOLLOWING VARIABLES..
-C
-C NEQ    = INTEGER ARRAY CONTAINING PROBLEM SIZE IN NEQ(1), AND
-C          PASSED AS THE NEQ ARGUMENT IN ALL CALLS TO F AND JAC.
-C Y      = AN ARRAY OF LENGTH .GE. N USED AS THE Y ARGUMENT IN
-C          ALL CALLS TO F AND JAC.
-C YH     = AN NYH BY LMAX ARRAY CONTAINING THE DEPENDENT VARIABLES
-C          AND THEIR APPROXIMATE SCALED DERIVATIVES, WHERE
-C          LMAX = MAXORD + 1.  YH(I,J+1) CONTAINS THE APPROXIMATE
-C          J-TH DERIVATIVE OF Y(I), SCALED BY H**J/FACTORIAL(J)
-C          (J = 0,1,...,NQ).  ON ENTRY FOR THE FIRST STEP, THE FIRST
-C          TWO COLUMNS OF YH MUST BE SET FROM THE INITIAL VALUES.
-C NYH    = A CONSTANT INTEGER .GE. N, THE FIRST DIMENSION OF YH.
-C YH1    = A ONE-DIMENSIONAL ARRAY OCCUPYING THE SAME SPACE AS YH.
-C EWT    = AN ARRAY OF LENGTH N CONTAINING MULTIPLICATIVE WEIGHTS
-C          FOR LOCAL ERROR MEASUREMENTS.  LOCAL ERRORS IN Y(I) ARE
-C          COMPARED TO 1.0/EWT(I) IN VARIOUS ERROR TESTS.
-C SAVF   = AN ARRAY OF WORKING STORAGE, OF LENGTH N.
-C          ALSO USED FOR INPUT OF YH(*,MAXORD+2) WHEN JSTART = -1
-C          AND MAXORD .LT. THE CURRENT ORDER NQ.
-C ACOR   = A WORK ARRAY OF LENGTH N, USED FOR THE ACCUMULATED
-C          CORRECTIONS.  ON A SUCCESSFUL RETURN, ACOR(I) CONTAINS
-C          THE ESTIMATED ONE-STEP LOCAL ERROR IN Y(I).
-C WM,IWM = REAL AND INTEGER WORK ARRAYS ASSOCIATED WITH MATRIX
-C          OPERATIONS IN CHORD ITERATION (MITER .NE. 0).
-C PJAC   = NAME OF ROUTINE TO EVALUATE AND PREPROCESS JACOBIAN MATRIX
-C          AND P = I - H*EL0*JAC, IF A CHORD METHOD IS BEING USED.
-C SLVS   = NAME OF ROUTINE TO SOLVE LINEAR SYSTEM IN CHORD ITERATION.
-C CCMAX  = MAXIMUM RELATIVE CHANGE IN H*EL0 BEFORE PJAC IS CALLED.
-C H      = THE STEP SIZE TO BE ATTEMPTED ON THE NEXT STEP.
-C          H IS ALTERED BY THE ERROR CONTROL ALGORITHM DURING THE
-C          PROBLEM.  H CAN BE EITHER POSITIVE OR NEGATIVE, BUT ITS
-C          SIGN MUST REMAIN CONSTANT THROUGHOUT THE PROBLEM.
-C HMIN   = THE MINIMUM ABSOLUTE VALUE OF THE STEP SIZE H TO BE USED.
-C HMXI   = INVERSE OF THE MAXIMUM ABSOLUTE VALUE OF H TO BE USED.
-C          HMXI = 0.0 IS ALLOWED AND CORRESPONDS TO AN INFINITE HMAX.
-C          HMIN AND HMXI MAY BE CHANGED AT ANY TIME, BUT WILL NOT
-C          TAKE EFFECT UNTIL THE NEXT CHANGE OF H IS CONSIDERED.
-C TN     = THE INDEPENDENT VARIABLE. TN IS UPDATED ON EACH STEP TAKEN.
-C JSTART = AN INTEGER USED FOR INPUT ONLY, WITH THE FOLLOWING
-C          VALUES AND MEANINGS..
-C               0  PERFORM THE FIRST STEP.
-C           .GT.0  TAKE A NEW STEP CONTINUING FROM THE LAST.
-C              -1  TAKE THE NEXT STEP WITH A NEW VALUE OF H, MAXORD,
-C                    N, METH, MITER, AND/OR MATRIX PARAMETERS.
-C              -2  TAKE THE NEXT STEP WITH A NEW VALUE OF H,
-C                    BUT WITH OTHER INPUTS UNCHANGED.
-C          ON RETURN, JSTART IS SET TO 1 TO FACILITATE CONTINUATION.
-C KFLAG  = A COMPLETION CODE WITH THE FOLLOWING MEANINGS..
-C               0  THE STEP WAS SUCCESFUL.
-C              -1  THE REQUESTED ERROR COULD NOT BE ACHIEVED.
-C              -2  CORRECTOR CONVERGENCE COULD NOT BE ACHIEVED.
-C              -3  FATAL ERROR IN PJAC OR SLVS.
-C          A RETURN WITH KFLAG = -1 OR -2 MEANS EITHER
-C          ABS(H) = HMIN OR 10 CONSECUTIVE FAILURES OCCURRED.
-C          ON A RETURN WITH KFLAG NEGATIVE, THE VALUES OF TN AND
-C          THE YH ARRAY ARE AS OF THE BEGINNING OF THE LAST
-C          STEP, AND H IS THE LAST STEP SIZE ATTEMPTED.
-C MAXORD = THE MAXIMUM ORDER OF INTEGRATION METHOD TO BE ALLOWED.
-C MAXCOR = THE MAXIMUM NUMBER OF CORRECTOR ITERATIONS ALLOWED.
-C MSBP   = MAXIMUM NUMBER OF STEPS BETWEEN PJAC CALLS (MITER .GT. 0).
-C MXNCF  = MAXIMUM NUMBER OF CONVERGENCE FAILURES ALLOWED.
-C METH/MITER = THE METHOD FLAGS.  SEE DESCRIPTION IN DRIVER.
-C N      = THE NUMBER OF FIRST-ORDER DIFFERENTIAL EQUATIONS.
-C IERR   = ERROR FLAG FROM USER-SUPPLIED FUNCTION
-C-----------------------------------------------------------------------
-      KFLAG = 0
-      TOLD = TN
-      NCF = 0
-      IERPJ = 0
-      IERSL = 0
-      JCUR = 0
-      ICF = 0
-      DELP = 0.0D0
-      IF (JSTART .GT. 0) GO TO 200
-      IF (JSTART .EQ. -1) GO TO 100
-      IF (JSTART .EQ. -2) GO TO 160
-C-----------------------------------------------------------------------
-C ON THE FIRST CALL, THE ORDER IS SET TO 1, AND OTHER VARIABLES ARE
-C INITIALIZED.  RMAX IS THE MAXIMUM RATIO BY WHICH H CAN BE INCREASED
-C IN A SINGLE STEP.  IT IS INITIALLY 1.E4 TO COMPENSATE FOR THE SMALL
-C INITIAL H, BUT THEN IS NORMALLY EQUAL TO 10.  IF A FAILURE
-C OCCURS (IN CORRECTOR CONVERGENCE OR ERROR TEST), RMAX IS SET AT 2
-C FOR THE NEXT INCREASE.
-C-----------------------------------------------------------------------
-      LMAX = MAXORD + 1
-      NQ = 1
-      L = 2
-      IALTH = 2
-      RMAX = 10000.0D0
-      RC = 0.0D0
-      EL0 = 1.0D0
-      CRATE = 0.7D0
-      HOLD = H
-      MEO = METH
-      NSLP = 0
-      IPUP = MITER
-      IRET = 3
-      GO TO 140
-C-----------------------------------------------------------------------
-C THE FOLLOWING BLOCK HANDLES PRELIMINARIES NEEDED WHEN JSTART = -1.
-C IPUP IS SET TO MITER TO FORCE A MATRIX UPDATE.
-C IF AN ORDER INCREASE IS ABOUT TO BE CONSIDERED (IALTH = 1),
-C IALTH IS RESET TO 2 TO POSTPONE CONSIDERATION ONE MORE STEP.
-C IF THE CALLER HAS CHANGED METH, CFODE IS CALLED TO RESET
-C THE COEFFICIENTS OF THE METHOD.
-C IF THE CALLER HAS CHANGED MAXORD TO A VALUE LESS THAN THE CURRENT
-C ORDER NQ, NQ IS REDUCED TO MAXORD, AND A NEW H CHOSEN ACCORDINGLY.
-C IF H IS TO BE CHANGED, YH MUST BE RESCALED.
-C IF H OR METH IS BEING CHANGED, IALTH IS RESET TO L = NQ + 1
-C TO PREVENT FURTHER CHANGES IN H FOR THAT MANY STEPS.
-C-----------------------------------------------------------------------
- 100  IPUP = MITER
-      LMAX = MAXORD + 1
-      IF (IALTH .EQ. 1) IALTH = 2
-      IF (METH .EQ. MEO) GO TO 110
-      CALL CFODE (METH, ELCO, TESCO)
-      MEO = METH
-      IF (NQ .GT. MAXORD) GO TO 120
-      IALTH = L
-      IRET = 1
-      GO TO 150
- 110  IF (NQ .LE. MAXORD) GO TO 160
- 120  NQ = MAXORD
-      L = LMAX
-      DO 125 I = 1,L
- 125    EL(I) = ELCO(I,NQ)
-      NQNYH = NQ*NYH
-      RC = RC*EL(1)/EL0
-      EL0 = EL(1)
-      CONIT = 0.5D0/DBLE(NQ+2)
-      DDN = VNORM (N, SAVF, EWT)/TESCO(1,L)
-      EXDN = 1.0D0/DBLE(L)
-      RHDN = 1.0D0/(1.3D0*DDN**EXDN + 0.0000013D0)
-      RH = DMIN1(RHDN,1.0D0)
-      IREDO = 3
-      IF (H .EQ. HOLD) GO TO 170
-      RH = DMIN1(RH,DABS(H/HOLD))
-      H = HOLD
-      GO TO 175
-C-----------------------------------------------------------------------
-C CFODE IS CALLED TO GET ALL THE INTEGRATION COEFFICIENTS FOR THE
-C CURRENT METH.  THEN THE EL VECTOR AND RELATED CONSTANTS ARE RESET
-C WHENEVER THE ORDER NQ IS CHANGED, OR AT THE START OF THE PROBLEM.
-C-----------------------------------------------------------------------
- 140  CALL CFODE (METH, ELCO, TESCO)
- 150  DO 155 I = 1,L
- 155    EL(I) = ELCO(I,NQ)
-      NQNYH = NQ*NYH
-      RC = RC*EL(1)/EL0
-      EL0 = EL(1)
-      CONIT = 0.5D0/DBLE(NQ+2)
-      GO TO (160, 170, 200), IRET
-C-----------------------------------------------------------------------
-C IF H IS BEING CHANGED, THE H RATIO RH IS CHECKED AGAINST
-C RMAX, HMIN, AND HMXI, AND THE YH ARRAY RESCALED.  IALTH IS SET TO
-C L = NQ + 1 TO PREVENT A CHANGE OF H FOR THAT MANY STEPS, UNLESS
-C FORCED BY A CONVERGENCE OR ERROR TEST FAILURE.
-C-----------------------------------------------------------------------
- 160  IF (H .EQ. HOLD) GO TO 200
-      RH = H/HOLD
-      H = HOLD
-      IREDO = 3
-      GO TO 175
- 170  RH = DMAX1(RH,HMIN/DABS(H))
- 175  RH = DMIN1(RH,RMAX)
-      RH = RH/DMAX1(1.0D0,DABS(H)*HMXI*RH)
-      R = 1.0D0
-      DO 180 J = 2,L
-        R = R*RH
-        DO 180 I = 1,N
- 180      YH(I,J) = YH(I,J)*R
-      H = H*RH
-      RC = RC*RH
-      IALTH = L
-      IF (IREDO .EQ. 0) GO TO 690
-C-----------------------------------------------------------------------
-C THIS SECTION COMPUTES THE PREDICTED VALUES BY EFFECTIVELY
-C MULTIPLYING THE YH ARRAY BY THE PASCAL TRIANGLE MATRIX.
-C RC IS THE RATIO OF NEW TO OLD VALUES OF THE COEFFICIENT  H*EL(1).
-C WHEN RC DIFFERS FROM 1 BY MORE THAN CCMAX, IPUP IS SET TO MITER
-C TO FORCE PJAC TO BE CALLED, IF A JACOBIAN IS INVOLVED.
-C IN ANY CASE, PJAC IS CALLED AT LEAST EVERY MSBP STEPS.
-C-----------------------------------------------------------------------
- 200  IF (DABS(RC-1.0D0) .GT. CCMAX) IPUP = MITER
-      IF (NST .GE. NSLP+MSBP) IPUP = MITER
-      TN = TN + H
-      I1 = NQNYH + 1
-      DO 215 JB = 1,NQ
-        I1 = I1 - NYH
-CDIR$ IVDEP
-        DO 210 I = I1,NQNYH
- 210      YH1(I) = YH1(I) + YH1(I+NYH)
- 215    CONTINUE
-C-----------------------------------------------------------------------
-C UP TO MAXCOR CORRECTOR ITERATIONS ARE TAKEN.  A CONVERGENCE TEST IS
-C MADE ON THE R.M.S. NORM OF EACH CORRECTION, WEIGHTED BY THE ERROR
-C WEIGHT VECTOR EWT.  THE SUM OF THE CORRECTIONS IS ACCUMULATED IN THE
-C VECTOR ACOR(I).  THE YH ARRAY IS NOT ALTERED IN THE CORRECTOR LOOP.
-C-----------------------------------------------------------------------
- 220  M = 0
-      DO 230 I = 1,N
- 230    Y(I) = YH(I,1)
-      IERR = 0
-      CALL F (NEQ, TN, Y, SAVF, IERR)
-      IF (IERR .LT. 0) RETURN
-      NFE = NFE + 1
-      IF (IPUP .LE. 0) GO TO 250
-C-----------------------------------------------------------------------
-C IF INDICATED, THE MATRIX P = I - H*EL(1)*J IS REEVALUATED AND
-C PREPROCESSED BEFORE STARTING THE CORRECTOR ITERATION.  IPUP IS SET
-C TO 0 AS AN INDICATOR THAT THIS HAS BEEN DONE.
-C-----------------------------------------------------------------------
-      IERR = 0
-      CALL PJAC (NEQ, Y, YH, NYH, EWT, ACOR, SAVF, WM, IWM, F, JAC,
-     1   IERR)
-      IF (IERR .LT. 0) RETURN
-      IPUP = 0
-      RC = 1.0D0
-      NSLP = NST
-      CRATE = 0.7D0
-      IF (IERPJ .NE. 0) GO TO 430
- 250  DO 260 I = 1,N
- 260    ACOR(I) = 0.0D0
- 270  IF (MITER .NE. 0) GO TO 350
-C-----------------------------------------------------------------------
-C IN THE CASE OF FUNCTIONAL ITERATION, UPDATE Y DIRECTLY FROM
-C THE RESULT OF THE LAST FUNCTION EVALUATION.
-C-----------------------------------------------------------------------
-      DO 290 I = 1,N
-        SAVF(I) = H*SAVF(I) - YH(I,2)
- 290    Y(I) = SAVF(I) - ACOR(I)
-      DEL = VNORM (N, Y, EWT)
-      DO 300 I = 1,N
-        Y(I) = YH(I,1) + EL(1)*SAVF(I)
- 300    ACOR(I) = SAVF(I)
-      GO TO 400
-C-----------------------------------------------------------------------
-C IN THE CASE OF THE CHORD METHOD, COMPUTE THE CORRECTOR ERROR,
-C AND SOLVE THE LINEAR SYSTEM WITH THAT AS RIGHT-HAND SIDE AND
-C P AS COEFFICIENT MATRIX.
-C-----------------------------------------------------------------------
- 350  DO 360 I = 1,N
- 360    Y(I) = H*SAVF(I) - (YH(I,2) + ACOR(I))
-      CALL SLVS (WM, IWM, Y, SAVF)
-      IF (IERSL .LT. 0) GO TO 430
-      IF (IERSL .GT. 0) GO TO 410
-      DEL = VNORM (N, Y, EWT)
-      DO 380 I = 1,N
-        ACOR(I) = ACOR(I) + Y(I)
- 380    Y(I) = YH(I,1) + EL(1)*ACOR(I)
-C-----------------------------------------------------------------------
-C TEST FOR CONVERGENCE.  IF M.GT.0, AN ESTIMATE OF THE CONVERGENCE
-C RATE CONSTANT IS STORED IN CRATE, AND THIS IS USED IN THE TEST.
-C-----------------------------------------------------------------------
- 400  IF (M .NE. 0) CRATE = DMAX1(0.2D0*CRATE,DEL/DELP)
-      DCON = DEL*DMIN1(1.0D0,1.5D0*CRATE)/(TESCO(2,NQ)*CONIT)
-      IF (DCON .LE. 1.0D0) GO TO 450
-      M = M + 1
-      IF (M .EQ. MAXCOR) GO TO 410
-      IF (M .GE. 2 .AND. DEL .GT. 2.0D0*DELP) GO TO 410
-      DELP = DEL
-      IERR = 0
-      CALL F (NEQ, TN, Y, SAVF, IERR)
-      IF (IERR .LT. 0) RETURN
-      NFE = NFE + 1
-      GO TO 270
-C-----------------------------------------------------------------------
-C THE CORRECTOR ITERATION FAILED TO CONVERGE.
-C IF MITER .NE. 0 AND THE JACOBIAN IS OUT OF DATE, PJAC IS CALLED FOR
-C THE NEXT TRY.  OTHERWISE THE YH ARRAY IS RETRACTED TO ITS VALUES
-C BEFORE PREDICTION, AND H IS REDUCED, IF POSSIBLE.  IF H CANNOT BE
-C REDUCED OR MXNCF FAILURES HAVE OCCURRED, EXIT WITH KFLAG = -2.
-C-----------------------------------------------------------------------
- 410  IF (MITER .EQ. 0 .OR. JCUR .EQ. 1) GO TO 430
-      ICF = 1
-      IPUP = MITER
-      GO TO 220
- 430  ICF = 2
-      NCF = NCF + 1
-      RMAX = 2.0D0
-      TN = TOLD
-      I1 = NQNYH + 1
-      DO 445 JB = 1,NQ
-        I1 = I1 - NYH
-CDIR$ IVDEP
-        DO 440 I = I1,NQNYH
- 440      YH1(I) = YH1(I) - YH1(I+NYH)
- 445    CONTINUE
-      IF (IERPJ .LT. 0 .OR. IERSL .LT. 0) GO TO 680
-      IF (DABS(H) .LE. HMIN*1.00001D0) GO TO 670
-      IF (NCF .EQ. MXNCF) GO TO 670
-      RH = 0.25D0
-      IPUP = MITER
-      IREDO = 1
-      GO TO 170
-C-----------------------------------------------------------------------
-C THE CORRECTOR HAS CONVERGED.  JCUR IS SET TO 0
-C TO SIGNAL THAT THE JACOBIAN INVOLVED MAY NEED UPDATING LATER.
-C THE LOCAL ERROR TEST IS MADE AND CONTROL PASSES TO STATEMENT 500
-C IF IT FAILS.
-C-----------------------------------------------------------------------
- 450  JCUR = 0
-      IF (M .EQ. 0) DSM = DEL/TESCO(2,NQ)
-      IF (M .GT. 0) DSM = VNORM (N, ACOR, EWT)/TESCO(2,NQ)
-      IF (DSM .GT. 1.0D0) GO TO 500
-C-----------------------------------------------------------------------
-C AFTER A SUCCESSFUL STEP, UPDATE THE YH ARRAY.
-C CONSIDER CHANGING H IF IALTH = 1.  OTHERWISE DECREASE IALTH BY 1.
-C IF IALTH IS THEN 1 AND NQ .LT. MAXORD, THEN ACOR IS SAVED FOR
-C USE IN A POSSIBLE ORDER INCREASE ON THE NEXT STEP.
-C IF A CHANGE IN H IS CONSIDERED, AN INCREASE OR DECREASE IN ORDER
-C BY ONE IS CONSIDERED ALSO.  A CHANGE IN H IS MADE ONLY IF IT IS BY A
-C FACTOR OF AT LEAST 1.1.  IF NOT, IALTH IS SET TO 3 TO PREVENT
-C TESTING FOR THAT MANY STEPS.
-C-----------------------------------------------------------------------
-      KFLAG = 0
-      IREDO = 0
-      NST = NST + 1
-      HU = H
-      NQU = NQ
-      DO 470 J = 1,L
-        DO 470 I = 1,N
- 470      YH(I,J) = YH(I,J) + EL(J)*ACOR(I)
-      IALTH = IALTH - 1
-      IF (IALTH .EQ. 0) GO TO 520
-      IF (IALTH .GT. 1) GO TO 700
-      IF (L .EQ. LMAX) GO TO 700
-      DO 490 I = 1,N
- 490    YH(I,LMAX) = ACOR(I)
-      GO TO 700
-C-----------------------------------------------------------------------
-C THE ERROR TEST FAILED.  KFLAG KEEPS TRACK OF MULTIPLE FAILURES.
-C RESTORE TN AND THE YH ARRAY TO THEIR PREVIOUS VALUES, AND PREPARE
-C TO TRY THE STEP AGAIN.  COMPUTE THE OPTIMUM STEP SIZE FOR THIS OR
-C ONE LOWER ORDER.  AFTER 2 OR MORE FAILURES, H IS FORCED TO DECREASE
-C BY A FACTOR OF 0.2 OR LESS.
-C-----------------------------------------------------------------------
- 500  KFLAG = KFLAG - 1
-      TN = TOLD
-      I1 = NQNYH + 1
-      DO 515 JB = 1,NQ
-        I1 = I1 - NYH
-CDIR$ IVDEP
-        DO 510 I = I1,NQNYH
- 510      YH1(I) = YH1(I) - YH1(I+NYH)
- 515    CONTINUE
-      RMAX = 2.0D0
-      IF (DABS(H) .LE. HMIN*1.00001D0) GO TO 660
-      IF (KFLAG .LE. -3) GO TO 640
-      IREDO = 2
-      RHUP = 0.0D0
-      GO TO 540
-C-----------------------------------------------------------------------
-C REGARDLESS OF THE SUCCESS OR FAILURE OF THE STEP, FACTORS
-C RHDN, RHSM, AND RHUP ARE COMPUTED, BY WHICH H COULD BE MULTIPLIED
-C AT ORDER NQ - 1, ORDER NQ, OR ORDER NQ + 1, RESPECTIVELY.
-C IN THE CASE OF FAILURE, RHUP = 0.0 TO AVOID AN ORDER INCREASE.
-C THE LARGEST OF THESE IS DETERMINED AND THE NEW ORDER CHOSEN
-C ACCORDINGLY.  IF THE ORDER IS TO BE INCREASED, WE COMPUTE ONE
-C ADDITIONAL SCALED DERIVATIVE.
-C-----------------------------------------------------------------------
- 520  RHUP = 0.0D0
-      IF (L .EQ. LMAX) GO TO 540
-      DO 530 I = 1,N
- 530    SAVF(I) = ACOR(I) - YH(I,LMAX)
-      DUP = VNORM (N, SAVF, EWT)/TESCO(3,NQ)
-      EXUP = 1.0D0/DBLE(L+1)
-      RHUP = 1.0D0/(1.4D0*DUP**EXUP + 0.0000014D0)
- 540  EXSM = 1.0D0/DBLE(L)
-      RHSM = 1.0D0/(1.2D0*DSM**EXSM + 0.0000012D0)
-      RHDN = 0.0D0
-      IF (NQ .EQ. 1) GO TO 560
-      DDN = VNORM (N, YH(1,L), EWT)/TESCO(1,NQ)
-      EXDN = 1.0D0/DBLE(NQ)
-      RHDN = 1.0D0/(1.3D0*DDN**EXDN + 0.0000013D0)
- 560  IF (RHSM .GE. RHUP) GO TO 570
-      IF (RHUP .GT. RHDN) GO TO 590
-      GO TO 580
- 570  IF (RHSM .LT. RHDN) GO TO 580
-      NEWQ = NQ
-      RH = RHSM
-      GO TO 620
- 580  NEWQ = NQ - 1
-      RH = RHDN
-      IF (KFLAG .LT. 0 .AND. RH .GT. 1.0D0) RH = 1.0D0
-      GO TO 620
- 590  NEWQ = L
-      RH = RHUP
-      IF (RH .LT. 1.1D0) GO TO 610
-      R = EL(L)/DBLE(L)
-      DO 600 I = 1,N
- 600    YH(I,NEWQ+1) = ACOR(I)*R
-      GO TO 630
- 610  IALTH = 3
-      GO TO 700
- 620  IF ((KFLAG .EQ. 0) .AND. (RH .LT. 1.1D0)) GO TO 610
-      IF (KFLAG .LE. -2) RH = DMIN1(RH,0.2D0)
-C-----------------------------------------------------------------------
-C IF THERE IS A CHANGE OF ORDER, RESET NQ, L, AND THE COEFFICIENTS.
-C IN ANY CASE H IS RESET ACCORDING TO RH AND THE YH ARRAY IS RESCALED.
-C THEN EXIT FROM 690 IF THE STEP WAS OK, OR REDO THE STEP OTHERWISE.
-C-----------------------------------------------------------------------
-      IF (NEWQ .EQ. NQ) GO TO 170
- 630  NQ = NEWQ
-      L = NQ + 1
-      IRET = 2
-      GO TO 150
-C-----------------------------------------------------------------------
-C CONTROL REACHES THIS SECTION IF 3 OR MORE FAILURES HAVE OCCURRED.
-C IF 10 FAILURES HAVE OCCURRED, EXIT WITH KFLAG = -1.
-C IT IS ASSUMED THAT THE DERIVATIVES THAT HAVE ACCUMULATED IN THE
-C YH ARRAY HAVE ERRORS OF THE WRONG ORDER.  HENCE THE FIRST
-C DERIVATIVE IS RECOMPUTED, AND THE ORDER IS SET TO 1.  THEN
-C H IS REDUCED BY A FACTOR OF 10, AND THE STEP IS RETRIED,
-C UNTIL IT SUCCEEDS OR H REACHES HMIN.
-C-----------------------------------------------------------------------
- 640  IF (KFLAG .EQ. -10) GO TO 660
-      RH = 0.1D0
-      RH = DMAX1(HMIN/DABS(H),RH)
-      H = H*RH
-      DO 645 I = 1,N
- 645    Y(I) = YH(I,1)
-      IERR = 0
-      CALL F (NEQ, TN, Y, SAVF, IERR)
-      IF (IERR .LT. 0) RETURN
-      NFE = NFE + 1
-      DO 650 I = 1,N
- 650    YH(I,2) = H*SAVF(I)
-      IPUP = MITER
-      IALTH = 5
-      IF (NQ .EQ. 1) GO TO 200
-      NQ = 1
-      L = 2
-      IRET = 3
-      GO TO 150
-C-----------------------------------------------------------------------
-C ALL RETURNS ARE MADE THROUGH THIS SECTION.  H IS SAVED IN HOLD
-C TO ALLOW THE CALLER TO CHANGE H ON THE NEXT STEP.
-C-----------------------------------------------------------------------
- 660  KFLAG = -1
-      GO TO 720
- 670  KFLAG = -2
-      GO TO 720
- 680  KFLAG = -3
-      GO TO 720
- 690  RMAX = 10.0D0
- 700  R = 1.0D0/TESCO(2,NQU)
-      DO 710 I = 1,N
- 710    ACOR(I) = ACOR(I)*R
- 720  HOLD = H
-      JSTART = 1
-      RETURN
-C----------------------- END OF SUBROUTINE STODE -----------------------
-      END
--- a/liboctave/external/odepack/vnorm.f	Thu Nov 19 13:05:51 2020 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,18 +0,0 @@
-      DOUBLE PRECISION FUNCTION VNORM (N, V, W)
-CLLL. OPTIMIZE
-C-----------------------------------------------------------------------
-C THIS FUNCTION ROUTINE COMPUTES THE WEIGHTED ROOT-MEAN-SQUARE NORM
-C OF THE VECTOR OF LENGTH N CONTAINED IN THE ARRAY V, WITH WEIGHTS
-C CONTAINED IN THE ARRAY W OF LENGTH N..
-C   VNORM = SQRT( (1/N) * SUM( V(I)*W(I) )**2 )
-C-----------------------------------------------------------------------
-      INTEGER N,   I
-      DOUBLE PRECISION V, W,   SUM
-      DIMENSION V(N), W(N)
-      SUM = 0.0D0
-      DO 10 I = 1,N
- 10     SUM = SUM + (V(I)*W(I))**2
-      VNORM = DSQRT(SUM/DBLE(N))
-      RETURN
-C----------------------- END OF FUNCTION VNORM -------------------------
-      END
--- a/liboctave/external/slatec-err/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/external/slatec-err/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -8,6 +8,7 @@
   %reldir%/xermsg.f \
   %reldir%/xerprn.f \
   %reldir%/xerrwd.f \
+  %reldir%/xerrwv.f \
   %reldir%/xersve.f \
   %reldir%/xgetf.f \
   %reldir%/xgetua.f \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/external/slatec-err/xerrwv.f	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,96 @@
+*DECK XERRWV
+      SUBROUTINE XERRWV (MSG, NMES, NERR, LEVEL, NI, I1, I2, NR, R1, R2)
+C***BEGIN PROLOGUE  XERRWV
+C***SUBSIDIARY
+C***PURPOSE  Write error message with values.
+C***CATEGORY  R3C
+C***TYPE      SINGLE PRECISION (XERRWV-S, XERRWD-D)
+C***AUTHOR  Hindmarsh, Alan C., (LLNL)
+C***DESCRIPTION
+C
+C  Subroutines XERRWV, XSETF, XSETUN, and the function routine IXSAV,
+C  as given here, constitute a simplified version of the SLATEC error
+C  handling package.
+C
+C  All arguments are input arguments.
+C
+C  MSG    = The message (character array).
+C  NMES   = The length of MSG (number of characters).
+C  NERR   = The error number (not used).
+C  LEVEL  = The error level..
+C           0 or 1 means recoverable (control returns to caller).
+C           2 means fatal (run is aborted--see note below).
+C  NI     = Number of integers (0, 1, or 2) to be printed with message.
+C  I1,I2  = Integers to be printed, depending on NI.
+C  NR     = Number of reals (0, 1, or 2) to be printed with message.
+C  R1,R2  = Reals to be printed, depending on NR.
+C
+C  Note..  this routine is machine-dependent and specialized for use
+C  in limited context, in the following ways..
+C  1. The argument MSG is assumed to be of type CHARACTER, and
+C     the message is printed with a format of (1X,A).
+C  2. The message is assumed to take only one line.
+C     Multi-line messages are generated by repeated calls.
+C  3. If LEVEL = 2, control passes to the statement   STOP
+C     to abort the run.  This statement may be machine-dependent.
+C  4. R1 and R2 are assumed to be in single precision and are printed
+C     in E21.13 format.
+C
+C***ROUTINES CALLED  IXSAV
+C***REVISION HISTORY  (YYMMDD)
+C   791129  DATE WRITTEN
+C   890413  Heavily revised, with Common eliminated. (ACH, PNB)
+C   921118  Replaced MFLGSV/LUNSAV by IXSAV. (ACH)
+C   930329  Modified prologue to SLATEC format. (FNF)
+C   930407  Changed MSG from CHARACTER*1 array to variable. (FNF)
+C   930922  Minor cosmetic change. (FNF)
+C***END PROLOGUE  XERRWV
+C
+C*Internal Notes:
+C
+C For a different default logical unit number, IXSAV (or a subsidiary
+C routine that it calls) will need to be modified.
+C For a different run-abort command, change the statement following
+C statement 100 at the end.
+C-----------------------------------------------------------------------
+C Subroutines called by XERRWV.. None
+C Function routine called by XERRWV.. IXSAV
+C-----------------------------------------------------------------------
+C**End
+C
+C  Declare arguments.
+C
+      REAL R1, R2
+      INTEGER NMES, NERR, LEVEL, NI, I1, I2, NR
+      CHARACTER*(*) MSG
+C
+C  Declare local variables.
+C
+      INTEGER LUNIT, IXSAV, MESFLG
+C
+C  Get logical unit number and message print flag.
+C
+C***FIRST EXECUTABLE STATEMENT  XERRWV
+      LUNIT = IXSAV (1, 0, .FALSE.)
+      MESFLG = IXSAV (2, 0, .FALSE.)
+      IF (MESFLG .EQ. 0) GO TO 100
+C
+C  Write the message.
+C
+      WRITE (LUNIT,10)  MSG(1:NMES)
+ 10   FORMAT(1X,A)
+      IF (NI .EQ. 1) WRITE (LUNIT, 20) I1
+ 20   FORMAT(6X,'In above message,  I1 =',I10)
+      IF (NI .EQ. 2) WRITE (LUNIT, 30) I1,I2
+ 30   FORMAT(6X,'In above message,  I1 =',I10,3X,'I2 =',I10)
+      IF (NR .EQ. 1) WRITE (LUNIT, 40) R1
+ 40   FORMAT(6X,'In above message,  R1 =',E21.13)
+      IF (NR .EQ. 2) WRITE (LUNIT, 50) R1,R2
+ 50   FORMAT(6X,'In above,  R1 =',E21.13,3X,'R2 =',E21.13)
+C
+C  Abort the run if LEVEL = 2.
+C
+ 100  IF (LEVEL .NE. 2) RETURN
+      CALL XSTOPX (' ')
+C----------------------- End of Subroutine XERRWV ----------------------
+      END
--- a/liboctave/numeric/CollocWt.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/numeric/CollocWt.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -415,7 +415,6 @@
   if (wid <= 0.0)
     {
       error ("CollocWt: width less than or equal to zero");
-      return;
     }
 
   octave_idx_type nt = n + inc_left + inc_right;
--- a/liboctave/numeric/lo-lapack-proto.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/numeric/lo-lapack-proto.h	Thu Nov 19 13:08:00 2020 -0800
@@ -1640,6 +1640,32 @@
                              const F77_INT& LIWORK,
                              F77_INT& INFO);
 
+  F77_RET_T
+  F77_FUNC (ztgsen, ZTGSEN) (const F77_INT& IJOB,
+                             const F77_LOGICAL& WANTQ,
+                             const F77_LOGICAL& WANTZ,
+                             const F77_LOGICAL *SELECT,
+                             const F77_INT& N,
+                             F77_DBLE_CMPLX *A,
+                             const F77_INT& LDA,
+                             F77_DBLE_CMPLX *B,
+                             const F77_INT& LDB,
+                             F77_DBLE_CMPLX *ALPHA,
+                             F77_DBLE_CMPLX *BETA,
+                             F77_DBLE_CMPLX *Q,
+                             const F77_INT& LDQ,
+                             F77_DBLE_CMPLX *Z,
+                             const F77_INT& LDZ,
+                             F77_INT& M,
+                             F77_DBLE& PL,
+                             F77_DBLE& PR,
+                             F77_DBLE *DIF,
+                             F77_DBLE_CMPLX *WORK,
+                             const F77_INT& LWORK,
+                             F77_INT *IWORK,
+                             const F77_INT& LIWORK,
+                             F77_INT& INFO);
+
   // TRCON
 
   F77_RET_T
--- a/liboctave/numeric/lo-mappers.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/numeric/lo-mappers.h	Thu Nov 19 13:08:00 2020 -0800
@@ -203,6 +203,13 @@
     inline bool isinf (double x) { return std::isinf (x); }
     inline bool isinf (float x) { return std::isinf (x); }
 
+    template <typename T>
+    bool
+    isinf (const octave_int<T>&)
+    {
+      return false;
+    }
+
     // FIXME: Do we need isinf overload for complex?
     template <typename T>
     bool
--- a/liboctave/numeric/randmtzig.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/numeric/randmtzig.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -162,7 +162,9 @@
 #include <cstdio>
 
 #include <algorithm>
+#include <random>
 
+#include "oct-syscalls.h"
 #include "oct-time.h"
 #include "randmtzig.h"
 
@@ -259,36 +261,50 @@
     uint32_t entropy[MT_N];
     int n = 0;
 
-    /* Look for entropy in /dev/urandom */
-    FILE *urandom = std::fopen ("/dev/urandom", "rb");
-    if (urandom)
-      {
-        while (n < MT_N)
-          {
-            unsigned char word[4];
-            if (std::fread (word, 4, 1, urandom) != 1)
-              break;
-            entropy[n++] = word[0] + (word[1]<<8) + (word[2]<<16)
-                           + (static_cast<uint32_t> (word[3])<<24);
-          }
-        std::fclose (urandom);
-      }
-
-    /* If there isn't enough entropy, gather some from various sources */
+    // Gather some entropy from various sources
 
     sys::time now;
 
+    // Current time in seconds
     if (n < MT_N)
-      entropy[n++] = now.unix_time (); /* Current time in seconds */
+      entropy[n++] = now.unix_time ();
+
+    // CPU time used (usec)
+    if (n < MT_N)
+      entropy[n++] = clock ();
+
+    // Fractional part of current time
+    if (n < MT_N)
+      entropy[n++] = now.usec ();
+
+    // Include the PID to make sure that several processes reaching here at the
+    // same time use different random numbers.
+    if (n < MT_N)
+      entropy[n++] = sys::getpid ();
 
     if (n < MT_N)
-      entropy[n++] = clock ();    /* CPU time used (usec) */
+      {
+        try
+          {
+            // The standard doesn't *guarantee* that random_device provides
+            // non-deterministic random numbers. So add entropy from this
+            // source last to make sure we gathered at least some entropy from
+            // the earlier sources.
+            std::random_device rd;
+            std::uniform_int_distribution<uint32_t> dist;
+            // Add 1024 bit of "true" entropy
+            int n_max = std::min (n + 32, MT_N);
+            while (n < n_max)
+              entropy[n++] = dist (rd);
+          }
+        catch (std::exception& e)
+          {
+            // Just ignore any exception and skip that source of entropy.
+          }
+      }
 
-    if (n < MT_N)
-      entropy[n++] = now.usec ();   /* Fractional part of current time */
-
-    /* Send all the entropy into the initial state vector */
-    init_mersenne_twister (entropy,n);
+    // Send all the entropy into the initial state vector
+    init_mersenne_twister (entropy, n);
   }
 
   void set_mersenne_twister_state (const uint32_t *save)
--- a/liboctave/system/dir-ops.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/system/dir-ops.h	Thu Nov 19 13:08:00 2020 -0800
@@ -44,7 +44,7 @@
       // NOTE: This class cannot be used safely cross-platform (Windows) with
       // non-ASCII characters in paths.
       // Consider replacing the implementation using std::filesystem (C++ 17).
-      // In the meantime, consider using octave::sys::get_dirlist instead.
+      // In the meantime, consider using sys::get_dirlist instead.
 
     public:
 
--- a/liboctave/system/file-stat.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/system/file-stat.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -209,10 +209,10 @@
           // If path is a root (like "C:" or "\\SERVER\share"), add a
           // trailing backslash.
           // FIXME: Does this pattern match all possible UNC roots?
-          octave::regexp pat (R"(^\\\\[\w-]*\\[\w-]*$)");
+          regexp pat (R"(^\\\\[\w-]*\\[\w-]*$)");
           if ((full_file_name.length () == 2 && full_file_name[1] == ':')
               || pat.is_match (full_file_name))
-            full_file_name += "\\";
+            full_file_name += '\\';
 #endif
 
           const char *cname = full_file_name.c_str ();
--- a/liboctave/system/lo-sysdep.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/system/lo-sysdep.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -31,6 +31,7 @@
 #include "file-ops.h"
 #include "lo-error.h"
 #include "lo-sysdep.h"
+#include "localcharset-wrapper.h"
 #include "putenv-wrapper.h"
 #include "uniconv-wrappers.h"
 #include "unistd-wrappers.h"
@@ -40,8 +41,9 @@
 #  include <windows.h>
 #  include <wchar.h>
 
+#  include "filepos-wrappers.h"
 #  include "lo-hash.h"
-#  include "filepos-wrappers.h"
+#  include "oct-locbuf.h"
 #  include "unwind-prot.h"
 #endif
 
@@ -219,7 +221,8 @@
           return false;
         }
 
-      unwind_action act ([fptr, tmpname] () {
+      unwind_action act ([=] ()
+                         {
                            std::fclose (fptr);
                            sys::unlink (tmpname);
                          });
@@ -428,8 +431,10 @@
 
 #if defined (OCTAVE_USE_WINDOWS_API)
       wchar_t *wnew_item = u8_to_wchar (new_item);
-      unwind_protect frame;
-      frame.add_fcn (std::free, static_cast<void *> (new_item));
+
+      // free new_item, but leak wnew_item (see above)
+      unwind_action free_new_item ([=] () { std::free (new_item); });
+
       if (_wputenv (wnew_item) < 0)
         (*current_liboctave_error_handler) ("putenv (%s) failed", new_item);
 #else
@@ -523,11 +528,16 @@
     // checks whether there are any non-ASCII characters in the passed
     // file name.  If there are not, it returns the original name.
 
-    // Otherwise, it tries to obtain the short file name (8.3 naming
-    // scheme) which only consists of ASCII characters and are safe to
-    // pass.  However, short file names can be disabled for performance
-    // reasons on the file system level with NTFS.  So there is no
-    // guarantee that these exist.
+    // Otherwise, it optionally tries to convert the file name to the locale
+    // charset.
+
+    // If the file name contains characters that cannot be converted to the
+    // locale charset (or that step is skipped), it tries to obtain the short
+    // file name (8.3 naming scheme) which only consists of ASCII characters
+    // and are safe to pass.  However, short file names can be disabled for
+    // performance reasons on the file system level with NTFS and they are not
+    // stored on other file systems (e.g. ExFAT).  So there is no guarantee
+    // that these exist.
 
     // If short file names are not stored, a hard link to the file is
     // created.  For this the path to the file is split at the deepest
@@ -548,7 +558,8 @@
     // For Unixy systems, this function does nothing.
 
     std::string
-    get_ASCII_filename (const std::string& orig_file_name)
+    get_ASCII_filename (const std::string& orig_file_name,
+                        const bool allow_locale)
     {
 #if defined (OCTAVE_USE_WINDOWS_API)
 
@@ -558,7 +569,7 @@
       // This is useful for passing file names to functions that are not
       // aware of the character encoding we are using.
 
-      // 1. Check whether filename contains non-ASCII (UTF-8) characters.
+      // 0. Check whether filename contains non-ASCII (UTF-8) characters.
 
       std::string::const_iterator first_non_ASCII
         = std::find_if (orig_file_name.begin (), orig_file_name.end (),
@@ -567,8 +578,29 @@
       if (first_non_ASCII == orig_file_name.end ())
         return orig_file_name;
 
-      // 2. Check if file system stores short filenames (always
-      // ASCII-only).
+      // 1. Optionally, check if all characters in the path can be successfully
+      // converted to the locale charset
+      if (allow_locale)
+        {
+          const char *locale = octave_locale_charset_wrapper ();
+          if (locale)
+            {
+              const uint8_t *name_u8 = reinterpret_cast<const uint8_t *>
+                                         (orig_file_name.c_str ());
+              size_t length = 0;
+              char *name_locale = octave_u8_conv_to_encoding_strict
+                                    (locale, name_u8,
+                                     orig_file_name.length () + 1, &length);
+              if (name_locale)
+                {
+                  std::string file_name_locale (name_locale, length);
+                  free (name_locale);
+                  return file_name_locale;
+                }
+            }
+        }
+
+      // 2. Check if file system stores short filenames (might be ASCII-only).
 
       std::wstring w_orig_file_name_str = u8_to_wstring (orig_file_name);
       const wchar_t *w_orig_file_name = w_orig_file_name_str.c_str ();
@@ -589,15 +621,24 @@
           // Dynamically allocate the correct size (terminating null char
           // was included in length).
 
-          wchar_t *w_short_file_name = new wchar_t[length];
+          OCTAVE_LOCAL_BUFFER (wchar_t, w_short_file_name, length);
           GetShortPathNameW (w_full_file_name, w_short_file_name, length);
 
           std::wstring w_short_file_name_str
             = std::wstring (w_short_file_name, length);
-          std::string short_file_name = u8_from_wstring (w_short_file_name_str);
 
           if (w_short_file_name_str.compare (0, length-1, w_full_file_name_str) != 0)
-            return short_file_name;
+            {
+              // Check whether short file name contains non-ASCII characters
+              std::string short_file_name
+                = u8_from_wstring (w_short_file_name_str);
+              first_non_ASCII
+                = std::find_if (short_file_name.begin (),
+                                short_file_name.end (),
+                                [](char c) { return (c < 0 || c >= 128); });
+              if (first_non_ASCII == short_file_name.end ())
+                return short_file_name;
+            }
         }
 
       // 3. Create hard link with only-ASCII characters.
@@ -651,6 +692,10 @@
       if (CreateHardLinkW (w_filename_hash, w_orig_file_name, nullptr))
         return filename_hash;
 
+#else
+
+      octave_unused_parameter (allow_locale);
+
 #endif
 
       return orig_file_name;
--- a/liboctave/system/lo-sysdep.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/system/lo-sysdep.h	Thu Nov 19 13:08:00 2020 -0800
@@ -71,7 +71,8 @@
 
     extern std::string u8_from_wstring (const std::wstring&);
 
-    extern std::string get_ASCII_filename (const std::string& long_file_name);
+    extern std::string get_ASCII_filename (const std::string& long_file_name,
+                                           const bool allow_locale = false);
   }
 }
 
--- a/liboctave/system/oct-env.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/system/oct-env.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -165,6 +165,13 @@
     }
 
     std::string
+    env::get_user_data_directory ()
+    {
+      return (instance_ok ())
+        ? instance->do_get_user_data_directory () : "";
+    }
+
+    std::string
     env::get_program_name (void)
     {
       return (instance_ok ())
@@ -248,9 +255,9 @@
       if (SHGetFolderPathW (nullptr, CSIDL_APPDATA | CSIDL_FLAG_DONT_VERIFY,
                             nullptr, SHGFP_TYPE_CURRENT, path) == S_OK)
         {
-          char *local_app_data = u8_from_wchar (path);
-          cfg_dir = local_app_data;
-          free (local_app_data);
+          char *app_data = u8_from_wchar (path);
+          cfg_dir = app_data;
+          free (app_data);
         }
 #else
       cfg_dir = do_getenv ("XDG_CONFIG_HOME");
@@ -263,6 +270,32 @@
       return cfg_dir;
     }
 
+  std::string
+  env::do_get_user_data_directory (void) const
+  {
+      std::string data_dir;
+
+#if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && defined (OCTAVE_USE_WINDOWS_API)
+      wchar_t path[MAX_PATH+1];
+      if (SHGetFolderPathW (nullptr, CSIDL_APPDATA | CSIDL_FLAG_DONT_VERIFY,
+                            nullptr, SHGFP_TYPE_CURRENT, path) == S_OK)
+        {
+          char *app_data = u8_from_wchar (path);
+          data_dir = app_data;
+          free (app_data);
+        }
+#else
+      data_dir = do_getenv ("XDG_DATA_HOME");
+
+      if (data_dir.empty ())
+        data_dir = do_get_home_directory () + sys::file_ops::dir_sep_str ()
+             + ".local" + sys::file_ops::dir_sep_str () + "share";
+#endif
+
+      return data_dir;
+  }
+
+
     // FIXME: this leaves no way to distinguish between a
     // variable that is not set and one that is set to the empty string.
     // Is this a problem?
--- a/liboctave/system/oct-env.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/system/oct-env.h	Thu Nov 19 13:08:00 2020 -0800
@@ -70,6 +70,8 @@
 
       static std::string get_user_config_directory (void);
 
+      static std::string get_user_data_directory (void);
+
       static std::string get_program_name (void);
 
       static std::string get_program_invocation_name (void);
@@ -111,6 +113,8 @@
 
       std::string do_get_user_config_directory (void) const;
 
+      std::string do_get_user_data_directory (void) const;
+
       std::string do_get_user_name (void) const;
 
       std::string do_get_host_name (void) const;
--- a/liboctave/util/cmd-edit.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/util/cmd-edit.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -562,7 +562,7 @@
   char *
   gnu_readline::do_completer_word_break_hook ()
   {
-    static char *dir_sep = octave_strdup_wrapper (" '\"");
+    static char *dir_sep = octave_strdup_wrapper (R"( '")");
 
     std::string word;
     std::string line = get_line_buffer ();
--- a/liboctave/util/cmd-hist.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/util/cmd-hist.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -46,6 +46,7 @@
 
 #include "oct-rl-hist.h"
 
+#include "file-ops.h"
 #include "file-stat.h"
 #endif
 
@@ -364,6 +365,17 @@
 
         if (! f.empty ())
           {
+            // Try to create the folder if it does not exist
+            std::string hist_dir = sys::file_ops::dirname (f);
+            if (! hist_dir.empty ())
+              {
+                sys::file_stat fs (hist_dir);
+                if (! fs.is_dir () && (sys::mkdir (hist_dir, 0777) < 0))
+                  (*current_liboctave_error_handler)
+                    ("%s: Could not create directory \"%s\" for history",
+                     "gnu_history::do_write", hist_dir.c_str ());
+              }
+
             int status = ::octave_write_history (f.c_str ());
 
             if (status != 0)
--- a/liboctave/util/lo-utils.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/util/lo-utils.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -38,6 +38,7 @@
 
 #include "quit.h"
 
+#include "intprops-wrappers.h"
 #include "lo-error.h"
 #include "lo-ieee.h"
 #include "lo-mappers.h"
@@ -46,12 +47,6 @@
 bool xis_int_or_inf_or_nan (double x)
 { return octave::math::isnan (x) || octave::math::x_nint (x) == x; }
 
-bool xis_one_or_zero (double x)
-{ return x == 0 || x == 1; }
-
-bool xis_zero (double x)
-{ return x == 0; }
-
 bool xtoo_large_for_float (double x)
 {
   return (octave::math::isfinite (x)
@@ -67,12 +62,6 @@
 bool xis_int_or_inf_or_nan (float x)
 { return octave::math::isnan (x) || octave::math::x_nint (x) == x; }
 
-bool xis_one_or_zero (float x)
-{ return x == 0 || x == 1; }
-
-bool xis_zero (float x)
-{ return x == 0; }
-
 // Save a string.
 
 char *
@@ -187,244 +176,292 @@
   return retval;
 }
 
-// Note that the caller is responsible for repositioning the stream on failure.
+namespace octave
+{
+  // Note that the caller is responsible for repositioning the stream on
+  // failure.
+
+  template <typename T>
+  T
+  read_inf_nan_na (std::istream& is, char c0)
+  {
+    T val = 0.0;
+
+    switch (c0)
+      {
+      case 'i': case 'I':
+        {
+          char c1 = is.get ();
+          if (c1 == 'n' || c1 == 'N')
+            {
+              char c2 = is.get ();
+              if (c2 == 'f' || c2 == 'F')
+                val = std::numeric_limits<T>::infinity ();
+              else
+                is.setstate (std::ios::failbit);
+            }
+          else
+            is.setstate (std::ios::failbit);
+        }
+        break;
 
-template <typename T>
-T
-read_inf_nan_na (std::istream& is, char c0)
-{
-  T val = 0.0;
+      case 'n': case 'N':
+        {
+          char c1 = is.get ();
+          if (c1 == 'a' || c1 == 'A')
+            {
+              char c2 = is.get ();
+              if (c2 == 'n' || c2 == 'N')
+                val = std::numeric_limits<T>::quiet_NaN ();
+              else
+                {
+                  val = numeric_limits<T>::NA ();
+                  if (c2 != std::istream::traits_type::eof ())
+                    is.putback (c2);
+                  else
+                    is.clear (is.rdstate () & ~std::ios::failbit);
+                }
+            }
+          else
+            is.setstate (std::ios::failbit);
+        }
+        break;
+
+      default:
+        (*current_liboctave_error_handler)
+          ("read_inf_nan_na: invalid character '%c'", c0);
+      }
+
+    return val;
+  }
+
+  // Read a double value.  Discard any sign on NaN and NA.
+
+  template <typename T>
+  double
+  read_fp_value (std::istream& is)
+  {
+    T val = 0.0;
+
+    // FIXME: resetting stream position is likely to fail unless we are
+    // reading from a file.
+    std::streampos pos = is.tellg ();
+
+    char c1 = ' ';
+
+    while (isspace (c1))
+      c1 = is.get ();
+
+    bool neg = false;
 
-  switch (c0)
-    {
-    case 'i': case 'I':
+    switch (c1)
+      {
+      case '-':
+        neg = true;
+        OCTAVE_FALLTHROUGH;
+
+      case '+':
+        {
+          char c2 = 0;
+          c2 = is.get ();
+          if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N')
+            val = read_inf_nan_na<T> (is, c2);
+          else
+            {
+              is.putback (c2);
+              is >> val;
+            }
+
+          if (neg && ! is.fail ())
+            val = -val;
+        }
+        break;
+
+      case 'i': case 'I':
+      case 'n': case 'N':
+        val = read_inf_nan_na<T> (is, c1);
+        break;
+
+      default:
+        is.putback (c1);
+        is >> val;
+        break;
+      }
+
+    std::ios::iostate status = is.rdstate ();
+    if (status & std::ios::failbit)
       {
-        char c1 = is.get ();
-        if (c1 == 'n' || c1 == 'N')
+        // Convert MAX_VAL returned by C++ streams for very large numbers to Inf
+        if (val == std::numeric_limits<T>::max ())
+          {
+            if (neg)
+              val = -std::numeric_limits<T>::infinity ();
+            else
+              val = std::numeric_limits<T>::infinity ();
+            is.clear (status & ~std::ios::failbit);
+          }
+        else
           {
-            char c2 = is.get ();
-            if (c2 == 'f' || c2 == 'F')
-              val = std::numeric_limits<T>::infinity ();
+            // True error.  Reset stream to original position and pass status on.
+            is.clear ();
+            is.seekg (pos);
+            is.setstate (status);
+          }
+      }
+
+    return val;
+  }
+
+  template <typename T>
+  std::complex<T>
+  read_cx_fp_value (std::istream& is)
+  {
+    T re = 0.0;
+    T im = 0.0;
+
+    std::complex<T> cx = 0.0;
+
+    char ch = ' ';
+
+    while (isspace (ch))
+      ch = is.get ();
+
+    if (ch == '(')
+      {
+        re = read_value<T> (is);
+        ch = is.get ();
+
+        if (ch == ',')
+          {
+            im = read_value<T> (is);
+            ch = is.get ();
+
+            if (ch == ')')
+              cx = std::complex<T> (re, im);
             else
               is.setstate (std::ios::failbit);
           }
-        else
-          is.setstate (std::ios::failbit);
-      }
-      break;
-
-    case 'n': case 'N':
-      {
-        char c1 = is.get ();
-        if (c1 == 'a' || c1 == 'A')
-          {
-            char c2 = is.get ();
-            if (c2 == 'n' || c2 == 'N')
-              val = std::numeric_limits<T>::quiet_NaN ();
-            else
-              {
-                val = octave::numeric_limits<T>::NA ();
-                if (c2 != std::istream::traits_type::eof ())
-                  is.putback (c2);
-                else
-                  is.clear (is.rdstate () & ~std::ios::failbit);
-              }
-          }
+        else if (ch == ')')
+          cx = re;
         else
           is.setstate (std::ios::failbit);
       }
-      break;
-
-    default:
-      (*current_liboctave_error_handler)
-        ("read_inf_nan_na: invalid character '%c'", c0);
-    }
-
-  return val;
-}
-
-// Read a double value.  Discard any sign on NaN and NA.
-
-template <typename T>
-double
-octave_read_fp_value (std::istream& is)
-{
-  T val = 0.0;
-
-  // FIXME: resetting stream position is likely to fail unless we are
-  // reading from a file.
-  std::streampos pos = is.tellg ();
-
-  char c1 = ' ';
-
-  while (isspace (c1))
-    c1 = is.get ();
-
-  bool neg = false;
-
-  switch (c1)
-    {
-    case '-':
-      neg = true;
-      OCTAVE_FALLTHROUGH;
-
-    case '+':
+    else
       {
-        char c2 = 0;
-        c2 = is.get ();
-        if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N')
-          val = read_inf_nan_na<T> (is, c2);
-        else
-          {
-            is.putback (c2);
-            is >> val;
-          }
+        is.putback (ch);
+        cx = read_value<T> (is);
+      }
+
+    return cx;
+  }
+
+  // FIXME: Could we use traits and enable_if to avoid duplication in the
+  // following specializations?
+
+  template <> double read_value (std::istream& is)
+  {
+    return read_fp_value<double> (is);
+  }
 
-        if (neg && ! is.fail ())
-          val = -val;
-      }
-      break;
+  template <> Complex read_value (std::istream& is)
+  {
+    return read_cx_fp_value<double> (is);
+  }
 
-    case 'i': case 'I':
-    case 'n': case 'N':
-      val = read_inf_nan_na<T> (is, c1);
-      break;
+  template <> float read_value (std::istream& is)
+  {
+    return read_fp_value<float> (is);
+  }
+
+  template <> FloatComplex read_value (std::istream& is)
+  {
+    return read_cx_fp_value<float> (is);
+  }
+
+  // Note: precision is supposed to be managed outside of this function by
+  // setting stream parameters.
 
-    default:
-      is.putback (c1);
-      is >> val;
-      break;
-    }
+  template <> void write_value (std::ostream& os, const double& value)
+  {
+    if (lo_ieee_is_NA (value))
+      os << "NA";
+    else if (lo_ieee_isnan (value))
+      os << "NaN";
+    else if (lo_ieee_isinf (value))
+      os << (value < 0 ? "-Inf" : "Inf");
+    else
+      os << value;
+  }
+
+  template <> void write_value (std::ostream& os, const Complex& value)
+  {
+    os << '(';
+    write_value<double> (os, real (value));
+    os << ',';
+    write_value<double> (os, imag (value));
+    os << ')';
+  }
+
+  // Note: precision is supposed to be managed outside of this function by
+  // setting stream parameters.
 
-  std::ios::iostate status = is.rdstate ();
-  if (status & std::ios::failbit)
+  template <> void write_value (std::ostream& os, const float& value)
+  {
+    if (lo_ieee_is_NA (value))
+      os << "NA";
+    else if (lo_ieee_isnan (value))
+      os << "NaN";
+    else if (lo_ieee_isinf (value))
+      os << (value < 0 ? "-Inf" : "Inf");
+    else
+      os << value;
+  }
+
+  template <> void write_value (std::ostream& os, const FloatComplex& value)
+  {
+    os << '(';
+    write_value<float> (os, real (value));
+    os << ',';
+    write_value<float> (os, imag (value));
+    os << ')';
+  }
+
+  namespace math
+  {
+    bool int_multiply_overflow (int a, int b)
     {
-      // Convert MAX_VAL returned by C++ streams for very large numbers to Inf
-      if (val == std::numeric_limits<T>::max ())
-        {
-          if (neg)
-            val = -std::numeric_limits<T>::infinity ();
-          else
-            val = std::numeric_limits<T>::infinity ();
-          is.clear (status & ~std::ios::failbit);
-        }
-      else
-        {
-          // True error.  Reset stream to original position and pass status on.
-          is.clear ();
-          is.seekg (pos);
-          is.setstate (status);
-        }
+      return octave_i_multiply_overflow_wrapper (a, b);
     }
 
-  return val;
-}
-
-template <typename T>
-std::complex<T>
-octave_read_cx_fp_value (std::istream& is)
-{
-  T re = 0.0;
-  T im = 0.0;
-
-  std::complex<T> cx = 0.0;
-
-  char ch = ' ';
-
-  while (isspace (ch))
-    ch = is.get ();
-
-  if (ch == '(')
+    bool int_multiply_overflow (long int a, long int b)
     {
-      re = octave_read_value<T> (is);
-      ch = is.get ();
-
-      if (ch == ',')
-        {
-          im = octave_read_value<T> (is);
-          ch = is.get ();
-
-          if (ch == ')')
-            cx = std::complex<T> (re, im);
-          else
-            is.setstate (std::ios::failbit);
-        }
-      else if (ch == ')')
-        cx = re;
-      else
-        is.setstate (std::ios::failbit);
-    }
-  else
-    {
-      is.putback (ch);
-      cx = octave_read_value<double> (is);
+      return octave_li_multiply_overflow_wrapper (a, b);
     }
 
-  return cx;
-}
-
-template <> OCTAVE_API double octave_read_value (std::istream& is)
-{
-  return octave_read_fp_value<double> (is);
-}
+#if defined (OCTAVE_HAVE_LONG_LONG_INT)
+    bool int_multiply_overflow (long long int a, long long int b)
+    {
+      return octave_lli_multiply_overflow_wrapper (a, b);
+    }
+#endif
 
-template <> OCTAVE_API Complex octave_read_value (std::istream& is)
-{
-  return octave_read_cx_fp_value<double> (is);
-}
-
-template <> OCTAVE_API float octave_read_value (std::istream& is)
-{
-  return octave_read_fp_value<float> (is);
-}
-
-template <> OCTAVE_API FloatComplex octave_read_value (std::istream& is)
-{
-  return octave_read_cx_fp_value<float> (is);
-}
+    bool int_multiply_overflow (unsigned int a, unsigned int b)
+    {
+      return octave_ui_multiply_overflow_wrapper (a, b);
+    }
 
-void
-octave_write_double (std::ostream& os, double d)
-{
-  if (lo_ieee_is_NA (d))
-    os << "NA";
-  else if (lo_ieee_isnan (d))
-    os << "NaN";
-  else if (lo_ieee_isinf (d))
-    os << (d < 0 ? "-Inf" : "Inf");
-  else
-    os << d;
-}
-
-void
-octave_write_complex (std::ostream& os, const Complex& c)
-{
-  os << '(';
-  octave_write_double (os, real (c));
-  os << ',';
-  octave_write_double (os, imag (c));
-  os << ')';
-}
+    bool int_multiply_overflow (unsigned long int a, unsigned long int b)
+    {
+      return octave_uli_multiply_overflow_wrapper (a, b);
+    }
 
-void
-octave_write_float (std::ostream& os, float d)
-{
-  if (lo_ieee_is_NA (d))
-    os << "NA";
-  else if (lo_ieee_isnan (d))
-    os << "NaN";
-  else if (lo_ieee_isinf (d))
-    os << (d < 0 ? "-Inf" : "Inf");
-  else
-    os << d;
+#if defined (OCTAVE_HAVE_UNSIGNED_LONG_LONG_INT)
+    bool int_multiply_overflow (unsigned long long int a,
+                                unsigned long long int b)
+    {
+      return octave_ulli_multiply_overflow_wrapper (a, b);
+    }
+#endif
+
+  }
 }
-
-void
-octave_write_float_complex (std::ostream& os, const FloatComplex& c)
-{
-  os << '(';
-  octave_write_float (os, real (c));
-  os << ',';
-  octave_write_float (os, imag (c));
-  os << ')';
-}
--- a/liboctave/util/lo-utils.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/util/lo-utils.h	Thu Nov 19 13:08:00 2020 -0800
@@ -66,15 +66,26 @@
 }
 
 extern OCTAVE_API bool xis_int_or_inf_or_nan (double x);
-extern OCTAVE_API bool xis_one_or_zero (double x);
-extern OCTAVE_API bool xis_zero (double x);
+
+template <typename T>
+bool
+xis_one_or_zero (const T& x)
+{
+  return x == T (0) || x == T (1);
+}
+
+template <typename T>
+bool
+xis_zero (const T& x)
+{
+  return x == T (0);
+}
+
 extern OCTAVE_API bool xtoo_large_for_float (double x);
 
 extern OCTAVE_API bool xtoo_large_for_float (const Complex&  x);
 
 extern OCTAVE_API bool xis_int_or_inf_or_nan (float x);
-extern OCTAVE_API bool xis_one_or_zero (float x);
-extern OCTAVE_API bool xis_zero (float x);
 extern OCTAVE_API bool xtoo_large_for_float (float x);
 
 extern OCTAVE_API char * strsave (const char *);
@@ -85,55 +96,104 @@
 extern OCTAVE_API std::string octave_fgets (std::FILE *, bool& eof);
 extern OCTAVE_API std::string octave_fgetl (std::FILE *, bool& eof);
 
-template <typename T>
-T
-octave_read_value (std::istream& is)
+namespace octave
 {
-  T retval;
-  is >> retval;
-  return retval;
+  template <typename T>
+  T
+  read_value (std::istream& is)
+  {
+    T retval;
+    is >> retval;
+    return retval;
+  }
+
+  template <> double read_value (std::istream& is);
+  template <> Complex read_value (std::istream& is);
+  template <> float read_value (std::istream& is);
+  template <> FloatComplex read_value (std::istream& is);
+
+  template <typename T>
+  void
+  write_value (std::ostream& os, const T& value)
+  {
+    os << value;
+  }
+
+  template <> void write_value (std::ostream& os, const double& value);
+  template <> void write_value (std::ostream& os, const Complex& value);
+  template <> void write_value (std::ostream& os, const float& value);
+  template <> void write_value (std::ostream& os, const FloatComplex& value);
+
+  namespace math
+  {
+    bool int_multiply_overflow (int a, int b);
+    bool int_multiply_overflow (long int a, long int b);
+#if defined (OCTAVE_HAVE_LONG_LONG_INT)
+    bool int_multiply_overflow (long long int a, long long int b);
+#endif
+    bool int_multiply_overflow (unsigned int a, unsigned int b);
+    bool int_multiply_overflow (unsigned long int a, unsigned long int b);
+#if defined (OCTAVE_HAVE_UNSIGNED_LONG_LONG_INT)
+    bool int_multiply_overflow (unsigned long long int a,
+                                unsigned long long int b);
+#endif
+  }
 }
 
-template <> OCTAVE_API double octave_read_value (std::istream& is);
-template <> OCTAVE_API Complex octave_read_value (std::istream& is);
-template <> OCTAVE_API float octave_read_value (std::istream& is);
-template <> OCTAVE_API FloatComplex octave_read_value (std::istream& is);
-
-// The next four functions are provided for backward compatibility.
+OCTAVE_DEPRECATED (7, "use 'octave::read_value<T>' instead")
 inline double
 octave_read_double (std::istream& is)
 {
-  return octave_read_value<double> (is);
+  return octave::read_value<double> (is);
 }
 
+OCTAVE_DEPRECATED (7, "use 'octave::read_value<T>' instead")
 inline Complex
 octave_read_complex (std::istream& is)
 {
-  return octave_read_value<Complex> (is);
+  return octave::read_value<Complex> (is);
 }
 
+OCTAVE_DEPRECATED (7, "use 'octave::read_value<T>' instead")
 inline float
 octave_read_float (std::istream& is)
 {
-  return octave_read_value<float> (is);
+  return octave::read_value<float> (is);
 }
 
+OCTAVE_DEPRECATED (7, "use 'octave::read_value<T>' instead")
 inline FloatComplex
 octave_read_float_complex (std::istream& is)
 {
-  return octave_read_value<FloatComplex> (is);
+  return octave::read_value<FloatComplex> (is);
+}
+
+OCTAVE_DEPRECATED (7, "use 'octave::write_value<T>' instead")
+inline void
+octave_write_double (std::ostream& os, double value)
+{
+  octave::write_value<double> (os, value);
 }
 
-extern OCTAVE_API void
-octave_write_double (std::ostream& os, double dval);
-
-extern OCTAVE_API void
-octave_write_complex (std::ostream& os, const Complex& cval);
+OCTAVE_DEPRECATED (7, "use 'octave::write_value<T>' instead")
+inline void
+octave_write_complex (std::ostream& os, const Complex& value)
+{
+  octave::write_value<Complex> (os, value);
+}
 
-extern OCTAVE_API void
-octave_write_float (std::ostream& os, float dval);
+OCTAVE_DEPRECATED (7, "use 'octave::write_value<T>' instead")
+inline void
+octave_write_float (std::ostream& os, float value)
+{
+  octave::write_value<float> (os, value);
+}
 
-extern OCTAVE_API void
-octave_write_float_complex (std::ostream& os, const FloatComplex& cval);
+OCTAVE_DEPRECATED (7, "use 'octave::write_value<T>' instead")
+inline void
+octave_write_float_complex (std::ostream& os, const FloatComplex& value)
+{
+  octave::write_value<FloatComplex> (os, value);
+}
 
 #endif
--- a/liboctave/util/oct-base64.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/util/oct-base64.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -94,4 +94,31 @@
 
     return retval;
   }
+
+  intNDArray<octave_uint8>
+  base64_decode_bytes (const std::string& str)
+  {
+    intNDArray<octave_uint8> retval;
+
+    char *out;
+    size_t outlen;
+
+    bool ok
+      = octave_base64_decode_alloc_wrapper (str.data (), str.length (),
+                                            &out, &outlen);
+
+    if (! ok)
+      (*current_liboctave_error_handler)
+        ("base64_decode: input was not valid base64");
+
+    if (! out)
+      (*current_liboctave_error_handler)
+        ("base64_decode: memory allocation error");
+
+    retval.resize (dim_vector (1, outlen));
+    std::copy (out, out + outlen, retval.fortran_vec ());
+    ::free (out);
+
+    return retval;
+  }
 }
--- a/liboctave/util/oct-base64.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/util/oct-base64.h	Thu Nov 19 13:08:00 2020 -0800
@@ -30,6 +30,8 @@
 
 #include <string>
 
+#include "intNDArray.h"
+
 template <typename T> class Array;
 
 namespace octave
@@ -39,6 +41,9 @@
 
   extern OCTAVE_API Array<double>
   base64_decode (const std::string& str);
+
+  extern OCTAVE_API intNDArray<octave_uint8>
+  base64_decode_bytes (const std::string& str);
 }
 
 #endif
--- a/liboctave/util/oct-glob.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/util/oct-glob.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -33,9 +33,18 @@
 #include "glob-wrappers.h"
 
 #include "oct-glob.h"
+#include "file-ops.h"
 #include "file-stat.h"
 #include "unwind-prot.h"
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+#  include <windows.h>
+#  include <shlwapi.h>
+#  include <wchar.h>
+
+#  include "lo-sysdep.h"
+#endif
+
 // These functions are defined here and not in glob_match.cc so that we
 // can include the glob.h file from gnulib, which defines glob to
 // be rpl_glob.  If we include glob.h in glob_match.cc, then it
@@ -78,11 +87,10 @@
 
       int k = 0;
 
-      unwind_protect frame;
-
       void *glob_info = octave_create_glob_info_struct ();
 
-      frame.add_fcn (octave_destroy_glob_info_struct, glob_info);
+      unwind_action cleanup_glob_info_struct
+        ([=] () { octave_destroy_glob_info_struct (glob_info); });
 
       for (int i = 0; i < npat; i++)
         {
@@ -143,6 +151,56 @@
       return retval.sort ();
     }
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+
+    static void
+    find_files (std::list<std::string>& dirlist, const std::string& dir,
+                const std::string& pat, std::string& file)
+    {
+      // remove leading file separators
+      while (file.length () > 1 && sys::file_ops::is_dir_sep (file[0]))
+        file = file.substr (1, std::string::npos);
+
+      // find first file in directory that matches pattern in PAT
+      std::wstring wpat = u8_to_wstring (sys::file_ops::concat (dir, pat));
+      _WIN32_FIND_DATAW ffd;
+      HANDLE h_find = FindFirstFileW (wpat.c_str (), &ffd);
+      // ignore any error
+      if (h_find == INVALID_HANDLE_VALUE)
+        return;
+
+      unwind_action close_h_find ([=] () { FindClose (h_find); });
+
+      // find all files that match pattern
+      do
+        {
+          std::string found_dir = u8_from_wstring (ffd.cFileName);
+
+          if (file.empty ())
+            {
+              if (found_dir.compare (".") && found_dir.compare (".."))
+                dirlist.push_back (sys::file_ops::concat (dir, found_dir));
+            }
+          else
+            {
+              // get next component of path (or file name)
+              size_t sep_pos
+                = file.find_first_of (sys::file_ops::dir_sep_chars ());
+              std::string pat_str = file.substr (0, sep_pos);
+              std::string file_str = (sep_pos != std::string::npos
+                                      && file.length () > sep_pos+1)
+                                     ? file.substr (sep_pos+1) : "";
+
+              // call this function recursively with next path component in PAT
+              find_files (dirlist, sys::file_ops::concat (dir, found_dir),
+                          pat_str, file_str);
+            }
+        }
+      while (FindNextFileW (h_find, &ffd) != 0);
+    }
+
+#endif
+
     // Glob like Windows "dir".  Treat only * and ? as wildcards,
     // and "*.*" matches filenames even if they do not contain ".".
     string_vector
@@ -152,13 +210,68 @@
 
       int npat = pat.numel ();
 
-      int k = 0;
+#if defined (OCTAVE_USE_WINDOWS_API)
+
+      std::list<std::string> dirlist;
+
+      for (int i = 0; i < npat; i++)
+        {
+          std::string xpat = pat(i);
+          if (xpat.empty ())
+            continue;
+
+          // separate component until first dir separator
+          size_t sep_pos
+            = xpat.find_first_of (sys::file_ops::dir_sep_chars ());
+          std::string file = (sep_pos != std::string::npos
+                              && xpat.length () > sep_pos+1)
+                             ? xpat.substr (sep_pos+1) : "";
+          xpat = xpat.substr (0, sep_pos);
+
+          std::string dir = "";
+
+          if ((sep_pos == 2 || xpat.length () == 2) && xpat[1] == ':')
+            {
+              // include disc root with first file or folder
+
+              // remove leading file separators in path without disc root
+              while (file.length () > 1 && sys::file_ops::is_dir_sep (file[0]))
+                file = file.substr (1, std::string::npos);
 
-      unwind_protect frame;
+              sep_pos = file.find_first_of (sys::file_ops::dir_sep_chars ());
+              dir = xpat;
+              xpat = file.substr (0, sep_pos);
+              file = (sep_pos != std::string::npos
+                      && file.length () > sep_pos+1)
+                     ? file.substr (sep_pos+1) : "";
+              if (xpat.empty ())
+                {
+                  // don't glob if input is only disc root
+                  if (PathFileExistsA (pat(i).c_str ()))
+                    {
+                      if (sys::file_ops::is_dir_sep (pat(i).back ()))
+                        dirlist.push_back (dir +
+                                           sys::file_ops::dir_sep_char ());
+                      else
+                        dirlist.push_back (dir);
+                    }
+                  continue;
+                }
+            }
+
+          find_files (dirlist, dir, xpat, file);
+        }
+
+      retval = string_vector (dirlist);
+
+#else
+
+      int k = 0;
 
       void *glob_info = octave_create_glob_info_struct ();
 
-      frame.add_fcn (octave_destroy_glob_info_struct, glob_info);
+      unwind_action cleanup_glob_info_struct
+        ([=] () { octave_destroy_glob_info_struct (glob_info); });
 
       for (int i = 0; i < npat; i++)
         {
@@ -171,12 +284,12 @@
 
               for (size_t j = 0; j < xpat.length (); j++)
                 {
-#if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM)           \
-     && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
+#  if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM)           \
+       && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
                   if (xpat[j] == '\\')
                     escaped += '/';
                   else
-#endif
+#  endif
                     {
                       if (xpat[j] == ']' || xpat[j] == '[')
                         escaped += '\\';
@@ -221,12 +334,12 @@
 
                           for (size_t m = 0; m < tmp.length (); m++)
                             {
-#if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM)           \
+#  if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM)           \
      && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
                               if (tmp[m] == '/')
                                 unescaped += '\\';
                               else
-#endif
+#  endif
                                 {
                                   if (tmp[m] == '\\'
                                       && ++m == tmp.length ())
@@ -244,6 +357,7 @@
                 }
             }
         }
+#endif
 
       return retval.sort ();
     }
--- a/liboctave/util/oct-inttypes.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/util/oct-inttypes.h	Thu Nov 19 13:08:00 2020 -0800
@@ -1330,4 +1330,29 @@
   return octave_int<T> (xv <= yv ? xv : yv);
 }
 
+// Ints are handled by converting to octave_int type.
+
+#define OCTAVE_INT_IDX_TYPE_BIN_OP(OP)                          \
+  template <typename T>                                         \
+  inline octave_int<T>                                          \
+  operator OP (const octave_int<T>& x, octave_idx_type y)       \
+  {                                                             \
+    return x OP octave_int<T> (y);                              \
+  }                                                             \
+                                                                \
+  template <typename T>                                         \
+  inline octave_int<T>                                          \
+  operator OP (octave_idx_type x, const octave_int<T>& y)       \
+  {                                                             \
+    return octave_int<T> (x) OP y;                              \
+  }
+
+OCTAVE_INT_IDX_TYPE_BIN_OP (+)
+OCTAVE_INT_IDX_TYPE_BIN_OP (-)
+OCTAVE_INT_IDX_TYPE_BIN_OP (*)
+OCTAVE_INT_IDX_TYPE_BIN_OP (/)
+
+#undef OCTAVE_INT_IDX_TYPE_BIN_OP
+
+
 #endif
--- a/liboctave/util/oct-string.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/util/oct-string.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -516,8 +516,7 @@
            who.c_str (), encoding.c_str (), std::strerror (errno));
     }
 
-  octave::unwind_protect frame;
-  frame.add_fcn (::free, static_cast<void *> (native_str));
+  octave::unwind_action free_native_str ([=] () { ::free (native_str); });
 
   std::string retval = std::string (native_str, length);
 
@@ -547,8 +546,7 @@
            who.c_str (), encoding.c_str (), std::strerror (errno));
     }
 
-  octave::unwind_protect frame;
-  frame.add_fcn (::free, static_cast<void *> (utf8_str));
+  octave::unwind_action free_utf8_str ([=] () { ::free (utf8_str); });
 
   std::string retval = std::string (reinterpret_cast<char *> (utf8_str), length);
 
@@ -594,8 +592,8 @@
                   ("%s: converting from codepage '%s' to UTF-8 failed: %s",
                    who.c_str (), fallback.c_str (), std::strerror (errno));
 
-              octave::unwind_protect frame;
-              frame.add_fcn (::free, static_cast<void *> (val_utf8));
+              octave::unwind_action free_val_utf8
+                ([=] () { ::free (val_utf8); });
 
               out_str.append (reinterpret_cast<const char *> (val_utf8),
                               lengthp);
--- a/liboctave/util/unwind-prot.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/util/unwind-prot.h	Thu Nov 19 13:08:00 2020 -0800
@@ -147,7 +147,7 @@
   //     int val = 42;
   //
   //     // template parameters, std::bind and std::function provide
-  //     // flexibility in calling forms:
+  //     // flexibility in calling forms (function pointer or lambda):
   //
   //     unwind_action act1 (fcn, val);
   //     unwind_action act2 ([val] (void) { fcn (val); });
--- a/liboctave/util/url-transfer.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/util/url-transfer.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -448,8 +448,7 @@
     {
       struct curl_slist *slist = nullptr;
 
-      unwind_protect frame;
-      frame.add_fcn (curl_slist_free_all, slist);
+      unwind_action cleanup_slist ([=] () { curl_slist_free_all (slist); });
 
       std::string cmd = "rnfr " + oldname;
       slist = curl_slist_append (slist, cmd.c_str ());
@@ -616,8 +615,7 @@
 
       struct curl_slist *slist = nullptr;
 
-      unwind_protect frame;
-      frame.add_fcn (curl_slist_free_all, slist);
+      unwind_action cleanup_slist ([=] () { curl_slist_free_all (slist); });
 
       slist = curl_slist_append (slist, "pwd");
       SETOPTR (CURLOPT_POSTQUOTE, slist);
@@ -708,9 +706,7 @@
     {
       struct curl_slist *slist = nullptr;
 
-      unwind_protect frame;
-
-      frame.add_fcn (curl_slist_free_all, slist);
+      unwind_action cleanup_slist ([=] () { curl_slist_free_all (slist); });
 
       if (param.numel () >= 2)
         {
@@ -732,13 +728,12 @@
     // path of the file as its value.
     void form_data_post (const Array<std::string>& param)
     {
-      struct curl_httppost *post = nullptr, *last = nullptr;
+      struct curl_httppost *post = nullptr;
+      struct curl_httppost *last = nullptr;
 
       SETOPT (CURLOPT_URL, m_host_or_url.c_str ());
 
-      unwind_protect frame;
-
-      frame.add_fcn (curl_formfree, post);
+      unwind_action cleanup_httppost ([=] () { curl_formfree (post); });
 
       if (param.numel () >= 2)
         {
@@ -912,9 +907,7 @@
     {
       struct curl_slist *slist = nullptr;
 
-      unwind_protect frame;
-
-      frame.add_fcn (curl_slist_free_all, slist);
+      unwind_action cleanup_slist ([=] () { curl_slist_free_all (slist); });
 
       std::string cmd = action + ' ' + file_or_dir;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/wrappers/intprops-wrappers.c	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,75 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#include "intprops.h"
+
+#include "intprops-wrappers.h"
+
+// The *_OVERFLOW macros are provided by gnulib.  We don't include gnulib
+// headers directly in Octave's C++ source files to avoid problems that
+// may be caused by the way that gnulib overrides standard library
+// functions.
+
+int
+octave_i_multiply_overflow_wrapper (int a, int b)
+{
+  return INT_MULTIPLY_OVERFLOW (a, b);
+}
+
+int
+octave_li_multiply_overflow_wrapper (long int a, long int b)
+{
+  return INT_MULTIPLY_OVERFLOW (a, b);
+}
+
+#if defined (OCTAVE_HAVE_LONG_LONG_INT)
+int
+octave_lli_multiply_overflow_wrapper (long long int a, long long int b)
+{
+  return INT_MULTIPLY_OVERFLOW (a, b);
+}
+#endif
+
+int
+octave_ui_multiply_overflow_wrapper (unsigned int a, unsigned int b)
+{
+  return INT_MULTIPLY_OVERFLOW (a, b);
+}
+
+int
+octave_uli_multiply_overflow_wrapper (unsigned long int a,
+                                      unsigned long int b)
+{
+  return INT_MULTIPLY_OVERFLOW (a, b);
+}
+
+#if defined (OCTAVE_HAVE_UNSIGNED_LONG_LONG_INT)
+int
+octave_ulli_multiply_overflow_wrapper (unsigned long long int a,
+                                       unsigned long long int b)
+{
+  return INT_MULTIPLY_OVERFLOW (a, b);
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/wrappers/intprops-wrappers.h	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,62 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if ! defined (octave_localcharset_wrapper_h)
+#define octave_localcharset_wrapper_h 1
+
+#include "octave-config.h"
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+// These functions return 1 if the operation between the input arguments would
+// overflow.
+
+extern int octave_i_multiply_overflow_wrapper (int a, int b);
+
+extern int octave_li_multiply_overflow_wrapper (long int a, long int b);
+
+#  if defined (OCTAVE_HAVE_LONG_LONG_INT)
+extern int octave_lli_multiply_overflow_wrapper (long long int a,
+                                                 long long int b);
+#  endif
+
+extern int octave_ui_multiply_overflow_wrapper (unsigned int a,
+                                                unsigned int b);
+
+extern int octave_uli_multiply_overflow_wrapper (unsigned long int a,
+                                                 unsigned long int b);
+
+#  if defined (OCTAVE_HAVE_UNSIGNED_LONG_LONG_INT)
+extern int octave_ulli_multiply_overflow_wrapper (unsigned long long int a,
+                                                  unsigned long long int b);
+#  endif
+
+#if defined __cplusplus
+}
+#endif
+
+#endif
--- a/liboctave/wrappers/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/wrappers/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -12,6 +12,7 @@
   %reldir%/glob-wrappers.h \
   %reldir%/hash-wrappers.h \
   %reldir%/iconv-wrappers.h \
+  %reldir%/intprops-wrappers.h \
   %reldir%/localcharset-wrapper.h \
   %reldir%/math-wrappers.h \
   %reldir%/mkostemp-wrapper.h \
@@ -54,6 +55,7 @@
   %reldir%/glob-wrappers.c \
   %reldir%/hash-wrappers.c \
   %reldir%/iconv-wrappers.c \
+  %reldir%/intprops-wrappers.c \
   %reldir%/localcharset-wrapper.c \
   %reldir%/math-wrappers.c \
   %reldir%/mkostemp-wrapper.c \
--- a/liboctave/wrappers/uniconv-wrappers.c	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/wrappers/uniconv-wrappers.c	Thu Nov 19 13:08:00 2020 -0800
@@ -57,11 +57,19 @@
 }
 
 char *
+octave_u8_conv_to_encoding_strict (const char *tocode, const uint8_t *src,
+                                   size_t srclen, size_t *lengthp)
+{
+  return u8_conv_to_encoding (tocode, iconveh_error,
+                              src, srclen, NULL, NULL, lengthp);
+}
+
+char *
 octave_u32_conv_to_encoding_strict (const char *tocode, const uint32_t *src,
-                            size_t srclen, size_t *lengthp)
+                                    size_t srclen, size_t *lengthp)
 {
   return u32_conv_to_encoding (tocode, iconveh_error,
-                              src, srclen, NULL, NULL, lengthp);
+                               src, srclen, NULL, NULL, lengthp);
 }
 
 char *
--- a/liboctave/wrappers/uniconv-wrappers.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/wrappers/uniconv-wrappers.h	Thu Nov 19 13:08:00 2020 -0800
@@ -50,6 +50,10 @@
                             size_t srclen, size_t *lengthp);
 
 extern char *
+octave_u8_conv_to_encoding_strict (const char *tocode, const uint8_t *src,
+                                   size_t srclen, size_t *lengthp);
+
+extern char *
 octave_u32_conv_to_encoding_strict (const char *tocode, const uint32_t *src,
                                     size_t srclen, size_t *lengthp);
 
--- a/liboctave/wrappers/unistr-wrappers.c	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/wrappers/unistr-wrappers.c	Thu Nov 19 13:08:00 2020 -0800
@@ -49,6 +49,27 @@
   return u8_strmbtouc (puc, src);
 }
 
+uint8_t *
+octave_u16_to_u8_wrapper (const uint16_t *src, size_t src_len,
+                          uint8_t *result_buf, size_t *lengthp)
+{
+  return u16_to_u8 (src, src_len, result_buf, lengthp);
+}
+
+uint8_t *
+octave_u32_to_u8_wrapper (const uint32_t *src, size_t src_len,
+                          uint8_t *result_buf, size_t *lengthp)
+{
+  return u32_to_u8 (src, src_len, result_buf, lengthp);
+}
+
+uint16_t *
+octave_u8_to_u16_wrapper (const uint8_t *src, size_t src_len,
+                          uint16_t *result_buf, size_t *lengthp)
+{
+  return u8_to_u16 (src, src_len, result_buf, lengthp);
+}
+
 uint32_t *
 octave_u8_to_u32_wrapper (const uint8_t *src, size_t src_len,
                           uint32_t *result_buf, size_t *lengthp)
--- a/liboctave/wrappers/unistr-wrappers.h	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/wrappers/unistr-wrappers.h	Thu Nov 19 13:08:00 2020 -0800
@@ -39,6 +39,18 @@
 extern int
 octave_u8_strmbtouc_wrapper (uint32_t *puc, const uint8_t *src);
 
+extern uint8_t *
+octave_u16_to_u8_wrapper (const uint16_t *src, size_t src_len,
+                          uint8_t *result_buf, size_t *lengthp);
+
+extern uint8_t *
+octave_u32_to_u8_wrapper (const uint32_t *src, size_t src_len,
+                          uint8_t *result_buf, size_t *lengthp);
+
+extern uint16_t *
+octave_u8_to_u16_wrapper (const uint8_t *src, size_t src_len,
+                          uint16_t *result_buf, size_t *lengthp);
+
 extern uint32_t *
 octave_u8_to_u32_wrapper (const uint8_t *src, size_t src_len,
                           uint32_t *result_buf, size_t *lengthp);
--- a/liboctave/wrappers/wait-wrappers.c	Thu Nov 19 13:05:51 2020 -0800
+++ b/liboctave/wrappers/wait-wrappers.c	Thu Nov 19 13:08:00 2020 -0800
@@ -35,6 +35,10 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 
+#if defined (__WIN32__) && ! defined (__CYGWIN__)
+#  include <windows.h>
+#endif
+
 #include "wait-wrappers.h"
 
 #if ! defined (WCONTINUE)
@@ -57,14 +61,42 @@
 octave_waitpid_wrapper (pid_t pid, int *statusp, int options)
 {
 #if defined (__WIN32__) && ! defined (__CYGWIN__)
+  // gnulib's waitpid replacement currently uses _cwait, which
+  // apparently only works with console applications.
+  // Implement our own wrapper using win32 API functions.
 
-  octave_unused_parameter (pid);
   octave_unused_parameter (options);
 
-  // gnulib's waitpid replacement currently uses _cwait, which
-  // apparently only works with console applications.
-  *statusp = 0;
-  return -1;
+  pid_t retval = -1;
+  DWORD status = 0;
+
+  HANDLE hProcess = OpenProcess (PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
+                                 false, pid);
+
+  if (! hProcess)
+    return retval;
+
+  if (WaitForSingleObject (hProcess, INFINITE) != WAIT_OBJECT_0)
+    {
+      CloseHandle (hProcess);
+      return retval;
+    }
+
+  if (! GetExitCodeProcess (hProcess, &status))
+    {
+      CloseHandle (hProcess);
+      return retval;
+    }
+
+  CloseHandle (hProcess);
+
+  if (statusp)
+    *statusp = status;
+
+  retval = pid;
+
+  return retval;
+
 #else
   return waitpid (pid, statusp, options);
 #endif
--- a/m4/acinclude.m4	Thu Nov 19 13:05:51 2020 -0800
+++ b/m4/acinclude.m4	Thu Nov 19 13:08:00 2020 -0800
@@ -369,86 +369,6 @@
   fi
 ])
 dnl
-dnl Check whether the Qt class QAbstractItemModel exists and has the
-dnl beginResetModel and endResetModel member functions.  These member
-dnl functions were introduced in Qt 4.6.
-dnl
-dnl FIXME: Delete this entirely when we can safely assume that Qt 4.6 or later
-dnl is in use everywhere, or when we drop support for Qt 4.
-dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QABSTRACTITEMMODEL_BEGINRESETMODEL], [
-  AC_CACHE_CHECK([for QAbstractItemModel::beginResetModel in <QAbstractItemModel>],
-    [octave_cv_func_qabstractitemmodel_beginresetmodel],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QAbstractItemModel>
-        class item_model : public QAbstractItemModel
-        {
-        public:
-          item_model (QObject *parent = 0) : QAbstractItemModel (parent) {}
-          ~item_model () {}
-          QModelIndex index (int, int, const QModelIndex& m) const { return m; }
-          QModelIndex parent (const QModelIndex& m) const { return m; }
-          int columnCount (const QModelIndex&) const { return 0; }
-          int rowCount (const QModelIndex&) const { return 0; }
-          QVariant data (const QModelIndex&, int) const { return QVariant(); }
-          void update_model ()
-          {
-            this->beginResetModel ();
-            this->endResetModel ();
-          }
-        };
-        ]], [[
-        item_model model;
-        model.update_model ();
-        ]])],
-      octave_cv_func_qabstractitemmodel_beginresetmodel=yes,
-      octave_cv_func_qabstractitemmodel_beginresetmodel=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_func_qabstractitemmodel_beginresetmodel = yes; then
-    AC_DEFINE(HAVE_QABSTRACTITEMMODEL_BEGINRESETMODEL, 1,
-      [Define to 1 if you have the `QAbstractItemModel::beginResetModel' member function.])
-  fi
-])
-dnl
-dnl Check whether the Qt QComboBox class has the setCurrentText
-dnl function.  This function was introduced in Qt 5.
-dnl
-dnl FIXME: Delete this entirely when we drop support for Qt 4.
-dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QCOMBOBOX_SETCURRENTTEXT], [
-  AC_CACHE_CHECK([for QComboBox::setCurrentText],
-    [octave_cv_func_qcombobox_setcurrenttext],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CPPFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QComboBox>
-        ]], [[
-        QComboBox combo_box (nullptr);
-        combo_box.setCurrentText ("text");
-        ]])],
-      octave_cv_func_qcombobox_setcurrenttext=yes,
-      octave_cv_func_qcombobox_setcurrenttext=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_func_qcombobox_setcurrenttext = yes; then
-    AC_DEFINE(HAVE_QCOMBOBOX_SETCURRENTTEXT, 1,
-      [Define to 1 if you have the `QComboBox::setCurrentText' member function.])
-  fi
-])
-dnl
 dnl Check whether the Qt QGuiApplication class has the setDesktopFileName
 dnl static member function.  This function was introduced in Qt 5.7.
 dnl
@@ -479,99 +399,6 @@
   fi
 ])
 dnl
-dnl Check whether the Qt QHeaderView class has the setSectionResizeMode
-dnl function.  This function was introduced in Qt 5.
-dnl
-dnl FIXME: Delete this entirely when we drop support for Qt 4.
-dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QHEADERVIEW_SETSECTIONRESIZEMODE], [
-  AC_CACHE_CHECK([for QHeaderView::setSectionResizeMode],
-    [octave_cv_func_qheaderview_setsectionresizemode],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CPPFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QHeaderView>
-        ]], [[
-        QHeaderView header_view (Qt::Horizontal);
-        header_view.setSectionResizeMode (QHeaderView::Interactive);
-        ]])],
-      octave_cv_func_qheaderview_setsectionresizemode=yes,
-      octave_cv_func_qheaderview_setsectionresizemode=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_func_qheaderview_setsectionresizemode = yes; then
-    AC_DEFINE(HAVE_QHEADERVIEW_SETSECTIONRESIZEMODE, 1,
-      [Define to 1 if you have the `QHeaderView::setSectionResizeMode' member function.])
-  fi
-])
-dnl
-dnl Check whether the Qt QHeaderView class has the setSectionsClickable
-dnl function.  This function was introduced in Qt 5.
-dnl
-dnl FIXME: Delete this entirely when we drop support for Qt 4.
-dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QHEADERVIEW_SETSECTIONSCLICKABLE], [
-  AC_CACHE_CHECK([for QHeaderView::setSectionsClickable],
-    [octave_cv_func_qheaderview_setsectionsclickable],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CPPFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QHeaderView>
-        ]], [[
-        QHeaderView header_view (Qt::Horizontal);
-        header_view.setSectionsClickable (true);
-        ]])],
-      octave_cv_func_qheaderview_setsectionsclickable=yes,
-      octave_cv_func_qheaderview_setsectionsclickable=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_func_qheaderview_setsectionsclickable = yes; then
-    AC_DEFINE(HAVE_QHEADERVIEW_SETSECTIONSCLICKABLE, 1,
-      [Define to 1 if you have the `QHeaderView::setSectionsClickable' member function.])
-  fi
-])
-dnl
-dnl Check whether the Qt QHeaderView class has the setSectionsMovable
-dnl function.  This function was introduced in Qt 5.
-dnl
-dnl FIXME: Delete this entirely when we drop support for Qt 4.
-dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QHEADERVIEW_SETSECTIONSMOVABLE], [
-  AC_CACHE_CHECK([for QHeaderView::setSectionsMovable],
-    [octave_cv_func_qheaderview_setsectionsmovable],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CPPFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QHeaderView>
-        ]], [[
-        QHeaderView header_view (Qt::Horizontal);
-        header_view.setSectionsMovable (true);
-        ]])],
-      octave_cv_func_qheaderview_setsectionsmovable=yes,
-      octave_cv_func_qheaderview_setsectionsmovable=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_func_qheaderview_setsectionsmovable = yes; then
-    AC_DEFINE(HAVE_QHEADERVIEW_SETSECTIONSMOVABLE, 1,
-      [Define to 1 if you have the `QHeaderView::setSectionsMovable' member function.])
-  fi
-])
-dnl
 dnl Check whether the Qt QHelpSearchQueryWidget class has the searchInput
 dnl member function.  This function was introduced in Qt 5.9.
 dnl
@@ -636,133 +463,6 @@
   fi
 ])
 dnl
-dnl Check whether the Qt function qInstallMessageHandler is available.
-dnl This function was introduced in Qt 5.
-dnl
-dnl FIXME: Delete this entirely when we drop support for Qt 4.
-dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QINSTALLMESSAGEHANDLER], [
-  AC_CACHE_CHECK([for qInstallMessageHandler],
-    [octave_cv_func_qinstallmessagehandler],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CPPFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QtGlobal>
-        ]], [[
-        qInstallMessageHandler (nullptr);
-        ]])],
-      octave_cv_func_qinstallmessagehandler=yes,
-      octave_cv_func_qinstallmessagehandler=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_func_qinstallmessagehandler = yes; then
-    AC_DEFINE(HAVE_QINSTALLMESSAGEHANDLER, 1,
-      [Define to 1 if you have the `qInstallMessageHandler' function.])
-  fi
-])
-dnl
-dnl Check whether the Qt class QLineEdit has the setPlaceholderText member
-dnl function.  This member function was introduced in Qt 4.7.
-dnl
-dnl FIXME: Delete this entirely when we can safely assume that Qt 4.7 or later
-dnl is in use everywhere, or when we drop support for Qt 4.
-dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QLINEEDIT_SETPLACEHOLDERTEXT], [
-  AC_CACHE_CHECK([for QLineEdit::setPlaceholderText in <QLinedEdit>],
-    [octave_cv_func_qlineedit_setplaceholdertext],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CPPFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QLineEdit>
-        ]], [[
-        QLineEdit line_edit;
-        line_edit.setPlaceholderText ("placeholder text");
-        ]])],
-      octave_cv_func_qlineedit_setplaceholdertext=yes,
-      octave_cv_func_qlineedit_setplaceholdertext=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_func_qlineedit_setplaceholdertext = yes; then
-    AC_DEFINE(HAVE_QLINEEDIT_SETPLACEHOLDERTEXT, 1,
-      [Define to 1 if you have the `QLineEdit::setPlaceholderText' member function.])
-  fi
-])
-dnl
-dnl Check whether the Qt QMouseEvent class has the localPos function.
-dnl This function was introduced in Qt 5.
-dnl
-dnl FIXME: Delete this entirely when we drop support for Qt 4.
-dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QMOUSEEVENT_LOCALPOS], [
-  AC_CACHE_CHECK([for QMouseEvent::localPos],
-    [octave_cv_func_qmouseevent_localpos],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CPPFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QMouseEvent>
-        ]], [[
-        QMouseEvent *event;
-        event->localPos ();
-        ]])],
-      octave_cv_func_qmouseevent_localpos=yes,
-      octave_cv_func_qmouseevent_localpos=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_func_qmouseevent_localpos = yes; then
-    AC_DEFINE(HAVE_QMOUSEEVENT_LOCALPOS, 1,
-      [Define to 1 if you have the `QMouseEvent::localPos' member function.])
-  fi
-])
-dnl
-dnl Check whether QObject::findChildren accepts Qt::FindChildOptions
-dnl argument.
-dnl
-dnl FIXME: Delete this entirely when we drop support for Qt 4.
-dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QOBJECT_FINDCHILDREN_ACCEPTS_FINDCHILDOPTIONS], [
-  AC_CACHE_CHECK([whether QObject::findChildren accepts Qt::FindChildOptions],
-    [octave_cv_func_qobject_findchildren_accepts_findchildoptions],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QList>
-        #include <QObject>
-        #include <QWidget>
-        ]], [[
-        QObject obj;
-        QList<QWidget *> widgets
-          = obj.findChildren<QWidget *> ("name", Qt::FindDirectChildrenOnly);
-        ]])],
-      octave_cv_func_qobject_findchildren_accepts_findchildoptions=yes,
-      octave_cv_func_qobject_findchildren_accepts_findchildoptions=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_func_qobject_findchildren_accepts_findchildoptions = yes; then
-    AC_DEFINE(QOBJECT_FINDCHILDREN_ACCEPTS_FINDCHILDOPTIONS, 1,
-      [Define to 1 if 'QObject::findChildren' accepts 'Qt::FindChildOptions' argument.])
-  fi
-])
-dnl
 dnl Check whether the Qt class QScreen has the devicePixelRatio member function.
 dnl This member function was introduced in Qt 5.5.
 dnl
@@ -793,43 +493,6 @@
   fi
 ])
 dnl
-dnl Check whether the Qt class QTabWidget has the setMovable member function.
-dnl This member function was introduced in Qt 4.5.
-dnl
-dnl FIXME: Delete this entirely when we can safely assume that Qt 4.5 or later
-dnl is in use everywhere, or when we drop support for Qt 4.
-dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QTABWIDGET_SETMOVABLE], [
-  AC_CACHE_CHECK([for QTabWidget::setMovable in <QTabWidget>],
-    [octave_cv_func_qtabwidget_setmovable],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QTabWidget>
-        class tab_widget : public QTabWidget
-        {
-        public:
-          tab_widget (QWidget *parent = 0) : QTabWidget (parent) { this->setMovable (true); }
-          ~tab_widget () {}
-        };
-        ]], [[
-        tab_widget tw;
-        ]])],
-      octave_cv_func_qtabwidget_setmovable=yes,
-      octave_cv_func_qtabwidget_setmovable=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_func_qtabwidget_setmovable = yes; then
-    AC_DEFINE(HAVE_QTABWIDGET_SETMOVABLE, 1,
-      [Define to 1 if you have the `QTabWidget::setMovable' member function.])
-  fi
-])
-dnl
 dnl Check whether the Qt class QHelpEngine has the documentsForIdentifier
 dnl function.  dnl This member function was introduced in Qt 5.15.
 dnl
@@ -927,39 +590,6 @@
   fi
 ])
 dnl
-dnl Check whether Qt message handler function accepts QMessageLogContext
-dnl argument.  This change was introduced in Qt 5.
-dnl
-dnl FIXME: Delete this entirely when we drop support for Qt 4.
-dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QTMESSAGEHANDLER_ACCEPTS_QMESSAGELOGCONTEXT], [
-  AC_CACHE_CHECK([whether Qt message handler accepts QMessageLogContext],
-    [octave_cv_func_qtmessagehandler_accepts_qmessagelogcontext],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QtGlobal>
-        static void
-        msg_handler (QtMsgType, const QMessageLogContext &, const QString &)
-        { }
-        ]], [[
-        QtMessageHandler fptr = msg_handler;
-        ]])],
-      octave_cv_func_qtmessagehandler_accepts_qmessagelogcontext=yes,
-      octave_cv_func_qtmessagehandler_accepts_qmessagelogcontext=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_func_qtmessagehandler_accepts_qmessagelogcontext = yes; then
-    AC_DEFINE(QTMESSAGEHANDLER_ACCEPTS_QMESSAGELOGCONTEXT, 1,
-      [Define to 1 if Qt message handler accepts 'QMessageLogContext' argument.])
-  fi
-])
-dnl
 dnl Check whether the Qt class QList has a constructor that accepts
 dnl a pair of iterators.  This constructor was introduced in Qt 5.14.
 dnl
@@ -989,6 +619,39 @@
   fi
 ])
 dnl
+dnl Check whether the Qt class QList has a constructor that accepts
+dnl a pair of iterators.  This constructor was introduced in Qt 5.14.
+dnl
+AC_DEFUN([OCTAVE_CHECK_FUNC_QFONTMETRICS_HORIZONTAL_ADVANCE], [
+  AC_CACHE_CHECK([for QFontMetrics::horizontalAdvance function],
+    [octave_cv_func_qfontmetrics_horizontal_advance],
+    [AC_LANG_PUSH(C++)
+    ac_octave_save_CPPFLAGS="$CPPFLAGS"
+    ac_octave_save_CXXFLAGS="$CXXFLAGS"
+    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
+    CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
+    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+        #include <QFont>
+        #include <QFontMetrics>
+        #include <QString>
+        ]], [[
+        QFont font;
+        QFontMetrics fm (font);
+        fm.horizontalAdvance ('x');
+        fm.horizontalAdvance (QString ("string"));
+        ]])],
+      octave_cv_func_qfontmetrics_horizontal_advance=yes,
+      octave_cv_func_qfontmetrics_horizontal_advance=no)
+    CPPFLAGS="$ac_octave_save_CPPFLAGS"
+    CXXFLAGS="$ac_octave_save_CXXFLAGS"
+    AC_LANG_POP(C++)
+  ])
+  if test $octave_cv_func_qfontmetrics_horizontal_advance = yes; then
+    AC_DEFINE(HAVE_QFONTMETRICS_HORIZONTAL_ADVANCE, 1,
+      [Define to 1 if you have the `QFontMetrics::horizontalAdvance' function.])
+  fi
+])
+dnl
 dnl Check whether the Qt class QRegion has the iterators and related
 dnl functions introduced in Qt 5.8.
 dnl
@@ -1057,39 +720,6 @@
   fi
 ])
 dnl
-dnl Check whether the Qt class QList has a constructor that accepts
-dnl a pair of iterators.  This constructor was introduced in Qt 5.14.
-dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QFONTMETRICS_HORIZONTAL_ADVANCE], [
-  AC_CACHE_CHECK([for QFontMetrics::horizontalAdvance function],
-    [octave_cv_func_qfontmetrics_horizontal_advance],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QFont>
-        #include <QFontMetrics>
-        #include <QString>
-        ]], [[
-        QFont font;
-        QFontMetrics fm (font);
-        fm.horizontalAdvance ('x');
-        fm.horizontalAdvance (QString ("string"));
-        ]])],
-      octave_cv_func_qfontmetrics_horizontal_advance=yes,
-      octave_cv_func_qfontmetrics_horizontal_advance=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_func_qfontmetrics_horizontal_advance = yes; then
-    AC_DEFINE(HAVE_QFONTMETRICS_HORIZONTAL_ADVANCE, 1,
-      [Define to 1 if you have the `QFontMetrics::horizontalAdvance' function.])
-  fi
-])
-dnl
 dnl Check whether HDF5 library has version 1.6 API functions.
 dnl
 AC_DEFUN([OCTAVE_CHECK_HDF5_HAS_VER_16_API], [
@@ -1143,7 +773,7 @@
     no)
       ifelse([$#], 10,
         [AC_MSG_ERROR([--without-m4_tolower($1) specified but $2 is required.])],
-        [warn_$1="--without-m4_tolower($1) specified.  Functions or features that depend on $2 will be disabled."
+        [warn_$1=""
          m4_toupper([$1])_LIBS=])
     ;;
     yes | "")
@@ -1871,68 +1501,6 @@
   AC_SUBST(TERM_LIBS)
 ])
 dnl
-dnl Check whether the Qt class QFont has the ForceIntegerMetrics enumerated
-dnl type member.  This property was introduced in Qt 4.7.
-dnl
-dnl FIXME: Delete this entirely when we can safely assume that Qt 4.7 or later
-dnl is in use everywhere, or when we drop support for Qt 4.
-dnl
-AC_DEFUN([OCTAVE_CHECK_MEMBER_QFONT_FORCE_INTEGER_METRICS], [
-  AC_CACHE_CHECK([for QFont::ForceIntegerMetrics in <QFont>],
-    [octave_cv_decl_qfont_force_integer_metrics],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QFont>
-        ]], [[
-        QFont::StyleStrategy strategy = QFont::ForceIntegerMetrics;
-        ]])],
-      octave_cv_decl_qfont_force_integer_metrics=yes,
-      octave_cv_decl_qfont_force_integer_metrics=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_decl_qfont_force_integer_metrics = yes; then
-    AC_DEFINE(HAVE_QFONT_FORCE_INTEGER_METRICS, 1,
-      [Define to 1 if `ForceIntegerMetrics' is a member of `QFont'.])
-  fi
-])
-dnl
-dnl Check whether the Qt class QFont has the Monospace enumerated type member.
-dnl This property was introduced in Qt 4.7.
-dnl
-dnl FIXME: Delete this entirely when we can safely assume that Qt 4.7 or later
-dnl is in use everywhere, or when we drop support for Qt 4.
-dnl
-AC_DEFUN([OCTAVE_CHECK_MEMBER_QFONT_MONOSPACE], [
-  AC_CACHE_CHECK([for QFont::Monospace in <QFont>],
-    [octave_cv_decl_qfont_monospace],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QFont>
-        ]], [[
-        QFont::StyleHint hint = QFont::Monospace;
-        ]])],
-      octave_cv_decl_qfont_monospace=yes,
-      octave_cv_decl_qfont_monospace=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_decl_qfont_monospace = yes; then
-    AC_DEFINE(HAVE_QFONT_MONOSPACE, 1,
-      [Define to 1 if `Monospace' is a member of `QFont'.])
-  fi
-])
-dnl
 dnl Check for the Qhull version.
 dnl
 AC_DEFUN([OCTAVE_CHECK_QHULL_VERSION], [
@@ -1987,9 +1555,6 @@
 
   ## Check for Qt libraries
   case "$qt_version" in
-    4)
-      octave_qscintilla_libnames="qscintilla2-qt4 qscintilla2_qt4 qt4scintilla2 qscintilla2"
-    ;;
     5)
       octave_qscintilla_libnames="qscintilla2-qt5 qscintilla2_qt5 qt5scintilla2"
     ;;
@@ -2115,11 +1680,6 @@
 
   if test $build_qt_gui = yes; then
     BUILD_QT_SUMMARY_MSG="yes (version: $have_qt_version)"
-    if test x"$have_qt_version" = x4; then
-      AC_DEFINE(HAVE_QT4, 1, [Define to 1 if using Qt version 4.])
-      warn_qt_ver="Use of Qt version 4 is deprecated.  Support will be removed in Octave version 7."
-      OCTAVE_CONFIGURE_WARNING([warn_qt_ver])
-    fi
     if test x"$have_qt_version" = x5; then
       AC_DEFINE(HAVE_QT5, 1, [Define to 1 if using Qt version 5.])
     fi
@@ -2327,10 +1887,6 @@
 
   ## Check for Qt libraries
   case "$qt_version" in
-    4)
-      QT_OPENGL_MODULE="QtOpenGL"
-      QT_MODULES="QtCore QtGui QtNetwork QtHelp QtXml"
-    ;;
     5)
       QT_OPENGL_MODULE="Qt5OpenGL"
       QT_MODULES="Qt5Core Qt5Gui Qt5Network Qt5PrintSupport Qt5Help Qt5Xml"
@@ -2382,14 +1938,6 @@
         fi
       ;;
     esac
-
-    if test $qt_version = 4; then
-      ## Check for Qt4
-      if ! `$PKG_CONFIG --atleast-version=4.0.0 QtCore`; then
-        build_qt_gui=no
-        warn_qt_version="Qt >= 4.0.0 not found; disabling Qt GUI"
-      fi
-    fi
   fi
 
   QT_TOOLS_AVAILABLE=
@@ -2454,18 +2002,6 @@
   fi
 
   if test $build_qt_gui = yes; then
-    OCTAVE_CHECK_FUNC_QABSTRACTITEMMODEL_BEGINRESETMODEL
-
-    if test $octave_cv_func_qabstractitemmodel_beginresetmodel = no; then
-      build_qt_gui=no
-      warn_qt_abstract_item_model="QAbstractItemModel::beginResetModel not found; disabling Qt GUI"
-      ## Invalidate cache so that this test will be done again if we
-      ## perform the test with a different Qt version.
-      $as_unset octave_cv_func_qabstractitemmodel_beginresetmodel
-    fi
-  fi
-
-  if test $build_qt_gui = yes; then
     ## We have what we need to build the Qt GUI.  The remaining
     ## checks below are for optional features related to the Qt GUI.
 
@@ -2483,28 +2019,15 @@
     ## tests if they fail because we have already decided that the Qt
     ## version that we are testing now will be the one used.
 
-    OCTAVE_CHECK_FUNC_QCOMBOBOX_SETCURRENTTEXT
     OCTAVE_CHECK_FUNC_QFONTMETRICS_HORIZONTAL_ADVANCE
     OCTAVE_CHECK_FUNC_QGUIAPPLICATION_SETDESKTOPFILENAME
-    OCTAVE_CHECK_FUNC_QHEADERVIEW_SETSECTIONRESIZEMODE
-    OCTAVE_CHECK_FUNC_QHEADERVIEW_SETSECTIONSCLICKABLE
-    OCTAVE_CHECK_FUNC_QHEADERVIEW_SETSECTIONSMOVABLE
     OCTAVE_CHECK_FUNC_QHELPSEARCHQUERYWIDGET_SEARCHINPUT
     OCTAVE_CHECK_NEW_QHELPINDEXWIDGET_API
-    OCTAVE_CHECK_FUNC_QINSTALLMESSAGEHANDLER
-    OCTAVE_CHECK_FUNC_QLINEEDIT_SETPLACEHOLDERTEXT
     OCTAVE_CHECK_FUNC_QLIST_ITERATOR_CONSTRUCTOR
-    OCTAVE_CHECK_FUNC_QMOUSEEVENT_LOCALPOS
-    OCTAVE_CHECK_FUNC_QOBJECT_FINDCHILDREN_ACCEPTS_FINDCHILDOPTIONS
     OCTAVE_CHECK_FUNC_QSCREEN_DEVICEPIXELRATIO
-    OCTAVE_CHECK_FUNC_QTABWIDGET_SETMOVABLE
-    OCTAVE_CHECK_FUNC_QTMESSAGEHANDLER_ACCEPTS_QMESSAGELOGCONTEXT
     OCTAVE_CHECK_FUNC_QHELPENGINE_DOCUMENTSFORIDENTIFIER
     OCTAVE_CHECK_FUNC_QWHEELEVENT_ANGLEDELTA
     OCTAVE_CHECK_FUNC_QWHEELEVENT_POSITION
-    OCTAVE_CHECK_MEMBER_QFONT_FORCE_INTEGER_METRICS
-    OCTAVE_CHECK_MEMBER_QFONT_MONOSPACE
-    OCTAVE_HAVE_QGUIAPPLICATION
 
     OCTAVE_CHECK_QREGION_ITERATORS
     OCTAVE_CHECK_QT_SPLITBEHAVIOR_ENUM
@@ -2578,7 +2101,7 @@
   ac_octave_save_LIBS=$LIBS
   LIBS="$SUNDIALS_IDA_LIBS $SUNDIALS_NVECSERIAL_LIBS $LIBS"
   dnl Current API functions present in SUNDIALS version 4
-  AC_CHECK_FUNCS([IDASetJacFn IDASetLinearSolver SUNLinSol_Dense])
+  AC_CHECK_FUNCS([IDASetJacFn IDASetLinearSolver SUNLinSol_Dense SUNSparseMatrix_Reallocate])
   dnl FIXME: The purpose of the following tests is to detect the deprecated
   dnl API from SUNDIALS version 3, which should only be used if the current
   dnl API tests above failed. For now, always test for ida_direct.h.
@@ -2952,36 +2475,6 @@
   fi
 ])
 dnl
-dnl Check whether the Qt class QGuiApplication exists.
-dnl This class  was introduced in Qt 5.0.
-dnl
-dnl FIXME: Delete this entirely when we drop support for Qt 4.
-dnl
-AC_DEFUN([OCTAVE_HAVE_QGUIAPPLICATION], [
-  AC_CACHE_CHECK([for QGuiApplication],
-    [octave_cv_decl_qguiapplication],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QGuiApplication>
-        ]], [[
-        QScreen *pscreen = QGuiApplication::primaryScreen ();
-        ]])],
-      octave_cv_decl_qguiapplication=yes,
-      octave_cv_decl_qguiapplication=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_decl_qguiapplication = yes; then
-    AC_DEFINE(HAVE_QGUIAPPLICATION, 1,
-      [Define to 1 if `QGuiApplication' class is available.])
-  fi
-])
-dnl
 dnl Check for IEEE 754 data format.
 dnl
 AC_DEFUN([OCTAVE_IEEE754_DATA_FORMAT], [
--- a/scripts/+matlab/+lang/makeUniqueStrings.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/+matlab/+lang/makeUniqueStrings.m	Thu Nov 19 13:08:00 2020 -0800
@@ -57,7 +57,7 @@
 
 function [uniqstr, ismodified] = makeUniqueStrings (str, ex = {}, maxlength = Inf)
 
-  if (nargin == 0 || nargout > 3)
+  if (nargin == 0)
     print_usage ();
   endif
 
@@ -228,8 +228,7 @@
 %! assert (uniqstr, {"a_1","a_2","a_4","a_6","a_5"});
 
 ## Test input validation
-%!error matlab.lang.makeUniqueStrings ()
-%!error [a, b, c] = matlab.lang.makeUniqueStrings ("a");
+%!error <Invalid call> matlab.lang.makeUniqueStrings ()
 %!error <STR must be a string or cellstr> matlab.lang.makeUniqueStrings (1)
 %!error <STR and EX logical array must have the same length>
 %! matlab.lang.makeUniqueStrings ("a", [true false]);
--- a/scripts/+matlab/+lang/makeValidName.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/+matlab/+lang/makeValidName.m	Thu Nov 19 13:08:00 2020 -0800
@@ -67,7 +67,7 @@
 
 function [varname, ismodified] = makeValidName (str, varargin)
 
-  if (nargin == 0 || nargout > 2)
+  if (nargin == 0)
     print_usage ();
   endif
 
@@ -218,7 +218,7 @@
 %!error matlab.lang.makeValidName ("for", "Prefix", "for")
 
 ## Test input validation
-%!error matlab.lang.makeValidName ()
+%!error <Invalid call> matlab.lang.makeValidName ()
 %!error <STR must be a string or cellstr> matlab.lang.makeValidName (42)
 %!error <options must occur in pairs> matlab.lang.makeValidName ("a", "opt1")
 %!error <option argument must be a string>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/+matlab/+net/base64decode.m	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,64 @@
+########################################################################
+##
+## Copyright (C) 2020 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn  {} {@var{out_vec} =} matlab.net.base64decode (@var{b64_str})
+##
+## Convert base64 encoded @var{b64_str} to uint8 vector @var{out_vec}.
+##
+## The input @var{b64_str} must be a string vector.
+## The output @var{out_vec} will be a uint8 vector that is decoded
+## according to RFC 4648.
+##
+## @seealso{matlab.net.base64encode, base64_decode, base64_encode, native2unicode}
+## @end deftypefn
+
+function out_vec = base64decode (b64_str)
+
+  if (nargin != 1)
+    print_usage ();
+  endif
+
+  if (! isvector (b64_str) || ! ischar (b64_str))
+    error ("base64decode: B64_STR must be a base64 encoded character vector");
+  endif
+
+  out_vec = uint8 (__base64_decode_bytes__ (b64_str));
+
+endfunction
+
+
+## Test char vector input
+%!assert (matlab.net.base64decode ("AQ=="), uint8 (1));
+%!assert (matlab.net.base64decode ("/w=="), uint8 (255));
+%!assert (matlab.net.base64decode ("AQID"), uint8 (1:3));
+%!assert (matlab.net.base64decode ("YQ=="), uint8 ("a"));
+%!assert (matlab.net.base64decode ("YWJjZGVmZw=="), uint8 ("abcdefg"));
+
+## Test input validation
+%!error <Invalid call> matlab.net.base64decode ()
+%!error <character vector> matlab.net.base64decode (pi)
+%!error <character vector> matlab.net.base64decode ({1,2})
+%!error <character vector> matlab.net.base64decode ([1,2;3,4])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/+matlab/+net/base64encode.m	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,67 @@
+########################################################################
+##
+## Copyright (C) 2020 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn  {} {@var{b64_str} =} matlab.net.base64encode (@var{in})
+##
+## Convert @var{in} to a base64 encoded string @var{b64_str}.
+##
+## The input @var{in} can be a string or numeric vector.
+## The output @var{b64_str} will be encoded according to RFC 4648.
+##
+## @seealso{matlab.net.base64decode, base64_decode, base64_encode, unicode2native}
+## @end deftypefn
+
+function b64_str = base64encode (in)
+
+  if (nargin != 1)
+    print_usage ();
+  endif
+
+  if (! isvector (in) || ! (isnumeric (in) || ischar (in)))
+    error ("base64encode: IN must be a numeric or character vector");
+  endif
+
+  if (any (in != round (in)))
+    error ("base64encode: IN must consist of integers");
+  endif
+
+  b64_str = base64_encode (uint8 (in));
+
+endfunction
+
+
+## Test char vector input
+%!assert (matlab.net.base64encode (1), "AQ==");
+%!assert (matlab.net.base64encode (255), "/w==");
+%!assert (matlab.net.base64encode (1:3), "AQID");
+%!assert (matlab.net.base64encode ("a"), "YQ==");
+%!assert (matlab.net.base64encode ("abcdefg"), "YWJjZGVmZw==");
+
+## Test input validation
+%!error <Invalid call> matlab.net.base64encode ()
+%!error <numeric or character vector> matlab.net.base64encode ({1,2})
+%!error <numeric or character vector> matlab.net.base64encode ([1,2;3,4])
+%!error <consist of integers> matlab.net.base64encode (pi)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/+matlab/+net/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,15 @@
+FCN_FILE_DIRS += %reldir%
+
+%canon_reldir%_FCN_FILES = \
+  %reldir%/base64decode.m \
+  %reldir%/base64encode.m
+
+%canon_reldir%dir = $(fcnfiledir)/+matlab/+net
+
+%canon_reldir%_DATA = $(%canon_reldir%_FCN_FILES)
+
+FCN_FILES += $(%canon_reldir%_FCN_FILES)
+
+PKG_ADD_FILES += %reldir%/PKG_ADD
+
+DIRSTAMP_FILES += %reldir%/$(octave_dirstamp)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/@ftp/cd.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/@ftp/cd.m	Thu Nov 19 13:08:00 2020 -0800
@@ -40,7 +40,7 @@
 
 function path = cd (f, path)
 
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/@ftp/disp.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/@ftp/disp.m	Thu Nov 19 13:08:00 2020 -0800
@@ -25,7 +25,7 @@
 
 function disp (obj)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/audio/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/audio/@audioplayer/__get_properties__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/audio/@audioplayer/__get_properties__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function props = __get_properties__ (player)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/audio/@audioplayer/disp.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/audio/@audioplayer/disp.m	Thu Nov 19 13:08:00 2020 -0800
@@ -30,7 +30,7 @@
 
 function disp (player)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/audio/@audioplayer/isplaying.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/audio/@audioplayer/isplaying.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function result = isplaying (player)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/audio/@audioplayer/pause.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/audio/@audioplayer/pause.m	Thu Nov 19 13:08:00 2020 -0800
@@ -30,7 +30,7 @@
 
 function pause (player)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/audio/@audioplayer/resume.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/audio/@audioplayer/resume.m	Thu Nov 19 13:08:00 2020 -0800
@@ -30,7 +30,7 @@
 
 function resume (player)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/audio/@audioplayer/stop.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/audio/@audioplayer/stop.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function stop (player)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/audio/@audiorecorder/__get_properties__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/audio/@audiorecorder/__get_properties__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function props = __get_properties__ (recorder)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/audio/@audiorecorder/audiorecorder.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/audio/@audiorecorder/audiorecorder.m	Thu Nov 19 13:08:00 2020 -0800
@@ -88,14 +88,14 @@
 %! assert (size (data)(2), 2);
 
 %!testif HAVE_PORTAUDIO; audiodevinfo (1) > 0
-%! recorder = audiorecorder;
+%! recorder = audiorecorder ();
 %! set (recorder, {"SampleRate", "Tag", "UserData"}, {8000, "tag", [1, 2; 3, 4]});
 %! assert (recorder.SampleRate, 8000);
 %! assert (recorder.Tag, "tag");
 %! assert (recorder.UserData, [1, 2; 3, 4]);
 
 %!testif HAVE_PORTAUDIO; audiodevinfo (1) > 0
-%! recorder = audiorecorder;
+%! recorder = audiorecorder ();
 %! settable = set (recorder);
 %! settable.SampleRate = 8000;
 %! settable.Tag = "tag";
@@ -106,7 +106,7 @@
 %! assert (recorder.UserData, [1, 2; 3, 4]);
 
 %!testif HAVE_PORTAUDIO; audiodevinfo (1) > 0
-%! recorder = audiorecorder;
+%! recorder = audiorecorder ();
 %! recorder.SampleRate = 8000;
 %! recorder.Tag = "tag";
 %! recorder.UserData = [1, 2; 3, 4];
--- a/scripts/audio/@audiorecorder/disp.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/audio/@audiorecorder/disp.m	Thu Nov 19 13:08:00 2020 -0800
@@ -30,7 +30,7 @@
 
 function disp (recorder)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/audio/@audiorecorder/isrecording.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/audio/@audiorecorder/isrecording.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function result = isrecording (recorder)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/audio/@audiorecorder/pause.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/audio/@audiorecorder/pause.m	Thu Nov 19 13:08:00 2020 -0800
@@ -30,7 +30,7 @@
 
 function pause (recorder)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/audio/@audiorecorder/resume.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/audio/@audiorecorder/resume.m	Thu Nov 19 13:08:00 2020 -0800
@@ -30,7 +30,7 @@
 
 function resume (recorder)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/audio/@audiorecorder/stop.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/audio/@audiorecorder/stop.m	Thu Nov 19 13:08:00 2020 -0800
@@ -30,7 +30,7 @@
 
 function stop (recorder)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/audio/lin2mu.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/audio/lin2mu.m	Thu Nov 19 13:08:00 2020 -0800
@@ -39,6 +39,10 @@
 
 function y = lin2mu (x, n)
 
+  if (nargin < 1)
+    print_usage ();
+  endif
+
   if (nargin == 1)
     range = max (abs (x (:)));
     if (range <= 1)
@@ -49,12 +53,10 @@
     else
       n = 16;
     endif
-  elseif (nargin == 2)
+  else
     if (n != 0 && n != 8 && n != 16)
       error ("lin2mu: N must be either 0, 8 or 16");
     endif
-  else
-    print_usage ();
   endif
 
   ## Transform real and n-bit format to 16-bit.
--- a/scripts/audio/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/audio/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -4,6 +4,7 @@
   %reldir%/@audiorecorder
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/lin2mu.m \
   %reldir%/mu2lin.m \
   %reldir%/record.m \
--- a/scripts/audio/mu2lin.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/audio/mu2lin.m	Thu Nov 19 13:08:00 2020 -0800
@@ -37,14 +37,14 @@
 
 function y = mu2lin (x, n = 0)
 
-  if (nargin == 2)
-    if (n != 0 && n != 8 && n != 16)
-      error ("mu2lin: N must be either 0, 8, or 16");
-    endif
-  elseif (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
+  if (n != 0 && n != 8 && n != 16)
+    error ("mu2lin: N must be either 0, 8, or 16");
+  endif
+
   ulaw = [32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, ...
           23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, ...
           15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, ...
--- a/scripts/audio/record.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/audio/record.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,19 +36,17 @@
 ## @seealso{sound, soundsc}
 ## @end deftypefn
 
-function x = record (sec, fs)
+function x = record (sec, fs = 8000)
 
-  if (nargin == 1)
-    fs = 8000;
-  elseif (nargin != 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
-  if (! (isscalar (sec) && (sec >= 0)))
+  if (! (isscalar (sec) && sec >= 0))
     error ("record: recording duration SEC must be a non-negative number");
   endif
 
-  if (! (isscalar (fs) && (fs > 0)))
+  if (! (isscalar (fs) && fs > 0))
     error ("record: sample rate FS must be a positive number");
   endif
 
@@ -68,11 +66,10 @@
 
 
 ## Tests of record must not actually record anything.
-
 %!assert (isempty (record (0)))
 
 ## Test input validation
-%!error record ()
-%!error record (1,2,3)
-%!error record (-1)
-%!error record (1, -1)
+%!error <SEC must be a non-negative number> record (ones (2,2))
+%!error <SEC must be a non-negative number> record (-1)
+%!error <FS must be a positive number> record (1, ones (2,2))
+%!error <FS must be a positive number> record (1, -1)
--- a/scripts/audio/sound.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/audio/sound.m	Thu Nov 19 13:08:00 2020 -0800
@@ -45,13 +45,13 @@
 
 function sound (y, fs, nbits)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
   if (nargin < 2 || isempty (fs))
     fs = 8000;
-  elseif (! (isscalar (fs) && (fs > 0)))
+  elseif (! (isscalar (fs) && fs > 0))
     error ("sound: sample rate FS must be a positive number");
   endif
 
@@ -71,7 +71,7 @@
 ## Tests of sound must not actually play anything.
 
 ## Test input validation
-%!error sound ()
-%!error sound (1,2,3,4)
-%!error sound (1, -1)
-%!error sound (1, [], 2)
+%!error <Invalid call> sound ()
+%!error <FS must be a positive number> sound (1, ones (2,2))
+%!error <FS must be a positive number> sound (1, -1)
+%!error <NBITS must be 8, 16, or 24> sound (1, [], 2)
--- a/scripts/audio/soundsc.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/audio/soundsc.m	Thu Nov 19 13:08:00 2020 -0800
@@ -51,7 +51,7 @@
 
 function soundsc (y, fs, nbits, yrange)
 
-  if (nargin < 1 || nargin > 4)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -64,7 +64,7 @@
   elseif (nargin == 2 && numel (fs) > 1)
     yrange = fs;
     fs = 8000;
-  elseif (! (isscalar (fs) && (fs > 0)))
+  elseif (! (isscalar (fs) && fs > 0))
     error ("soundsc: sample rate FS must be a positive number");
   endif
 
@@ -102,15 +102,14 @@
 
 
 ## Tests of soundsc must not actually play anything.
-
 ## Test input validation
-%!error soundsc ()
-%!error soundsc (1,2,3,4,5)
-%!error soundsc (1, -1)
-%!error soundsc (1, [], 2)
-%!error soundsc (1, [2 1])
-%!error soundsc (1, [1 2 3])
-%!error soundsc (1, 8000, [2 1])
-%!error soundsc (1, 8000, [1 2 3])
-%!error soundsc (1, 8000, 8, [2 1])
-%!error soundsc (1, 8000, 8, [1 2 3])
+%!error <Invalid call> soundsc ()
+%!error <FS must be a positive number> soundsc (1, ones (2,2), 8)
+%!error <FS must be a positive number> soundsc (1, -1)
+%!error <NBITS must be 8, 16, or 24> soundsc (1, [], 2)
+%!error <range must be a 2-element .* vector> soundsc (1, [2 1])
+%!error <range must be a 2-element .* vector> soundsc (1, [1 2 3])
+%!error <range must be a 2-element .* vector> soundsc (1, 8000, [2 1])
+%!error <range must be a 2-element .* vector> soundsc (1, 8000, [1 2 3])
+%!error <range must be a 2-element .* vector> soundsc (1, 8000, 8, [2 1])
+%!error <range must be a 2-element .* vector> soundsc (1, 8000, 8, [1 2 3])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/deprecated/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/deprecated/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/deprecated/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -1,7 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
-  %reldir%/output_max_field_width.m \
+  %reldir%/.oct-config \
   %reldir%/runtests.m
 
 %canon_reldir%dir = $(fcnfiledir)/deprecated
--- a/scripts/deprecated/output_max_field_width.m	Thu Nov 19 13:05:51 2020 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-########################################################################
-##
-## Copyright (C) 2018-2020 The Octave Project Developers
-##
-## See the file COPYRIGHT.md in the top-level directory of this
-## distribution or <https://octave.org/copyright/>.
-##
-## This file is part of Octave.
-##
-## Octave is free software: you can redistribute it and/or modify it
-## under the terms of the GNU General Public License as published by
-## the Free Software Foundation, either version 3 of the License, or
-## (at your option) any later version.
-##
-## Octave is distributed in the hope that it will be useful, but
-## WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with Octave; see the file COPYING.  If not, see
-## <https://www.gnu.org/licenses/>.
-##
-########################################################################
-
-## -*- texinfo -*-
-## @deftypefn  {} {@var{val} =} output_max_field_width ()
-## @deftypefnx {} {@var{old_val} =} output_max_field_width (@var{new_val})
-## @deftypefnx {} {} output_max_field_width (@var{new_val}, "local")
-##
-## @code{output_max_field_width} is deprecated and will be removed in Octave
-## version 7.  Use @code{output_precision} instead.
-##
-## Query or set the internal variable that specifies the maximum width
-## of a numeric output field.
-##
-## When called from inside a function with the @qcode{"local"} option, the
-## variable is changed locally for the function and any subroutines it calls.
-## The original variable value is restored when exiting the function.
-## @seealso{format, fixed_point_format, output_precision}
-## @end deftypefn
-
-## FIXME: DEPRECATED: Remove in version 7.
-
-function retval = output_max_field_width (varargin)
-
-  persistent warned = false;
-  if (! warned)
-    warned = true;
-    warning ("Octave:deprecated-function",
-             "output_max_field_width is obsolete and will be removed from a future version of Octave, please use output_precision instead\n");
-  endif
-
-  retval = 20;
-
-endfunction
--- a/scripts/deprecated/runtests.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/deprecated/runtests.m	Thu Nov 19 13:08:00 2020 -0800
@@ -53,4 +53,5 @@
   endif
 
   oruntests (varargin{:});
+
 endfunction
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/elfun/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/elfun/acosd.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/elfun/acosd.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function y = acosd (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -42,5 +42,4 @@
 
 %!assert (acosd (0:0.1:1), 180/pi * acos (0:0.1:1), -10*eps)
 
-%!error acosd ()
-%!error acosd (1, 2)
+%!error <Invalid call> acosd ()
--- a/scripts/elfun/acot.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/elfun/acot.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function y = acot (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -47,5 +47,4 @@
 %! v = [pi/6, pi/4, pi/3, pi/2, -pi/3, -pi/4, -pi/6];
 %! assert (acot (x), v, sqrt (eps));
 
-%!error acot ()
-%!error acot (1, 2)
+%!error <Invalid call> acot ()
--- a/scripts/elfun/acotd.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/elfun/acotd.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function y = acotd (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -42,5 +42,4 @@
 
 %!assert (acotd (0:10:90), 180/pi * acot (0:10:90), -10*eps)
 
-%!error acotd ()
-%!error acotd (1, 2)
+%!error <Invalid call> acotd ()
--- a/scripts/elfun/acoth.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/elfun/acoth.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function y = acoth (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -47,5 +47,4 @@
 %! x = i*[rt3, 1, rt3/3, -rt3/3, -1, -rt3];
 %! assert (acoth (x), v, sqrt (eps));
 
-%!error acoth ()
-%!error acoth (1, 2)
+%!error <Invalid call> acoth ()
--- a/scripts/elfun/acsc.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/elfun/acsc.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function y = acsc (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -47,5 +47,4 @@
 %! x = [2, rt2, 2*rt3/3, 1, 2*rt3/3, rt2, 2];
 %! assert (acsc (x), v, sqrt (eps));
 
-%!error acsc ()
-%!error acsc (1, 2)
+%!error <Invalid call> acsc ()
--- a/scripts/elfun/acscd.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/elfun/acscd.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function y = acscd (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -42,5 +42,4 @@
 
 %!assert (acscd (0:10:90), 180/pi * acsc (0:10:90), -10*eps)
 
-%!error acscd ()
-%!error acscd (1, 2)
+%!error <Invalid call> acscd ()
--- a/scripts/elfun/acsch.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/elfun/acsch.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function y = acsch (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -45,5 +45,4 @@
 %! x = [-i, i];
 %! assert (acsch (x), v, sqrt (eps));
 
-%!error acsch ()
-%!error acsch (1, 2)
+%!error <Invalid call> acsch ()
--- a/scripts/elfun/asec.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/elfun/asec.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function y = asec (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -47,5 +47,4 @@
 %! x = [1, 2*rt3/3, rt2, 2, -2, -rt2, -2*rt3/3, -1];
 %! assert (asec (x), v, sqrt (eps));
 
-%!error asec ()
-%!error asec (1, 2)
+%!error <Invalid call> asec ()
--- a/scripts/elfun/asecd.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/elfun/asecd.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function y = asecd (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -42,5 +42,4 @@
 
 %!assert (asecd (0:10:90), 180/pi * asec (0:10:90), -10*eps)
 
-%!error asecd ()
-%!error asecd (1, 2)
+%!error <Invalid call> asecd ()
--- a/scripts/elfun/asech.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/elfun/asech.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function y = asech (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -53,5 +53,4 @@
 %! x = [1, -1];
 %! assert (asech (x), v, sqrt (eps));
 
-%!error asech ()
-%!error asech (1, 2)
+%!error <Invalid call> asech ()
--- a/scripts/elfun/asind.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/elfun/asind.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function y = asind (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -42,5 +42,4 @@
 
 %!assert (asind (0:0.1:1), 180/pi * asin (0:0.1:1), -10*eps)
 
-%!error asind ()
-%!error asind (1, 2)
+%!error <Invalid call> asind ()
--- a/scripts/elfun/atan2d.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/elfun/atan2d.m	Thu Nov 19 13:08:00 2020 -0800
@@ -43,5 +43,5 @@
 
 %!assert (atan2d (-1:.1:1, 1:-.1:-1), 180/pi * atan2 (-1:.1:1, 1:-.1:-1), -10*eps)
 
-%!error atan2d ()
-%!error atan2d (1)
+%!error <Invalid call> atan2d ()
+%!error <Invalid call> atan2d (1)
--- a/scripts/elfun/atand.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/elfun/atand.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function y = atand (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -42,5 +42,4 @@
 
 %!assert (atand (0:10:90), 180/pi * atan (0:10:90), -10*eps)
 
-%!error atand ()
-%!error atand (1, 2)
+%!error <Invalid call> atand ()
--- a/scripts/elfun/cosd.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/elfun/cosd.m	Thu Nov 19 13:08:00 2020 -0800
@@ -33,7 +33,7 @@
 
 function y = cosd (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -49,5 +49,4 @@
 %!assert (cosd ([0, 180, 360]) != 0)
 %!assert (cosd ([90, 270]) == 0)
 
-%!error cosd ()
-%!error cosd (1, 2)
+%!error <Invalid call> cosd ()
--- a/scripts/elfun/cot.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/elfun/cot.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function y = cot (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -47,5 +47,4 @@
 %! v = [rt3, 1, rt3/3, 0, -rt3/3, -1, -rt3];
 %! assert (cot (x), v, sqrt (eps));
 
-%!error cot ()
-%!error cot (1, 2)
+%!error <Invalid call> cot ()
--- a/scripts/elfun/cotd.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/elfun/cotd.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function y = cotd (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -44,5 +44,4 @@
 %!assert (cotd ([0, 180, 360]) == Inf)
 %!assert (cotd ([90, 270]) == 0)
 
-%!error cotd ()
-%!error cotd (1, 2)
+%!error <Invalid call> cotd ()
--- a/scripts/elfun/coth.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/elfun/coth.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function y = coth (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -45,5 +45,4 @@
 %! v = [0, 0];
 %! assert (coth (x), v, sqrt (eps));
 
-%!error coth ()
-%!error coth (1, 2)
+%!error <Invalid call> coth ()
--- a/scripts/elfun/csc.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/elfun/csc.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function y = csc (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -47,5 +47,4 @@
 %! v = [2, rt2, 2*rt3/3, 1, 2*rt3/3, rt2, 2];
 %! assert (csc (x), v, sqrt (eps));
 
-%!error csc ()
-%!error csc (1, 2)
+%!error <Invalid call> csc ()
--- a/scripts/elfun/cscd.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/elfun/cscd.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function y = cscd (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -44,5 +44,4 @@
 %!assert (cscd ([0, 180, 360]) == Inf)
 %!assert (cscd ([90, 270]) != Inf)
 
-%!error cscd ()
-%!error cscd (1, 2)
+%!error <Invalid call> cscd ()
--- a/scripts/elfun/csch.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/elfun/csch.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function y = csch (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -45,5 +45,4 @@
 %! v = [-i, i];
 %! assert (csch (x), v, sqrt (eps));
 
-%!error csch ()
-%!error csch (1, 2)
+%!error <Invalid call> csch ()
--- a/scripts/elfun/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/elfun/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/acosd.m \
   %reldir%/acot.m \
   %reldir%/acotd.m \
--- a/scripts/elfun/sec.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/elfun/sec.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function y = sec (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -47,5 +47,4 @@
 %! v = [1, 2*rt3/3, rt2, 2, -2, -rt2, -2*rt3/3, -1];
 %! assert (sec (x), v, sqrt (eps));
 
-%!error sec ()
-%!error sec (1, 2)
+%!error <Invalid call> sec ()
--- a/scripts/elfun/secd.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/elfun/secd.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function y = secd (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -44,5 +44,4 @@
 %!assert (secd ([0, 180, 360]) != Inf)
 %!assert (secd ([90, 270]) == Inf)
 
-%!error secd ()
-%!error secd (1, 2)
+%!error <Invalid call> secd ()
--- a/scripts/elfun/sech.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/elfun/sech.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function y = sech (x)
 
-if (nargin != 1)
+if (nargin < 1)
     print_usage ();
   endif
 
@@ -45,5 +45,4 @@
 %! v = [1, -1];
 %! assert (sech (x), v, sqrt (eps));
 
-%!error sech ()
-%!error sech (1, 2)
+%!error <Invalid call> sech ()
--- a/scripts/elfun/sind.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/elfun/sind.m	Thu Nov 19 13:08:00 2020 -0800
@@ -33,7 +33,7 @@
 
 function y = sind (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -48,5 +48,4 @@
 %!assert (sind ([0, 180, 360]) == 0)
 %!assert (sind ([90, 270]) != 0)
 
-%!error sind ()
-%!error sind (1, 2)
+%!error <Invalid call> sind ()
--- a/scripts/elfun/tand.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/elfun/tand.m	Thu Nov 19 13:08:00 2020 -0800
@@ -34,7 +34,7 @@
 
 function y = tand (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -51,5 +51,4 @@
 %!assert (tand ([0, 180, 360]) == 0)
 %!assert (tand ([90, 270]) == Inf)
 
-%!error tand ()
-%!error tand (1, 2)
+%!error <Invalid call> tand ()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/general/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/general/accumarray.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/accumarray.m	Thu Nov 19 13:08:00 2020 -0800
@@ -68,7 +68,7 @@
 ## that in the first column counts how many occurrences each number in
 ## the second column has, taken from the vector @var{x}.  Note the usage
 ## of @code{unique}  for assigning to all repeated elements of @var{x}
-## the same index (@pxref{XREFunique,,unique}).
+## the same index (@pxref{XREFunique,,@code{unique}}).
 ##
 ## @example
 ## @group
@@ -99,7 +99,7 @@
 ## @end example
 ##
 ## The sparse option can be used as an alternative to the @code{sparse}
-## constructor (@pxref{XREFsparse,,sparse}).  Thus
+## constructor (@pxref{XREFsparse,,@code{sparse}}).  Thus
 ##
 ## @example
 ## sparse (@var{i}, @var{j}, @var{sv})
@@ -134,7 +134,7 @@
 
 function A = accumarray (subs, vals, sz = [], func = [], fillval = [], issparse = [])
 
-  if (nargin < 2 || nargin > 6)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -442,8 +442,8 @@
 %! assert (accumarray (subsc, vals, [], @max),
 %!         accumarray (subs, vals, [], @max));
 
-%!error (accumarray (1:5))
-%!error (accumarray ([1,2,3],1:2))
+%!error accumarray (1:5)
+%!error accumarray ([1,2,3],1:2)
 
 ## Handle empty arrays
 %!test <*47287>
--- a/scripts/general/accumdim.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/accumdim.m	Thu Nov 19 13:08:00 2020 -0800
@@ -67,7 +67,7 @@
 
 function A = accumdim (subs, vals, dim, n = 0, func = [], fillval = 0)
 
-  if (nargin < 2 || nargin > 6)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -172,8 +172,8 @@
 %!assert (accumdim ([1;3;1;3;3], a, 1, 4, [], pi)([2 4],:,:), pi (2,5,5))
 
 ## Test input validation
-%!error accumdim (1)
-%!error accumdim (1,2,3,4,5,6,7)
+%!error <Invalid call> accumdim ()
+%!error <Invalid call> accumdim (1)
 %!error <SUBS must be a subscript vector> accumdim (ones (2,2), ones (2,2))
 %!error <indices must be positive integers> accumdim ([-1 1], ones (2,2))
 %!error <N index out of range> accumdim ([1 2], ones (2,2), 1, 1)
--- a/scripts/general/bincoeff.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/bincoeff.m	Thu Nov 19 13:08:00 2020 -0800
@@ -118,7 +118,7 @@
 %!assert (bincoeff ([4 NaN 4], [-1, 2, 2.5]), NaN (1, 3))
 
 ## Test input validation
-%!error bincoeff ()
-%!error bincoeff (1, 2, 3)
-%!error bincoeff (ones (3),ones (2))
-%!error bincoeff (ones (2),ones (3))
+%!error <Invalid call> bincoeff ()
+%!error <Invalid call> bincoeff (1)
+%!error bincoeff (ones (3), ones (2))
+%!error bincoeff (ones (2), ones (3))
--- a/scripts/general/bitcmp.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/bitcmp.m	Thu Nov 19 13:08:00 2020 -0800
@@ -47,7 +47,7 @@
 
 function C = bitcmp (A, k)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/general/bitget.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/bitget.m	Thu Nov 19 13:08:00 2020 -0800
@@ -103,23 +103,19 @@
 %!   endfor
 %! endfor
 
-%!error bitget (0, 0)
-%!error bitget (0, 55)
-
-%!error bitget (single (0), 0)
-%!error bitget (single (0), 26)
-
-%!error bitget (int8 (0), 9)
-%!error bitget (uint8 (0), 9)
-
-%!error bitget (int16 (0), 17)
-%!error bitget (uint16 (0), 17)
-
-%!error bitget (int32 (0), 33)
-%!error bitget (uint32 (0), 33)
-
-%!error bitget (int64 (0), 65)
-%!error bitget (uint64 (0), 65)
-
-%!error bitget (1)
-%!error bitget (1, 2, 3)
+## Test input validation
+%!error <Invalid call> bitget ()
+%!error <Invalid call> bitget (1)
+%!error <invalid class> bitget ("char", 1)
+%!error <N must be in the range \[1,53\]> bitget (0, 0)
+%!error <N must be in the range \[1,53\]> bitget (0, 55)
+%!error <N must be in the range \[1,24\]> bitget (single (0), 0)
+%!error <N must be in the range \[1,24\]> bitget (single (0), 26)
+%!error <N must be in the range \[1,8\]> bitget (int8 (0), 9)
+%!error <N must be in the range \[1,8\]> bitget (uint8 (0), 9)
+%!error <N must be in the range \[1,16\]> bitget (int16 (0), 17)
+%!error <N must be in the range \[1,16\]> bitget (uint16 (0), 17)
+%!error <N must be in the range \[1,32\]> bitget (int32 (0), 33)
+%!error <N must be in the range \[1,32\]> bitget (uint32 (0), 33)
+%!error <N must be in the range \[1,64\]> bitget (int64 (0), 65)
+%!error <N must be in the range \[1,64\]> bitget (uint64 (0), 65)
--- a/scripts/general/bitset.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/bitset.m	Thu Nov 19 13:08:00 2020 -0800
@@ -64,7 +64,7 @@
 
 function C = bitset (A, n, val = true)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -141,8 +141,9 @@
 %!assert <*54110> (bitset (1:5, 1, 1), [1, 3, 3, 5, 5])
 %!assert (bitset (1:5, 1, [1, 1, 1, 1, 0]), [1, 3, 3, 5, 4])
 
-%!error bitset (1)
-%!error bitset (1, 2, 3, 4)
+## Test input validation
+%!error <Invalid call> bitset ()
+%!error <Invalid call> bitset (1)
 %!error <A must be .= 0> bitset (-1, 2)
 %!error <must be the same size or scalar> bitset (1, [1 2], [1 2 3])
 %!error <must be the same size or scalar> bitset ([1 2], [1 2 3])
--- a/scripts/general/cart2pol.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/cart2pol.m	Thu Nov 19 13:08:00 2020 -0800
@@ -28,69 +28,105 @@
 ## @deftypefnx {} {[@var{theta}, @var{r}, @var{z}] =} cart2pol (@var{x}, @var{y}, @var{z})
 ## @deftypefnx {} {[@var{theta}, @var{r}] =} cart2pol (@var{C})
 ## @deftypefnx {} {[@var{theta}, @var{r}, @var{z}] =} cart2pol (@var{C})
-## @deftypefnx {} {@var{P} =} cart2pol (@dots{})
 ##
 ## Transform Cartesian coordinates to polar or cylindrical coordinates.
 ##
 ## The inputs @var{x}, @var{y} (, and @var{z}) must be the same shape, or
 ## scalar.  If called with a single matrix argument then each row of @var{C}
-## represents the Cartesian coordinate (@var{x}, @var{y} (, @var{z})).
+## represents the Cartesian coordinate pair (@var{x}, @var{y}) or triplet
+## (@var{x}, @var{y}, @var{z}).
 ##
-## @var{theta} describes the angle relative to the positive x-axis.
+## The outputs @var{theta}, @var{r} (, and @var{z}) match the shape of the
+## inputs.  For a matrix input @var{C} the outputs will be column vectors with
+## rows corresponding to the rows of the input matrix.
+##
+## @var{theta} describes the angle relative to the positive x-axis measured in
+## the xy-plane.
 ##
 ## @var{r} is the distance to the z-axis @w{(0, 0, z)}.
 ##
-## If only a single return argument is requested then return a matrix @var{P}
-## where each row represents one polar/(cylindrical) coordinate
-## (@var{theta}, @var{phi} (, @var{z})).
+## @var{z}, if present, is unchanged by the transformation.
+##
+## The coordinate transformation is computed using:
+##
+## @tex
+## $$ \theta = \arctan \left ( {y \over x} \right ) $$
+## $$ r = \sqrt{x^2 + y^2} $$
+## $$ z = z $$
+## @end tex
+## @ifnottex
+##
+## @example
+## @group
+## @var{theta} = arctan (@var{y} / @var{x})
+## @var{r} = sqrt (@var{x}^2 + @var{y}^2)
+## @var{z} = @var{z}
+## @end group
+## @end example
+##
+## @end ifnottex
+##
+## @c FIXME: Remove this note in Octave 9.1 (two releases after 7.1).
+## Note: For @sc{matlab} compatibility, this function no longer returns a full
+## coordinate matrix when called with a single return argument.
 ## @seealso{pol2cart, cart2sph, sph2cart}
 ## @end deftypefn
 
 function [theta, r, z] = cart2pol (x, y, z = [])
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
   if (nargin == 1)
-    if (! (isnumeric (x) && ismatrix (x)
-           && (columns (x) == 2 || columns (x) == 3)))
-      error ("cart2pol: matrix input must have 2 or 3 columns [X, Y (, Z)]");
+    if (! (isnumeric (x) && ismatrix (x)))
+      error ("cart2pol: matrix input must be 2-D numeric array");
     endif
-    if (columns (x) == 3)
-      z = x(:,3);
+    if (isvector (x))
+      n = numel (x);
+      if (n != 2 && n != 3)
+        error ("cart2pol: matrix input must be a 2- or 3-element vector or a 2- or 3-column array");
+      endif
+      if (n == 3)
+        z = x(3);
+      endif
+      y = x(2);
+      x = x(1);
+    else
+      ncols = columns (x);
+      if (ncols != 2 && ncols != 3)
+        error ("cart2pol: matrix input must be a 2- or 3-element vector or a 2- or 3-column array");
+      endif
+
+      if (ncols == 3)
+        z = x(:,3);
+      endif
+      y = x(:,2);
+      x = x(:,1);
     endif
-    y = x(:,2);
-    x = x(:,1);
+
   elseif (nargin == 2)
-    if (! isnumeric (x) || ! isnumeric (y))
-      error ("cart2pol: X, Y must be numeric arrays of the same size, or scalar");
+    if (! (isnumeric (x) && isnumeric (y)))
+      error ("cart2pol: X, Y must be numeric arrays or scalars");
     endif
     [err, x, y] = common_size (x, y);
     if (err)
-      error ("cart2pol: X, Y must be numeric arrays of the same size, or scalar");
+      error ("cart2pol: X, Y must be the same size or scalars");
     endif
+
   elseif (nargin == 3)
-    if (! isnumeric (x) || ! isnumeric (y) || ! isnumeric (z))
-      error ("cart2pol: X, Y, Z must be numeric arrays of the same size, or scalar");
+    if (! (isnumeric (x) && isnumeric (y) && isnumeric (z)))
+      error ("cart2pol: X, Y, Z must be numeric arrays or scalars");
     endif
     [err, x, y, z] = common_size (x, y, z);
     if (err)
-      error ("cart2pol: X, Y, Z must be numeric arrays of the same size, or scalar");
+      error ("cart2pol: X, Y, Z must be the same size or scalars");
     endif
   endif
 
   theta = atan2 (y, x);
   r = sqrt (x .^ 2 + y .^ 2);
 
-  if (nargout <= 1)
-    if (isempty (z))
-      theta = [theta(:), r(:)];
-    else
-      theta = [theta(:), r(:), z(:)];
-    endif
-  endif
-
 endfunction
 
 
@@ -104,9 +140,16 @@
 %!test
 %! x = [0, 1, 2];
 %! y = [0, 1, 2];
-%! P = cart2pol (x, y);
-%! assert (P(:,1), [0; pi/4; pi/4], sqrt (eps));
-%! assert (P(:,2), sqrt (2)*[0; 1; 2], sqrt (eps));
+%! [t, r] = cart2pol (x, y);
+%! assert (t, [0, pi/4, pi/4], eps);
+%! assert (r, sqrt (2)*[0, 1, 2], eps);
+
+%!test
+%! x = [0, 1, 2]';
+%! y = [0, 1, 2]';
+%! [t, r] = cart2pol (x, y);
+%! assert (t, [0; pi/4; pi/4], eps);
+%! assert (r, sqrt (2)*[0; 1; 2], eps);
 
 %!test
 %! x = [0, 1, 2];
@@ -146,13 +189,23 @@
 
 %!test
 %! C = [0, 0; 1, 1; 2, 2];
-%! P = [0, 0; pi/4, sqrt(2); pi/4, 2*sqrt(2)];
-%! assert (cart2pol (C), P, sqrt (eps));
+%! [t, r] = cart2pol (C);
+%! assert (t, [0; 1; 1]*pi/4, eps);
+%! assert (r, [0; 1; 2]*sqrt(2), eps);
 
 %!test
 %! C = [0, 0, 0; 1, 1, 1; 2, 2, 2];
-%! P = [0, 0, 0; pi/4, sqrt(2), 1; pi/4, 2*sqrt(2), 2];
-%! assert (cart2pol (C), P, sqrt (eps));
+%! [t, r, z] = cart2pol (C);
+%! assert (t, [0; 1; 1]*pi/4, eps);
+%! assert (r, [0; 1; 2]*sqrt(2), eps);
+%! assert (z, [0; 1; 2]);
+
+%!test
+%! C = [0, 0, 0; 1, 1, 1; 2, 2, 2;1, 1, 1];
+%! [t, r, z] = cart2pol (C);
+%! assert (t, [0; 1; 1; 1]*pi/4, eps);
+%! assert (r, [0; 1; 2; 1]*sqrt(2), eps);
+%! assert (z, [0; 1; 2; 1]);
 
 %!test
 %! x = zeros (1, 1, 1, 2);
@@ -177,17 +230,19 @@
 %! assert (z, Z);
 
 ## Test input validation
-%!error cart2pol ()
+%!error <Invalid call> cart2pol ()
 %!error cart2pol (1,2,3,4)
-%!error <matrix input must have 2 or 3 columns> cart2pol ({1,2,3})
-%!error <matrix input must have 2 or 3 columns> cart2pol (ones (3,3,2))
-%!error <matrix input must have 2 or 3 columns> cart2pol ([1])
-%!error <matrix input must have 2 or 3 columns> cart2pol ([1,2,3,4])
-%!error <numeric arrays of the same size> cart2pol ({1,2,3}, [1,2,3])
-%!error <numeric arrays of the same size> cart2pol ([1,2,3], {1,2,3})
-%!error <numeric arrays of the same size> cart2pol (ones (3,3,3), ones (3,2,3))
-%!error <numeric arrays of the same size> cart2pol ({1,2,3}, [1,2,3], [1,2,3])
-%!error <numeric arrays of the same size> cart2pol ([1,2,3], {1,2,3}, [1,2,3])
-%!error <numeric arrays of the same size> cart2pol ([1,2,3], [1,2,3], {1,2,3})
-%!error <numeric arrays of the same size> cart2pol (ones (3,3,3), 1, ones (3,2,3))
-%!error <numeric arrays of the same size> cart2pol (ones (3,3,3), ones (3,2,3), 1)
+%!error <matrix input must be 2-D numeric array> cart2pol ({1,2,3})
+%!error <matrix input must be 2-D numeric array> cart2pol (ones (3,3,2))
+%!error <matrix input must be a 2- or 3-element> cart2pol ([1])
+%!error <matrix input must be a 2- or 3-element> cart2pol ([1,2,3,4])
+%!error <must be numeric arrays or scalars> cart2pol ({1,2,3}, [1,2,3])
+%!error <must be numeric arrays or scalars> cart2pol ([1,2,3], {1,2,3})
+%!error <must be the same size or scalars> cart2pol (ones (3,3,3), ones (3,2,3))
+%!error <must be the same size or scalars> cart2pol ([1; 1], [2, 2])
+%!error <must be the same size or scalars> cart2pol ([1; 1], [2, 2], [3, 3])
+%!error <must be numeric arrays or scalars> cart2pol ({1,2,3}, [1,2,3], [1,2,3])
+%!error <must be numeric arrays or scalars> cart2pol ([1,2,3], {1,2,3}, [1,2,3])
+%!error <must be numeric arrays or scalars> cart2pol ([1,2,3], [1,2,3], {1,2,3})
+%!error <must be the same size or scalars> cart2pol (ones (3,3,3), 1, ones (3,2,3))
+%!error <must be the same size or scalars> cart2pol (ones (3,3,3), ones (3,2,3), 1)
--- a/scripts/general/cart2sph.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/cart2sph.m	Thu Nov 19 13:08:00 2020 -0800
@@ -26,22 +26,45 @@
 ## -*- texinfo -*-
 ## @deftypefn  {} {[@var{theta}, @var{phi}, @var{r}] =} cart2sph (@var{x}, @var{y}, @var{z})
 ## @deftypefnx {} {[@var{theta}, @var{phi}, @var{r}] =} cart2sph (@var{C})
-## @deftypefnx {} {@var{S} =} cart2sph (@dots{})
 ## Transform Cartesian coordinates to spherical coordinates.
 ##
 ## The inputs @var{x}, @var{y}, and @var{z} must be the same shape, or scalar.
-## If called with a single matrix argument then each row of @var{C} represents
-## the Cartesian coordinate (@var{x}, @var{y}, @var{z}).
+## If called with a single matrix argument then each row of @var{C} must
+## represent a Cartesian coordinate triplet (@var{x}, @var{y}, @var{z}).
 ##
-## @var{theta} describes the angle relative to the positive x-axis.
+## The outputs @var{theta}, @var{phi}, @var{r} match the shape of the inputs.
+## For a matrix input @var{C} the outputs will be column vectors with rows
+## corresponding to the rows of the input matrix.
 ##
-## @var{phi} is the angle relative to the xy-plane.
+## @var{theta} describes the azimuth angle relative to the positive x-axis
+## measured in the xy-plane.
+##
+## @var{phi} is the elevation angle measured relative to the xy-plane.
 ##
 ## @var{r} is the distance to the origin @w{(0, 0, 0)}.
 ##
-## If only a single return argument is requested then return a matrix @var{S}
-## where each row represents one spherical coordinate
-## (@var{theta}, @var{phi}, @var{r}).
+## The coordinate transformation is computed using:
+##
+## @tex
+## $$ \theta = \arctan \left ({y \over x} \right ) $$
+## $$ \phi = \arctan \left ( {z \over {\sqrt{x^2+y^2}}} \right ) $$
+## $$ r = \sqrt{x^2 + y^2 + z^2} $$
+## @end tex
+## @ifnottex
+##
+## @example
+## @group
+## @var{theta} = arctan (@var{y} / @var{x})
+## @var{phi} = arctan (@var{z} / sqrt (@var{x}^2 + @var{y}^2))
+## @var{r} = sqrt (@var{x}^2 + @var{y}^2 + @var{z}^2)
+## @end group
+## @end example
+##
+## @end ifnottex
+##
+## @c FIXME: Remove this note in Octave 9.1 (two releases after 7.1).
+## Note: For @sc{matlab} compatibility, this function no longer returns a full
+## coordinate matrix when called with a single return argument.
 ## @seealso{sph2cart, cart2pol, pol2cart}
 ## @end deftypefn
 
@@ -52,19 +75,29 @@
   endif
 
   if (nargin == 1)
-    if (! (isnumeric (x) && ismatrix (x) && columns (x) == 3))
-      error ("cart2sph: matrix input must have 3 columns [X, Y, Z]");
+    if (! (isnumeric (x) && ismatrix (x)))
+      error ("cart2sph: matrix input C must be a 2-D numeric array");
+    elseif (columns (x) != 3 && numel (x) != 3)
+      error ("cart2sph: matrix input C must be a 3-element vector or 3-column array");
     endif
-    z = x(:,3);
-    y = x(:,2);
-    x = x(:,1);
+
+    if (numel (x) == 3)
+      z = x(3);
+      y = x(2);
+      x = x(1);
+    else
+      z = x(:,3);
+      y = x(:,2);
+      x = x(:,1);
+    endif
+
   else
-    if (! isnumeric (x) || ! isnumeric (y) || ! isnumeric (z))
-      error ("cart2sph: X, Y, Z must be numeric arrays of the same size, or scalar");
+    if (! (isnumeric (x) && isnumeric (y) && isnumeric (z)))
+      error ("cart2sph: X, Y, Z must be numeric arrays or scalars");
     endif
     [err, x, y, z] = common_size (x, y, z);
     if (err)
-      error ("cart2sph: X, Y, Z must be numeric arrays of the same size, or scalar");
+      error ("cart2sph: X, Y, Z must be the same size or scalars");
     endif
   endif
 
@@ -72,10 +105,6 @@
   phi = atan2 (z, sqrt (x .^ 2 + y .^ 2));
   r = sqrt (x .^ 2 + y .^ 2 + z .^ 2);
 
-  if (nargout <= 1)
-    theta = [theta(:), phi(:), r(:)];
-  endif
-
 endfunction
 
 
@@ -89,13 +118,22 @@
 %! assert (r, [0, 1, 2]*sqrt (3), eps);
 
 %!test
+%! x = [0; 1; 2];
+%! y = [0; 1; 2];
+%! z = [0; 1; 2];
+%! [t, p, r] = cart2sph (x, y, z);
+%! assert (t, [0; pi/4; pi/4], eps);
+%! assert (p, [0; 1; 1] * atan (sqrt (0.5)), eps);
+%! assert (r, [0; 1; 2] * sqrt (3), eps);
+
+%!test
 %! x = 0;
 %! y = [0, 1, 2];
 %! z = [0, 1, 2];
-%! S = cart2sph (x, y, z);
-%! assert (S(:,1), [0; 1; 1] * pi/2, eps);
-%! assert (S(:,2), [0; 1; 1] * pi/4, eps);
-%! assert (S(:,3), [0; 1; 2] * sqrt (2), eps);
+%! [t, p, r] = cart2sph (x, y, z);
+%! assert (t, [0, 1, 1] * pi/2, eps);
+%! assert (p, [0, 1, 1] * pi/4, eps);
+%! assert (r, [0, 1, 2] * sqrt (2), eps);
 
 %!test
 %! x = [0, 1, 2];
@@ -103,17 +141,17 @@
 %! z = [0, 1, 2];
 %! [t, p, r] = cart2sph (x, y, z);
 %! assert (t, [0, 0, 0]);
-%! assert (p, [0, 1, 1] * pi/4);
-%! assert (r, [0, 1, 2] * sqrt (2));
+%! assert (p, [0, 1, 1] * pi/4, eps);
+%! assert (r, [0, 1, 2] * sqrt (2), eps);
 
 %!test
 %! x = [0, 1, 2];
 %! y = [0, 1, 2];
 %! z = 0;
 %! [t, p, r] = cart2sph (x, y, z);
-%! assert (t, [0, 1, 1] * pi/4);
+%! assert (t, [0, 1, 1] * pi/4, eps);
 %! assert (p, [0, 0, 0]);
-%! assert (r, [0, 1, 2] * sqrt (2));
+%! assert (r, [0, 1, 2] * sqrt (2), eps);
 
 %!test
 %! x = 0;
@@ -121,13 +159,22 @@
 %! z = [0, 1, 2];
 %! [t, p, r] = cart2sph (x, y, z);
 %! assert (t, [0, 0, 0]);
-%! assert (p, [0, 1, 1] * pi/2);
+%! assert (p, [0, 1, 1] * pi/2, eps);
 %! assert (r, [0, 1, 2]);
 
 %!test
 %! C = [0, 0, 0; 1, 0, 1; 2, 0, 2];
-%! S = [0, 0, 0; 0, pi/4, sqrt(2); 0, pi/4, 2*sqrt(2)];
-%! assert (cart2sph (C), S, eps);
+%! [t, p, r] = cart2sph (C);
+%! assert (t, [0; 0; 0]);
+%! assert (p, [0; 1; 1] * pi/4, eps);
+%! assert (r, [0; 1; 2] * sqrt (2), eps);
+
+%!test
+%! C = [0, 0, 0; 1, 0, 1; 2, 0, 2; 1, 0, 1];
+%! [t, p, r] = cart2sph (C);
+%! assert (t, [0; 0; 0; 0]);
+%! assert (p, [0; 1; 1; 1] * pi/4, eps);
+%! assert (r, [0; 1; 2; 1] * sqrt (2), eps);
 
 %!test
 %! [x, y, z] = meshgrid ([0, 1], [0, 1], [0, 1]);
@@ -142,14 +189,15 @@
 %! assert (r, R, eps);
 
 ## Test input validation
-%!error cart2sph ()
-%!error cart2sph (1,2)
-%!error cart2sph (1,2,3,4)
-%!error <matrix input must have 3 columns> cart2sph ({1,2,3})
-%!error <matrix input must have 3 columns> cart2sph (ones (3,3,2))
-%!error <matrix input must have 3 columns> cart2sph ([1,2,3,4])
-%!error <numeric arrays of the same size> cart2sph ({1,2,3}, [1,2,3], [1,2,3])
-%!error <numeric arrays of the same size> cart2sph ([1,2,3], {1,2,3}, [1,2,3])
-%!error <numeric arrays of the same size> cart2sph ([1,2,3], [1,2,3], {1,2,3})
-%!error <numeric arrays of the same size> cart2sph (ones (3,3,3), 1, ones (3,2,3))
-%!error <numeric arrays of the same size> cart2sph (ones (3,3,3), ones (3,2,3), 1)
+%!error <Invalid call> cart2sph ()
+%!error <Invalid call> cart2sph (1,2)
+%!error <matrix input C must be a 2-D numeric array> cart2sph ({1,2,3})
+%!error <matrix input C must be a 2-D numeric array> cart2sph (ones (3,3,2))
+%!error <matrix input C must be a 3-element> cart2sph ([1,2,3,4])
+%!error <matrix input C must be a 3-element> cart2sph ([1,2,3,4; 1,2,3,4; 1,2,3,4])
+%!error <must be numeric arrays or scalars> cart2sph ({1,2,3}, [1,2,3], [1,2,3])
+%!error <must be numeric arrays or scalars> cart2sph ([1,2,3], {1,2,3}, [1,2,3])
+%!error <must be numeric arrays or scalars> cart2sph ([1,2,3], [1,2,3], {1,2,3})
+%!error <must be the same size or scalars> cart2sph ([1,2,3], [1,2,3], [1,2,3]')
+%!error <must be the same size or scalars> cart2sph (ones (3,3,3), 1, ones (3,2,3))
+%!error <must be the same size or scalars> cart2sph (ones (3,3,3), ones (3,2,3), 1)
--- a/scripts/general/cell2mat.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/cell2mat.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,7 +36,7 @@
 
 function m = cell2mat (c)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -130,8 +130,7 @@
 %!assert (cell2mat ({"foo", "lol"; "bar", "qux"}),
 %!        reshape ("fboaorlqoulx", [2 6]))
 
-%!error cell2mat ()
-%!error cell2mat (1,2)
+%!error <Invalid call> cell2mat ()
 %!error <C must be a cell array> cell2mat ([1,2])
 %!error <mixed cells, structs, and matrices> cell2mat ({[1], struct()})
 %!error <mixed cells, structs, and matrices> cell2mat ({[1], {1}})
--- a/scripts/general/celldisp.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/celldisp.m	Thu Nov 19 13:08:00 2020 -0800
@@ -55,7 +55,7 @@
 
 function celldisp (c, name)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -98,6 +98,6 @@
 %! celldisp (c, "b")
 
 ## Test input validation
-%!error celldisp ()
+%!error <Invalid call> celldisp ()
 %!error celldisp ({}, "name", 1)
 %!error <C must be a cell array> celldisp (1)
--- a/scripts/general/circshift.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/circshift.m	Thu Nov 19 13:08:00 2020 -0800
@@ -74,7 +74,7 @@
 
 function y = circshift (x, n, dim)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -141,9 +141,8 @@
 %!test <*53178> assert (circshift (1:4, 1, 1), 1:4)
 
 ## Test input validation
-%!error circshift ()
-%!error circshift (1)
-%!error circshift (1,2,3)
+%!error <Invalid call> circshift ()
+%!error <Invalid call> circshift (1)
 %!error <N must be a scalar> circshift (1, [2 3], 4)
 %!error <N must be a vector> circshift (1, ones (2,2))
 %!error <no longer than the number of dimensions in X> circshift (1, [1 2 3])
--- a/scripts/general/common_size.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/common_size.m	Thu Nov 19 13:08:00 2020 -0800
@@ -99,5 +99,6 @@
 %! assert (b, []);
 %! assert (c, 5);
 
-%!error common_size ()
-%!error common_size (1)
+## Test input validation
+%!error <only makes sense if nargin .= 2> common_size ()
+%!error <only makes sense if nargin .= 2> common_size (1)
--- a/scripts/general/cplxpair.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/cplxpair.m	Thu Nov 19 13:08:00 2020 -0800
@@ -59,7 +59,7 @@
 
 function y = cplxpair (z, tol, dim)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -153,9 +153,9 @@
 
 %!shared z,y
 %! z = exp (2i*pi*[4; 3; 5; 2; 6; 1; 0]/7);
-%! z(2) = conj(z(1));
-%! z(4) = conj(z(3));
-%! z(6) = conj(z(5));
+%! z(2) = conj (z(1));
+%! z(4) = conj (z(3));
+%! z(6) = conj (z(5));
 %!assert (cplxpair (z(randperm (7))), z)
 %!assert (cplxpair (z(randperm (7))), z)
 %!assert (cplxpair (z(randperm (7))), z)
@@ -175,8 +175,7 @@
 %! cplxpair ([2e6 + j; 2e6 - j; 1e-9 * (1 + j); 1e-9 * (1 - 2j)]);
 
 ## Test input validation
-%!error cplxpair ()
-%!error cplxpair (1,2,3,4)
+%!error <Invalid call> cplxpair ()
 %!error <cplxpair: TOL must be .* scalar number> cplxpair (1, ones (2,2))
 %!error <cplxpair: TOL must be .* in the range 0 <= TOL < 1> cplxpair (1, -1)
 %!error <cplxpair: TOL must be .* in the range 0 <= TOL < 1> cplxpair (1, -1)
--- a/scripts/general/cumtrapz.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/cumtrapz.m	Thu Nov 19 13:08:00 2020 -0800
@@ -51,7 +51,7 @@
 
 function z = cumtrapz (x, y, dim)
 
-  if (nargin < 1) || (nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -158,8 +158,7 @@
 %!assert (cumtrapz (x2,y,3), reshape ([0,3,8;0,9,20],[1 2 3]))
 
 ## Test input validation
-%!error cumtrapz ()
-%!error cumtrapz (1,2,3,4)
+%!error <Invalid call> cumtrapz ()
 %!error <DIM must be an integer> cumtrapz (1, 2, [1 2])
 %!error <DIM must be an integer> cumtrapz (1, 2, 1.5)
 %!error <DIM must be .* a valid dimension> cumtrapz (1, 2, 0)
--- a/scripts/general/deal.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/deal.m	Thu Nov 19 13:08:00 2020 -0800
@@ -84,7 +84,7 @@
 ## @seealso{cell2struct, struct2cell, repmat}
 ## @end deftypefn
 
-function [varargout] = deal (varargin)
+function varargout = deal (varargin)
 
   if (nargin == 0)
     print_usage ();
@@ -106,5 +106,6 @@
 %! assert (a, 1);
 %! assert (b, 1);
 
-%!error deal ()
+## Test input validation
+%!error <Invalid call> deal ()
 %!error <nargin . 1 and nargin != nargout> y = deal (1, 2)
--- a/scripts/general/deg2rad.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/deg2rad.m	Thu Nov 19 13:08:00 2020 -0800
@@ -48,7 +48,7 @@
 
 function rad = deg2rad (deg)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -67,7 +67,6 @@
 %!assert (deg2rad ([0, 90, 180, 270, 360]), pi*[0, 1/2, 1, 3/2, 2])
 
 ## Test input validation
-%!error deg2rad ()
-%!error deg2rad (1, 2)
+%!error <Invalid call> deg2rad ()
 %!error <DEG must be a floating point class> deg2rad (uint8 (1))
 %!error <DEG must be a floating point class> deg2rad ("A")
--- a/scripts/general/del2.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/del2.m	Thu Nov 19 13:08:00 2020 -0800
@@ -334,8 +334,8 @@
 %! L = 4*del2 (U, x);
 
 ## Test input validation
-%!error del2 ()
-%!error del2 (1, 1, 2, 3)
+%!error <Invalid call> del2 ()
+%!error <Invalid call> del2 (1, 1, 2, 3)
 %!error <in spacing vector 1> del2 (1, 2, [1 1])
 %!error <in spacing vector 2> del2 (1, [1 1], 2)
 %!error <must be a scalar or vector> del2 (1, ones (2,2), 2)
--- a/scripts/general/flip.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/flip.m	Thu Nov 19 13:08:00 2020 -0800
@@ -61,7 +61,7 @@
 
 function y = flip (x, dim)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -107,6 +107,5 @@
 %! assert (flip (a, 4), b);
 %! assert (flip (a, 5), a);
 
-%!error flip ()
-%!error flip (1, 2, 3)
+%!error <Invalid call> flip ()
 %!error <DIM must be a positive integer> flip (magic (3), -1)
--- a/scripts/general/fliplr.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/fliplr.m	Thu Nov 19 13:08:00 2020 -0800
@@ -43,9 +43,10 @@
 
 function y = fliplr (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
+
   y = flip (x, 2);
 
 endfunction
@@ -78,5 +79,5 @@
 %! a(:,1,:,2) = [ 5  6  7  8];
 %! assert (fliplr (a), a);
 
-%!error fliplr()
-%!error fliplr (1, 2)
+## Test input validation
+%!error <Invalid call> fliplr ()
--- a/scripts/general/flipud.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/flipud.m	Thu Nov 19 13:08:00 2020 -0800
@@ -43,7 +43,7 @@
 
 function y = flipud (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
   y = flip (x, 1);
@@ -78,5 +78,4 @@
 %! a(1,:,:,2) = [ 5  6  7  8];
 %! assert (flipud (a), a);
 
-%!error flipud ()
-%!error flipud (1, 2)
+%!error <Invalid call> flipud ()
--- a/scripts/general/gradient.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/gradient.m	Thu Nov 19 13:08:00 2020 -0800
@@ -125,7 +125,7 @@
     endif
   else
     ## have spacing value for each dimension
-    if (length(varargin) != nd)
+    if (length (varargin) != nd)
       error ("gradient: dimensions and number of spacing values do not match");
     endif
     for i = 1:nd
--- a/scripts/general/idivide.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/idivide.m	Thu Nov 19 13:08:00 2020 -0800
@@ -74,7 +74,7 @@
 
 function z = idivide (x, y, op)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
--- a/scripts/general/int2str.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/int2str.m	Thu Nov 19 13:08:00 2020 -0800
@@ -60,7 +60,7 @@
 
 function retval = int2str (n)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   elseif (! (isnumeric (n) || islogical (n) || ischar (n)))
     error ("int2str: N must be a numeric, logical, or character array");
@@ -108,6 +108,5 @@
 %!assert (int2str ([1, 2, 3; 4, 5, 6]), ["1  2  3";"4  5  6"])
 %!assert (int2str ([]), "")
 
-%!error int2str ()
-%!error int2str (1, 2)
+%!error <Invalid call> int2str ()
 %!error <N must be a numeric> int2str ({1})
--- a/scripts/general/integral.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/integral.m	Thu Nov 19 13:08:00 2020 -0800
@@ -30,11 +30,12 @@
 ## Numerically evaluate the integral of @var{f} from @var{a} to @var{b} using
 ## adaptive quadrature.
 ##
-## @code{integral} is a wrapper for @code{quadcc} (general scalar integrands),
-## @code{quadgk} (integrals with specified integration paths), and @code{quadv}
-## (array-valued integrands) that is intended to provide @sc{matlab}
-## compatibility.  More control of the numerical integration may be achievable
-## by calling the various quadrature functions directly.
+## @code{integral} is a wrapper for @code{quadcc} (general real-valued, scalar
+## integrands and limits), @code{quadgk} (integrals with specified integration
+## paths), and @code{quadv} (array-valued integrands) that is intended to
+## provide @sc{matlab} compatibility.  More control of the numerical
+## integration may be achievable by calling the various quadrature functions
+## directly.
 ##
 ## @var{f} is a function handle, inline function, or string containing the name
 ## of the function to evaluate.  The function @var{f} must be vectorized and
@@ -54,14 +55,14 @@
 ## Specifies points to be used in defining subintervals of the quadrature
 ## algorithm, or if @var{a}, @var{b}, or @var{waypoints} are complex then
 ## the quadrature is calculated as a contour integral along a piecewise
-## continuous path.  For more detail see @code{quadgk}.
+## continuous path.  For more detail, @pxref{XREFquadgk,,@code{quadgk}}.
 ##
 ## @item ArrayValued
 ## @code{integral} expects @var{f} to return a scalar value unless
 ## @var{arrayvalued} is specified as true.  This option will cause
 ## @code{integral} to perform the integration over the entire array and return
 ## @var{q} with the same dimensions as returned by @var{f}.  For more detail
-## see @code{quadv}.
+## @pxref{XREFquadv,,@code{quadv}}.
 ##
 ## @item AbsTol
 ## Define the absolute error tolerance for the quadrature.  The default
@@ -114,11 +115,36 @@
   if (nargin < 3 || (mod (nargin, 2) == 0))
     print_usage ();
   endif
+  
+  ## quadcc can't handle complex limits or integrands, but quadgk & quadv can.
+  ## Check for simple cases of complex limits and integrand.
+  f_is_complex = false;
+  if (iscomplex (a) || iscomplex (b))
+    f_is_complex = true;
+  elseif (iscomplex (feval (f, a)) || iscomplex (feval (f, b)))
+    f_is_complex = true;
+  endif
 
   if (nargin == 3)
     ## Pass the simplest case directly to general integrator.
     ## Let quadcc function handle input checks on function and limits.
-    q = quadcc (f, a, b);
+    if (! f_is_complex)
+      try
+        q = quadcc (f, a, b);
+      catch quaderror
+        if (strcmp (quaderror.message,
+                    "quadcc: integrand F must return a single, real-valued vector"))
+          q = quadgk (f, a, b);
+        else
+          error (quaderror.message);
+        endif
+      end_try_catch
+
+    else
+      ## Complex-valued integral
+      q = quadgk (f, a, b);
+    endif
+
   else
     ## Parse options to determine how to call integrator.
     abstol = [];
@@ -155,13 +181,13 @@
 
       ## FIXME: Replace warning when have array compatible call with waypoints
       if (! isempty (waypoints))
-        warning(["integral: array-valued quadrature routine currently ", ...
+        warning (["integral: array-valued quadrature routine currently ", ...
                  "unable to handle WayPoints.  WayPoints are ignored."]);
       endif
 
       ## FIXME: Remove warning once we have reltol compatible arrayval'd quadfn
       if (! isempty (reltol))
-        warning(["integral: array-valued quadrature only accepts AbsTol.", ...
+        warning (["integral: array-valued quadrature only accepts AbsTol.", ...
                  "  RelTol ignored."]);
       endif
       if (isempty (abstol))
@@ -182,7 +208,21 @@
         q = quadgk (f, a, b, "AbsTol", abstol, "RelTol", reltol,
                              "WayPoints", waypoints);
       else
-        q = quadcc (f, a, b, [abstol, reltol]);
+        if (! f_is_complex)
+          try
+            q = quadcc (f, a, b, [abstol, reltol]); 
+          catch quaderror
+            if (strcmp (quaderror.message,
+                        "quadcc: integrand F must return a single, real-valued vector"))
+              q = quadgk (f, a, b, "AbsTol", abstol, "RelTol", reltol);
+            else
+              error (quaderror.message);
+            endif
+          end_try_catch
+        else
+          ## Complex-valued integral
+          q = quadgk (f, a, b, "AbsTol", abstol, "RelTol", reltol);
+        endif
       endif
     endif
   endif
@@ -203,7 +243,7 @@
 %! assert (integral (@(x) f(x,5), 0, 2), -0.4605015338467329, 1e-10);
 
 %!test  # with tolerances
-%! f = @(x) log(x);
+%! f = @(x) log (x);
 %! assert (integral (@(x) f(x), 0, 1, "AbsTol", 1e-6), -1, 1e-6);
 
 %!test  # waypoints
@@ -216,15 +256,22 @@
 %!         1e-10);
 
 %!test  # test single input/output
-%! assert (integral (@sin, 0, 1), cos(0)-cos(1), 1e-10);
+%! assert (integral (@sin, 0, 1), cos (0)-cos (1), 1e-10);
 %! assert (class (integral (@sin, single (0), 1)), "single");
 %! assert (class (integral (@sin, 0, single (1))), "single");
 %! assert (class (integral (@sin, single (0), single (1))), "single");
-%! assert (integral (@sin, 0, 1, "Waypoints", 0.5), cos(0)-cos(1), 1e-10);
+%! assert (integral (@sin, 0, 1, "Waypoints", 0.5), cos (0)-cos (1), 1e-10);
 %! assert (class (integral (@sin, 0, 1, "Waypoints", single (0.5))), "single");
 %! assert (class (integral (@sin, single (0), 1, "Waypoints", 0.5)), "single");
 %! assert (class (integral (@sin, 0, single (1), "Waypoints", 0.5)), "single");
 
+%!test  # test complex argument handling
+%! f = @(x) round (exp (i*x));
+%! assert (integral (f, 0, pi), quadgk (f, 0, pi), eps);
+%! assert (integral (f, -1, 1), 2, 5*eps);
+%! assert (integral (@sin, -i, i), 0, eps);
+%! assert (1.5 * integral (@sqrt, -1, 0), i, eps);
+
 %!test
 %! f = @(x) x.^5 .* exp (-x) .* sin (x);
 %! assert (integral (f, 0, inf, "RelTol", 1e-8, "AbsTol", 1e-12), -15, -1e-8);
--- a/scripts/general/integral2.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/integral2.m	Thu Nov 19 13:08:00 2020 -0800
@@ -303,12 +303,12 @@
 %!assert (integral2 (@plus, 1, 2, 3, 4, "method", "iterated"), 5, 1e-10)
 
 ## Test input validation
-%!error integral2 ()
-%!error integral2 (@plus)
-%!error integral2 (@plus, 1)
-%!error integral2 (@plus, 1, 2)
-%!error integral2 (@plus, 1, 2, 3)
-%!error integral2 (@plus, 1, 2, 3, 4, "foo")
+%!error <Invalid call> integral2 ()
+%!error <Invalid call> integral2 (@plus)
+%!error <Invalid call> integral2 (@plus, 1)
+%!error <Invalid call> integral2 (@plus, 1, 2)
+%!error <Invalid call> integral2 (@plus, 1, 2, 3)
+%!error <Invalid call> integral2 (@plus, 1, 2, 3, 4, "foo")
 %!error integral2 (0, 1, 2, 3, 4)          # f must be function handle
 %!error integral2 (@plus, 1i, 2, 3, 4)     # real limits
 %!error integral2 (@plus, 1, 2i, 3, 4)     # real limits
--- a/scripts/general/integral3.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/integral3.m	Thu Nov 19 13:08:00 2020 -0800
@@ -241,11 +241,11 @@
     if (! (isreal (za) && isscalar (za)))
       error ("integral3: ZA must be a real scalar or a function");
     endif
-    za = @(x, y) za * ones (size(y));
+    za = @(x, y) za * ones (size (y));
   endif
   if (! is_function_handle (zb))
     if (! (isreal (zb) && isscalar (zb)))
-      error ("integral3: ZB must be a real scalar or a function")
+      error ("integral3: ZB must be a real scalar or a function");
     endif
     zb = @(x, y) zb * ones (size (y));
   endif
@@ -286,10 +286,10 @@
 %!shared f
 %! f = @(x, y, z) x .* y .* z;
 
-%!assert (integral3 (f, 0, 1, 0, 1, 0, 1), 0.125, 1e-10);
-%!assert (integral3 (f, 0, 1, 0, 1, 0, 1, "method", "tiled"), 0.125, 1e-10);
-%!assert (integral3 (f, 0, 1, 0, 1, 0, 1, "method", "iterated"), 0.125, 1e-10);
-%!assert (integral3 (f, 0, 1, 0, 1, 0, 1, "method", "auto"), 0.125, 1e-10);
+%!assert (integral3 (f, 0, 1, 0, 1, 0, 1), 0.125, 1e-10)
+%!assert (integral3 (f, 0, 1, 0, 1, 0, 1, "method", "tiled"), 0.125, 1e-10)
+%!assert (integral3 (f, 0, 1, 0, 1, 0, 1, "method", "iterated"), 0.125, 1e-10)
+%!assert (integral3 (f, 0, 1, 0, 1, 0, 1, "method", "auto"), 0.125, 1e-10)
 
 ## vectorized = false test
 %!test
--- a/scripts/general/interp1.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/interp1.m	Thu Nov 19 13:08:00 2020 -0800
@@ -778,8 +778,9 @@
 %!assert (interp1 ([1,2,2,3,4],[0,1,4,2,1],[-1,1.5,2,2.5,3.5], "linear", "extrap", "left"), [-2,0.5,1,3,1.5])
 
 ## Test input validation
-%!error interp1 ()
-%!error interp1 (1,2,3,4,5,6,7)
+%!error <Invalid call> interp1 ()
+%!error <Invalid call> interp1 (1)
+%!error <Invalid call> interp1 (1,2,3,4,5,6,7)
 %!error <minimum of 2 points required> interp1 (1,1,1, "linear")
 %!error <minimum of 2 points required> interp1 (1,1,1, "*nearest")
 %!error <minimum of 2 points required> interp1 (1,1,1, "*linear")
--- a/scripts/general/interp2.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/interp2.m	Thu Nov 19 13:08:00 2020 -0800
@@ -568,14 +568,14 @@
 %!error <X, Y must be numeric matrices> interp2 (1, {1}, ones (2), 1, 1)
 %!error <XI, YI must be numeric> interp2 (1, 1, ones (2), {1}, 1)
 %!error <XI, YI must be numeric> interp2 (1, 1, ones (2), 1, {1})
-%!error <X and Y must be matrices of equal size> interp2 (ones(2,2), 1, ones (2), 1, 1)
-%!error <X and Y must be matrices of equal size> interp2 (ones(2,2), ones(2,3), ones (2), 1, 1)
+%!error <X and Y must be matrices of equal size> interp2 (ones (2,2), 1, ones (2), 1, 1)
+%!error <X and Y must be matrices of equal size> interp2 (ones (2,2), ones (2,3), ones (2), 1, 1)
 %!error <X and Y size must match the dimensions of Z> interp2 (1:3, 1:3, ones (3,2), 1, 1)
 %!error <X and Y size must match the dimensions of Z> interp2 (1:2, 1:2, ones (3,2), 1, 1)
 %!error <X must be strictly monotonic> interp2 ([1 0 2], 1:3, ones (3,3), 1, 1)
 %!error <Y must be strictly monotonic> interp2 (1:3, [1 0 2], ones (3,3), 1, 1)
-%!error <XI and YI must be matrices of equal size> interp2 (1:2, 1:2, ones (2), ones(2,2), 1)
-%!error <XI and YI must be matrices of equal size> interp2 (1:2, 1:2, ones (2), 1, ones(2,2))
+%!error <XI and YI must be matrices of equal size> interp2 (1:2, 1:2, ones (2), ones (2,2), 1)
+%!error <XI and YI must be matrices of equal size> interp2 (1:2, 1:2, ones (2), 1, ones (2,2))
 %!error <XI, YI must have uniform spacing> interp2 (1:2, 1:2, ones (2), [1 2 4], [1 2 3], "spline")
 %!error <XI, YI must have uniform spacing> interp2 (1:2, 1:2, ones (2), [1 2 3], [1 2 4], "spline")
 %!error interp2 (1, 1, 1, 1, 1, "foobar")
--- a/scripts/general/interp3.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/interp3.m	Thu Nov 19 13:08:00 2020 -0800
@@ -255,7 +255,7 @@
 %! assert (vi, vi2);
 
 %!test  # extrapolation
-%! X=[0,0.5,1]; Y=X; Z=X;
+%! X = [0,0.5,1];  Y=X;  Z=X;
 %! V = zeros (3,3,3);
 %! V(:,:,1) = [1 3 5; 3 5 7; 5 7 9];
 %! V(:,:,2) = V(:,:,1) + 2;
--- a/scripts/general/interpft.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/interpft.m	Thu Nov 19 13:08:00 2020 -0800
@@ -43,7 +43,7 @@
 
 function z = interpft (x, n, dim)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -111,18 +111,18 @@
 %! ti = t(1) + [0 : k-1]*dt*n/k;
 %! y = sin (4*t + 0.3) .* cos (3*t - 0.1);
 %! yp = sin (4*ti + 0.3) .* cos (3*ti - 0.1);
-%! plot (ti, yp, 'g', ti, interp1(t, y, ti, "spline"), 'b', ...
+%! plot (ti, yp, 'g', ti, interp1 (t, y, ti, "spline"), 'b', ...
 %!       ti, interpft (y, k), 'c', t, y, "r+");
-%! legend ("sin(4t+0.3)cos(3t-0.1)", "spline", "interpft", "data");
+%! legend ("sin (4t+0.3)cos (3t-0.1)", "spline", "interpft", "data");
 
 %!shared n,y
 %! x = [0:10]';  y = sin(x);  n = length (x);
 %!testif HAVE_FFTW
-%! assert (interpft (y, n), y, 20*eps)
+%! assert (interpft (y, n), y, 20*eps);
 %!testif HAVE_FFTW
-%! assert (interpft (y', n), y', 20*eps)
+%! assert (interpft (y', n), y', 20*eps);
 %!testif HAVE_FFTW
-%! assert (interpft ([y,y],n), [y,y], 20*eps)
+%! assert (interpft ([y,y],n), [y,y], 20*eps);
 
 ## Test case with complex input
 %!testif HAVE_FFTW <*39566>
@@ -132,18 +132,17 @@
 
 ## Test for correct spectral symmetry with even/odd lengths
 %!testif HAVE_FFTW
-%! assert (max (abs (imag (interpft ([1:8], 20)))), 0, 20*eps)
+%! assert (max (abs (imag (interpft ([1:8], 20)))), 0, 20*eps);
 %!testif HAVE_FFTW
-%! assert (max (abs (imag (interpft ([1:8], 21)))), 0, 21*eps)
+%! assert (max (abs (imag (interpft ([1:8], 21)))), 0, 21*eps);
 %!testif HAVE_FFTW
-%! assert (max (abs (imag (interpft ([1:9], 20)))), 0, 20*eps)
+%! assert (max (abs (imag (interpft ([1:9], 20)))), 0, 20*eps);
 %!testif HAVE_FFTW
-%! assert (max (abs (imag (interpft ([1:9], 21)))), 0, 21*eps)
+%! assert (max (abs (imag (interpft ([1:9], 21)))), 0, 21*eps);
 
 ## Test input validation
-%!error interpft ()
-%!error interpft (1)
-%!error interpft (1,2,3)
+%!error <Invalid call> interpft ()
+%!error <Invalid call> interpft (1)
 %!error <N must be a scalar integer> interpft (1,[2,2])
 %!error <N must be a scalar integer> interpft (1,2.1)
 %!error <invalid dimension DIM> interpft (1,2,0)
--- a/scripts/general/isequal.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/isequal.m	Thu Nov 19 13:08:00 2020 -0800
@@ -176,7 +176,7 @@
 
       endif
 
-    else  ## More than two args.  This is going to be slower in general.
+    else  # More than two args.  This is going to be slower in general.
 
       if (ischar (x) && all (cellfun ("isclass", varargin, "char")))
         ## char type.  Optimization, strcmp is ~35% faster than '==' operator.
@@ -545,5 +545,5 @@
 %!assert (isequal (sparse (1), sparse (1)), sparse (1), true)
 
 ## test input validation
-%!error isequal ()
-%!error isequal (1)
+%!error <Invalid call> isequal ()
+%!error <Invalid call> isequal (1)
--- a/scripts/general/isequaln.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/isequaln.m	Thu Nov 19 13:08:00 2020 -0800
@@ -174,7 +174,7 @@
 
       endif
 
-    else  ## More than two args.  This is going to be slower in general.
+    else  # More than two args.  This is going to be slower in general.
 
       if (ischar (x) && all (cellfun ("isclass", varargin, "char")))
         ## char type.  Optimization, strcmp is ~35% faster than '==' operator.
@@ -318,5 +318,5 @@
 %!assert (isequaln (st, st, st), true)
 
 ## Input validation
-%!error isequaln ()
-%!error isequaln (1)
+%!error <Invalid call> isequaln ()
+%!error <Invalid call> isequaln (1)
--- a/scripts/general/logspace.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/logspace.m	Thu Nov 19 13:08:00 2020 -0800
@@ -74,7 +74,7 @@
 
 function retval = logspace (a, b, n = 50)
 
-  if (nargin != 2 && nargin != 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -119,8 +119,7 @@
 ##%!assert (logspace (Inf, 0, 3), [Inf, NaN, 1])
 
 ## Test input validation
-%!error logspace ()
-%!error logspace (1, 2, 3, 4)
+%!error <Invalid call> logspace ()
 %!error logspace ([1, 2; 3, 4], 5, 6)
 %!error logspace (1, [1, 2; 3, 4], 6)
 %!error logspace (1, 2, [1, 2; 3, 4])
--- a/scripts/general/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -6,6 +6,7 @@
   %reldir%/private/__splinen__.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/accumarray.m \
   %reldir%/accumdim.m \
   %reldir%/bincoeff.m \
@@ -60,6 +61,7 @@
   %reldir%/repelem.m \
   %reldir%/repmat.m \
   %reldir%/rescale.m \
+  %reldir%/rng.m \
   %reldir%/rot90.m \
   %reldir%/rotdim.m \
   %reldir%/shift.m \
--- a/scripts/general/nextpow2.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/nextpow2.m	Thu Nov 19 13:08:00 2020 -0800
@@ -41,7 +41,7 @@
 
 function n = nextpow2 (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -73,6 +73,5 @@
 %!assert (nextpow2 ([1, Inf, 3, -Inf, 9, NaN]), [0, Inf, 2, Inf, 4, NaN])
 
 ## Test input validation
-%!error nexpow2 ()
-%!error nexpow2 (1, 2)
+%!error <Invalid call> nextpow2 ()
 %!error <X must be numeric> nextpow2 ("t")
--- a/scripts/general/num2str.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/num2str.m	Thu Nov 19 13:08:00 2020 -0800
@@ -80,7 +80,7 @@
 
 function retval = num2str (x, arg)
 
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1)
     print_usage ();
   elseif (! (isnumeric (x) || islogical (x) || ischar (x)))
     error ("num2str: X must be a numeric, logical, or character array");
@@ -211,8 +211,8 @@
 %!assert (num2str ([inf -inf]), "Inf -Inf")
 %!assert (num2str ([inf NaN -inf]), "Inf  NaN -Inf")
 %!assert (num2str ([complex(Inf,0), complex(0,-Inf)]), "Inf+0i   0-Infi")
-%!assert (num2str (complex(Inf,1)), "Inf+1i")
-%!assert (num2str (complex(1,Inf)), "1+Infi")
+%!assert (num2str (complex (Inf,1)), "Inf+1i")
+%!assert (num2str (complex (1,Inf)), "1+Infi")
 %!assert (num2str (nan), "NaN")
 %!assert (num2str (complex (NaN, 1)), "NaN+1i")
 %!assert (num2str (complex (1, NaN)), "1+NaNi")
@@ -249,7 +249,7 @@
 %!assert <*36133> (num2str (1e15), "1000000000000000")
 %!assert <*36133> (num2str (1e16), "1e+16")
 ## Even exact integers in IEEE notation should use exponential notation
-%!assert <*36133> (num2str(2^512), "1.34078079299426e+154")
+%!assert <*36133> (num2str (2^512), "1.34078079299426e+154")
 ## Mixed integer/floating point arrays
 %!assert <*36133> (num2str ([2.1, 1e23, pi]),
 %!                 "2.1  9.999999999999999e+22      3.141592653589793")
@@ -265,8 +265,7 @@
 %!assert <*45174> (num2str ([65 66 67], "%s"), "ABC")
 
 ## Test input validation
-%!error num2str ()
-%!error num2str (1, 2, 3)
+%!error <Invalid call> num2str ()
 %!error <X must be a numeric> num2str ({1})
 %!error <PRECISION must be a scalar integer .= 0> num2str (1, {1})
 %!error <PRECISION must be a scalar integer .= 0> num2str (1, ones (2))
--- a/scripts/general/pol2cart.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/pol2cart.m	Thu Nov 19 13:08:00 2020 -0800
@@ -28,69 +28,104 @@
 ## @deftypefnx {} {[@var{x}, @var{y}, @var{z}] =} pol2cart (@var{theta}, @var{r}, @var{z})
 ## @deftypefnx {} {[@var{x}, @var{y}] =} pol2cart (@var{P})
 ## @deftypefnx {} {[@var{x}, @var{y}, @var{z}] =} pol2cart (@var{P})
-## @deftypefnx {} {@var{C} =} pol2cart (@dots{})
 ## Transform polar or cylindrical coordinates to Cartesian coordinates.
 ##
 ## The inputs @var{theta}, @var{r}, (and @var{z}) must be the same shape, or
 ## scalar.  If called with a single matrix argument then each row of @var{P}
-## represents the polar/(cylindrical) coordinate (@var{theta}, @var{r}
-## (, @var{z})).
+## represents the polar coordinate pair (@var{theta}, @var{r}) or the
+## cylindrical triplet (@var{theta}, @var{r}, @var{z}).
+##
+## The outputs @var{x}, @var{y} (, and @var{z}) match the shape of the inputs.
+## For a matrix input @var{P} the outputs will be column vectors with rows
+## corresponding to the rows of the input matrix.
 ##
-## @var{theta} describes the angle relative to the positive x-axis.
+## @var{theta} describes the angle relative to the positive x-axis measured in
+## the xy-plane.
+##
+## @var{r} is the distance to the z-axis @w{(0, 0, z)}.
+##
+## @var{z}, if present, is unchanged by the transformation.
+##
+## The coordinate transformation is computed using:
 ##
-## @var{r} is the distance to the z-axis (0, 0, z).
+## @tex
+## $$ x = r \cos \theta $$
+## $$ y = r \sin \theta $$
+## $$ z = z $$
+## @end tex
+## @ifnottex
 ##
-## If only a single return argument is requested then return a matrix @var{C}
-## where each row represents one Cartesian coordinate
-## (@var{x}, @var{y} (, @var{z})).
+## @example
+## @group
+## @var{x} = @var{r} * cos (@var{theta})
+## @var{y} = @var{r} * sin (@var{theta})
+## @var{z} = @var{z}
+## @end group
+## @end example
+##
+## @end ifnottex
+## @c FIXME: Remove this note in Octave 9.1 (two releases after 7.1).
+## Note: For @sc{matlab} compatibility, this function no longer returns a full
+## coordinate matrix when called with a single return argument.
 ## @seealso{cart2pol, sph2cart, cart2sph}
 ## @end deftypefn
 
 function [x, y, z] = pol2cart (theta, r, z = [])
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
   if (nargin == 1)
-    if (! (isnumeric (theta) && ismatrix (theta)
-           && (columns (theta) == 2 || columns (theta) == 3)))
-      error ("pol2cart: matrix input must have 2 or 3 columns [THETA, R (, Z)]");
+    if (! (isnumeric (theta) && ismatrix (theta)))
+      error ("cart2pol: matrix input P must be 2-D numeric array");
     endif
-    if (columns (theta) == 3)
-      z = theta(:,3);
+    if (isvector (theta))
+      n = numel (theta);
+      if (n != 2 && n != 3)
+        error ("cart2pol: matrix input must be a 2- or 3-element vector or a 2- or 3-column array");
+      endif
+      if (n == 3)
+        z = theta(3);
+      endif
+      r = theta(2);
+      theta = theta(1);
+
+    else
+      ncols = columns (theta);
+      if (ncols != 2 && ncols != 3)
+        error ("cart2pol: matrix input must be a 2- or 3-element vector or a 2- or 3-column array");
+      endif
+
+      if (ncols == 3)
+        z = theta(:,3);
+      endif
+      r = theta(:,2);
+      theta = theta(:,1);
     endif
-    r = theta(:,2);
-    theta = theta(:,1);
+
   elseif (nargin == 2)
-    if (! isnumeric (theta) || ! isnumeric (r))
-      error ("pol2cart: THETA, R must be numeric arrays of the same size, or scalar");
+    if (! (isnumeric (theta) && isnumeric (r)))
+      error ("pol2cart: THETA, R must be numeric arrays or scalars");
     endif
     [err, theta, r] = common_size (theta, r);
     if (err)
-      error ("pol2cart: THETA, R must be numeric arrays of the same size, or scalar");
+      error ("pol2cart: THETA, R must be the same size or scalars");
     endif
+
   elseif (nargin == 3)
-    if (! isnumeric (theta) || ! isnumeric (r) || ! isnumeric (z))
-      error ("pol2cart: THETA, R, Z must be numeric arrays of the same size, or scalar");
+    if (! (isnumeric (theta) && isnumeric (r) && isnumeric (z)))
+      error ("pol2cart: THETA, R, Z must be numeric arrays or scalars");
     endif
     [err, theta, r, z] = common_size (theta, r, z);
     if (err)
-      error ("pol2cart: THETA, R, Z must be numeric arrays of the same size, or scalar");
+      error ("pol2cart: THETA, R, Z must be the same size or scalars");
     endif
   endif
 
   x = r .* cos (theta);
   y = r .* sin (theta);
 
-  if (nargout <= 1)
-    if (isempty (z))
-      x = [x(:), y(:)];
-    else
-      x = [x(:), y(:), z(:)];
-    endif
-  endif
-
 endfunction
 
 
@@ -98,32 +133,42 @@
 %! t = [0, 0.5, 1] * pi;
 %! r = 1;
 %! [x, y] = pol2cart (t, r);
-%! assert (x, [1, 0, -1], sqrt (eps));
-%! assert (y, [0, 1,  0], sqrt (eps));
+%! assert (x, [1, 0, -1], eps);
+%! assert (y, [0, 1,  0], eps);
 
 %!test
 %! t = [0, 1, 1] * pi/4;
 %! r = sqrt (2) * [0, 1, 2];
-%! C = pol2cart (t, r);
-%! assert (C(:,1), [0; 1; 2], sqrt (eps));
-%! assert (C(:,2), [0; 1; 2], sqrt (eps));
+%! [x, y] = pol2cart (t, r);
+%! assert (x, [0, 1, 2], 2*eps);
+%! assert (y, [0, 1, 2], 2*eps);
 
 %!test
 %! t = [0, 1, 1] * pi/4;
 %! r = sqrt (2) * [0, 1, 2];
 %! z = [0, 1, 2];
 %! [x, y, z2] = pol2cart (t, r, z);
-%! assert (x, [0, 1, 2], sqrt (eps));
-%! assert (y, [0, 1, 2], sqrt (eps));
+%! assert (x, [0, 1, 2], 2*eps);
+%! assert (y, [0, 1, 2], 2*eps);
 %! assert (z2, z);
 
 %!test
+%! t = [0; 1; 1] * pi/4;
+%! r = sqrt (2) * [0; 1; 2];
+%! z = [0; 1; 2];
+%! [x, y, z2] = pol2cart (t, r, z);
+%! assert (x, [0; 1; 2], 2*eps);
+%! assert (y, [0; 1; 2], 2*eps);
+%! assert (z2, z);
+
+
+%!test
 %! t = 0;
 %! r = [0, 1, 2];
 %! z = [0, 1, 2];
 %! [x, y, z2] = pol2cart (t, r, z);
-%! assert (x, [0, 1, 2], sqrt (eps));
-%! assert (y, [0, 0, 0], sqrt (eps));
+%! assert (x, [0, 1, 2], eps);
+%! assert (y, [0, 0, 0], eps);
 %! assert (z2, z);
 
 %!test
@@ -146,13 +191,23 @@
 
 %!test
 %! P = [0, 0; pi/4, sqrt(2); pi/4, 2*sqrt(2)];
-%! C = [0, 0; 1, 1; 2, 2];
-%! assert (pol2cart (P), C, sqrt (eps));
+%! [x, y] = pol2cart(P);
+%! assert (x, [0; 1; 2], 2*eps);
+%! assert (y, [0; 1; 2], 2*eps);
 
 %!test
 %! P = [0, 0, 0; pi/4, sqrt(2), 1; pi/4, 2*sqrt(2), 2];
-%! C = [0, 0, 0; 1, 1, 1; 2, 2, 2];
-%! assert (pol2cart (P), C, sqrt (eps));
+%! [x, y, z] = pol2cart(P);
+%! assert (x, [0; 1; 2], 2*eps);
+%! assert (y, [0; 1; 2], 2*eps);
+%! assert (z, P(:,3), 2*eps);
+
+%!test
+%! P = [0, 0, 0; pi/4, sqrt(2), 1; pi/4, 2*sqrt(2), 2; 0, 0, 0];
+%! [x, y, z] = pol2cart(P);
+%! assert (x, [0; 1; 2; 0], 2*eps);
+%! assert (y, [0; 1; 2; 0], 2*eps);
+%! assert (z, P(:,3), 2*eps);
 
 %!test
 %! r = ones (1, 1, 1, 2);
@@ -169,10 +224,10 @@
 %!test
 %! [t, r, Z] = meshgrid ([0, pi/2], [1, 2], [0, 1]);
 %! [x, y, z] = pol2cart (t, r, Z);
-%! X = zeros(2, 2, 2);
+%! X = zeros (2, 2, 2);
 %! X(:, 1, 1) = [1; 2];
 %! X(:, 1, 2) = [1; 2];
-%! Y = zeros(2, 2, 2);
+%! Y = zeros (2, 2, 2);
 %! Y(:, 2, 1) = [1; 2];
 %! Y(:, 2, 2) = [1; 2];
 %! assert (x, X, eps);
@@ -180,17 +235,18 @@
 %! assert (z, Z);
 
 ## Test input validation
-%!error pol2cart ()
-%!error pol2cart (1,2,3,4)
-%!error <matrix input must have 2 or 3 columns> pol2cart ({1,2,3})
-%!error <matrix input must have 2 or 3 columns> pol2cart (ones (3,3,2))
-%!error <matrix input must have 2 or 3 columns> pol2cart ([1])
-%!error <matrix input must have 2 or 3 columns> pol2cart ([1,2,3,4])
-%!error <numeric arrays of the same size> pol2cart ({1,2,3}, [1,2,3])
-%!error <numeric arrays of the same size> pol2cart ([1,2,3], {1,2,3})
-%!error <numeric arrays of the same size> pol2cart (ones (3,3,3), ones (3,2,3))
-%!error <numeric arrays of the same size> pol2cart ({1,2,3}, [1,2,3], [1,2,3])
-%!error <numeric arrays of the same size> pol2cart ([1,2,3], {1,2,3}, [1,2,3])
-%!error <numeric arrays of the same size> pol2cart ([1,2,3], [1,2,3], {1,2,3})
-%!error <numeric arrays of the same size> pol2cart (ones (3,3,3), 1, ones (3,2,3))
-%!error <numeric arrays of the same size> pol2cart (ones (3,3,3), ones (3,2,3), 1)
+%!error <Invalid call> pol2cart ()
+%!error <matrix input P must be 2-D numeric array> pol2cart ({1,2,3})
+%!error <matrix input P must be 2-D numeric array> pol2cart (ones (3,3,2))
+%!error <matrix input must be a 2- or 3-element> pol2cart ([1])
+%!error <matrix input must be a 2- or 3-element> pol2cart ([1,2,3,4])
+%!error <must be numeric arrays or scalars> pol2cart ({1,2,3}, [1,2,3])
+%!error <must be numeric arrays or scalars> pol2cart ([1,2,3], {1,2,3})
+%!error <must be the same size or scalars> pol2cart (ones (3,3,3), ones (3,2,3))
+%!error <must be the same size or scalars> pol2cart ([1; 1], [2, 2])
+%!error <must be the same size or scalars> pol2cart ([1; 1], [2, 2], [3, 3])
+%!error <must be numeric arrays or scalars> pol2cart ({1,2,3}, [1,2,3], [1,2,3])
+%!error <must be numeric arrays or scalars> pol2cart ([1,2,3], {1,2,3}, [1,2,3])
+%!error <must be numeric arrays or scalars> pol2cart ([1,2,3], [1,2,3], {1,2,3})
+%!error <must be the same size or scalars> pol2cart (ones (3,3,3), 1, ones (3,2,3))
+%!error <must be the same size or scalars> pol2cart (ones (3,3,3), ones (3,2,3), 1)
--- a/scripts/general/polyarea.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/polyarea.m	Thu Nov 19 13:08:00 2020 -0800
@@ -48,7 +48,7 @@
 
 function a = polyarea (x, y, dim)
 
-  if (nargin != 2 && nargin != 3)
+  if (nargin < 2)
     print_usage ();
   elseif (! size_equal (x, y))
     error ("polyarea: X and Y must have the same shape");
--- a/scripts/general/postpad.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/postpad.m	Thu Nov 19 13:08:00 2020 -0800
@@ -44,7 +44,7 @@
 
 function y = postpad (x, l, c, dim)
 
-  if (nargin < 2 || nargin > 4)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -113,6 +113,5 @@
 %!assert <*44162> (postpad ("Octave", 16, "x"), "Octavexxxxxxxxxx")
 %!assert (postpad ("Octave", 4), "Octa")
 
-%!error postpad ()
-%!error postpad (1)
-%!error postpad (1,2,3,4,5)
+%!error <Invalid call> postpad ()
+%!error <Invalid call> postpad (1)
--- a/scripts/general/prepad.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/prepad.m	Thu Nov 19 13:08:00 2020 -0800
@@ -44,7 +44,7 @@
 
 function y = prepad (x, l, c, dim)
 
-  if (nargin < 2 || nargin > 4)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -118,9 +118,8 @@
 
 ## FIXME: We need tests for multidimensional arrays.
 
-%!error prepad ()
-%!error prepad (1)
-%!error prepad (1,2,3,4,5)
+%!error <Invalid call> prepad ()
+%!error <Invalid call> prepad (1)
 %!error <C must be empty or a scalar> prepad ([1,2], 2, ones (2))
 %!error <DIM must be an integer> prepad ([1,2], 2, 2, ones (3))
 %!error <DIM must be an integer> prepad ([1,2], 2, 2, 1.1)
--- a/scripts/general/quad2d.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/quad2d.m	Thu Nov 19 13:08:00 2020 -0800
@@ -233,13 +233,13 @@
     if (! (isreal (ya) && isscalar (ya)))
       error ("quad2d: YA must be a real scalar or a function");
     endif
-    ya = @(x) ya * ones(rows (x), columns (x));
+    ya = @(x) ya * ones (rows (x), columns (x));
   endif
   if (! is_function_handle (yb))
     if (! (isreal (yb) && isscalar (yb)))
       error ("quad2d: YB must be a real scalar or a function");
     endif
-    yb = @(x) yb * ones(rows (x), columns (x));
+    yb = @(x) yb * ones (rows (x), columns (x));
   endif
 
   iter = 0;
@@ -262,7 +262,7 @@
 
     xtrans = @(tx) ((xa - xb) .* cos (tx) + (xa + xb)) ./ 2;
     ytrans = @(ty) (1 - cos (ty)) ./ 2;
-    ztrans = @(tx, ty) (xb - xa) .* sin(tx) .* sin(ty) ./ 4;
+    ztrans = @(tx, ty) (xb - xa) .* sin (tx) .* sin (ty) ./ 4;
     area = pi ^ 2;
 
     ## Initialize tile list
@@ -408,6 +408,7 @@
   z = yhalfwidth .* f (x, y) .* ztrans(tx, ty) .* xhalfwidth;
   q = weights15 * (weights15 * z)';
   qerr = abs (weights7 * (weights7 * z)' - q);
+
 endfunction
 
 
@@ -437,12 +438,12 @@
 %!assert (quad2d (@plus, 1, 2, 3, 4), 5, 1e-10)
 
 ## Test input validation
-%!error quad2d ()
-%!error quad2d (@plus)
-%!error quad2d (@plus, 1)
-%!error quad2d (@plus, 1, 2)
-%!error quad2d (@plus, 1, 2, 3)
-%!error quad2d (@plus, 1, 2, 3, 4, "foo")
+%!error <Invalid call> quad2d ()
+%!error <Invalid call> quad2d (@plus)
+%!error <Invalid call> quad2d (@plus, 1)
+%!error <Invalid call> quad2d (@plus, 1, 2)
+%!error <Invalid call> quad2d (@plus, 1, 2, 3)
+%!error <Invalid call> quad2d (@plus, 1, 2, 3, 4, "foo")
 %!error quad2d (0, 1, 2, 3, 4)          # f must be function handle
 %!error quad2d (@plus, 1i, 2, 3, 4)     # real limits
 %!error quad2d (@plus, 1, 2i, 3, 4)     # real limits
--- a/scripts/general/quadgk.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/quadgk.m	Thu Nov 19 13:08:00 2020 -0800
@@ -463,7 +463,7 @@
 function t = __quadgk_finite_waypoint__ (x, a, b)
   c = (-4 .* x + 2.* (b + a)) ./ (b - a);
   k = ((sqrt (c .^ 2 - 4) + c) ./ 2) .^ (1/3);
-  t = real ((sqrt(3) .* 1i * (1 - k .^ 2) - (1 + k .^ 2)) ./ 2 ./ k);
+  t = real ((sqrt (3) .* 1i * (1 - k .^ 2) - (1 + k .^ 2)) ./ 2 ./ k);
 endfunction
 
 
@@ -480,10 +480,10 @@
 %!assert (quadgk (@(x) 1./sqrt (x),0,1), 2, 1e-10)
 %!assert (quadgk (@(x) abs (1 - x.^2),0,2, "Waypoints", 1), 2, 1e-10)
 %!assert (quadgk (@(x) 1./(sqrt (x) .* (x+1)),0,Inf), pi, 1e-10)
-%!assert <*57614> (quadgk (@(z) exp(z)./z, 1, 1,
+%!assert <*57614> (quadgk (@(z) exp (z)./z, 1, 1,
 %!                        "Waypoints", [1+i, -1+i, -1-i, 1-i]),
 %!                 complex (0, 2*pi), 1e-10)
-%!assert <*57614> (quadgk (@(z) exp(z)./z, 1, 1,
+%!assert <*57614> (quadgk (@(z) exp (z)./z, 1, 1,
 %!                        "Waypoints", [1-i, -1-i, -1+i, 1+i]),
 %!                 complex (0, -2*pi), 1e-10)
 %!assert (quadgk (@(z) log (z),1+1i,1+1i, "WayPoints", [1-1i, -1,-1i, -1+1i]),
--- a/scripts/general/quadl.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/quadl.m	Thu Nov 19 13:08:00 2020 -0800
@@ -184,14 +184,14 @@
 
 ## extra parameters
 %!assert (quadl (@(x,a,b) sin (a + b*x), 0, 1, [], [], 2, 3),
-%!        cos(2)/3 - cos(5)/3, 1e-6)
+%!        cos (2)/3 - cos (5)/3, 1e-6)
 
 ## test different tolerances.
 %!test
 %! [q, nfun1] = quadl (@(x) sin (2 + 3*x).^2, 0, 10, 0.5, []);
-%! assert (q, (60 + sin(4) - sin(64))/12, 0.5);
+%! assert (q, (60 + sin (4) - sin (64))/12, 0.5);
 %! [q, nfun2] = quadl (@(x) sin (2 + 3*x).^2, 0, 10, 0.1, []);
-%! assert (q, (60 + sin(4) - sin(64))/12, 0.1);
+%! assert (q, (60 + sin (4) - sin (64))/12, 0.1);
 %! assert (nfun2 > nfun1);
 
 %!test  # test single input/output
@@ -200,8 +200,8 @@
 %! assert (class (quadl (@sin, 0, single (1))), "single");
 
 ## Test input validation
-%!error quadl ()
-%!error quadl (@sin)
-%!error quadl (@sin,1)
+%!error <Invalid call> quadl ()
+%!error <Invalid call> quadl (@sin)
+%!error <Invalid call> quadl (@sin,1)
 %!error <TOL must be a scalar> quadl (@sin,0,1, ones (2,2))
 %!error <TOL must be .* .=0> quadl (@sin,0,1, -1)
--- a/scripts/general/quadv.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/quadv.m	Thu Nov 19 13:08:00 2020 -0800
@@ -210,7 +210,7 @@
 %!assert (quadv (@sin, 0, pi), 2, 1e-6)
 
 ## Test weak singularities at the edge
-%!assert (quadv (@(x) 1 ./ sqrt (x), 0, 1), 2, 15*1e-6);
+%!assert (quadv (@(x) 1 ./ sqrt (x), 0, 1), 2, 15*1e-6)
 
 ## Test vector-valued functions
 %!assert (quadv (@(x) [(sin (x)), (sin (2 * x))], 0, pi), [2, 0], 1e-6)
@@ -223,8 +223,8 @@
 %!assert <*57603> (quadv (@(t) sin (t) .^ 2, 0, 8*pi), 4*pi, 1e-6)
 
 ## Test input validation
-%!error quadv ()
-%!error quadv (@sin)
-%!error quadv (@sin,1)
+%!error <Invalid call> quadv ()
+%!error <Invalid call> quadv (@sin)
+%!error <Invalid call> quadv (@sin,1)
 %!error <TOL must be a scalar> quadv (@sin,0,1, ones (2,2))
 %!error <TOL must be .* .=0> quadv (@sin,0,1, -1)
--- a/scripts/general/rad2deg.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/rad2deg.m	Thu Nov 19 13:08:00 2020 -0800
@@ -48,7 +48,7 @@
 
 function deg = rad2deg (rad)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -67,7 +67,6 @@
 %!assert (rad2deg (pi*[0, 1/2, 1, 3/2, 2]), [0, 90, 180, 270, 360])
 
 ## Test input validation
-%!error rad2deg ()
-%!error rad2deg (1, 2)
+%!error <Invalid call> rad2deg ()
 %!error <RAD must be a floating point class> rad2deg (uint8 (1))
 %!error <RAD must be a floating point class> rad2deg ("A")
--- a/scripts/general/randi.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/randi.m	Thu Nov 19 13:08:00 2020 -0800
@@ -189,13 +189,9 @@
 
 ## Test that no warning thrown if IMAX is exactly on the limits of the range
 %!function test_no_warning (func, varargin)
-%!  state = warning ("query");
-%!  unwind_protect
-%!    warning ("error", "all");
-%!    func (varargin{:});
-%!  unwind_protect_cleanup
-%!    warning (state);
-%!  end_unwind_protect
+%!  lastwarn ("");
+%!  func (varargin{:});
+%!  assert (lastwarn (), "");
 %!endfunction
 %!test test_no_warning (@randi, max_int8, "int8");
 %!test test_no_warning (@randi, max_uint8, "uint8");
@@ -224,7 +220,7 @@
 
 
 ## Test input validation
-%!error randi ()
+%!error <Invalid call> randi ()
 %!error <must be integer bounds> randi ("test")
 %!error <must be integer bounds> randi (struct ("a", 1))
 %!error <must be integer bounds> randi (1.5)
--- a/scripts/general/rat.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/rat.m	Thu Nov 19 13:08:00 2020 -0800
@@ -65,7 +65,7 @@
 
 function [n, d] = rat (x, tol)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -223,8 +223,7 @@
 %!assert <*43374> (eval (rat (0.75)), [0.75])
 
 ## Test input validation
-%!error rat ()
-%!error rat (1, 2, 3)
+%!error <Invalid call> rat ()
 %!error <X must be a single or double array> rat (int8 (3))
 %!error <X must be a real, not complex, array> rat (1+1i)
 %!error <TOL must be a numeric scalar> rat (1, "a")
--- a/scripts/general/repelem.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/repelem.m	Thu Nov 19 13:08:00 2020 -0800
@@ -176,7 +176,7 @@
 
 function retval = repelem (x, varargin)
 
-  if (nargin <= 1)
+  if (nargin < 2)
     print_usage ();
 
   elseif (nargin == 2)
@@ -344,7 +344,7 @@
 
 ## nargin == 2 tests
 %!assert (repelem ([-1 0 1], 2), [-1 -1 0 0 1 1])
-%!assert (repelem ([-1 0 1]', 2), [-1; -1; 0; 0; 1; 1;])
+%!assert (repelem ([-1 0 1]', 2), [-1; -1; 0; 0; 1; 1])
 %!assert (repelem ([-1 0 1], [1 2 1]), [-1 0 0 1])
 %!assert (repelem ([-1 0 1]', [1 2 1]), [-1; 0; 0; 1])
 %!assert (repelem ([1 2 3 4 5]', [2 1 0 1 2]), [1 1 2 4 5 5]')
@@ -364,32 +364,32 @@
 %!        [1 1 1 0 0;1 1 1 0 0;0 0 0 -1 -1;0 0 0 -1 -1;0 0 0 -1 -1])
 %!assert (repelem (cat(3,[1 1 1 0;0 1 0 0],[1 1 1 1;0 0 0 1],[1 0 0 1;1 1 0 1]),
 %!                2, 3),
-%!        cat(3,[1 1 1 1 1 1 1 1 1 0 0 0
-%!               1 1 1 1 1 1 1 1 1 0 0 0
-%!               0 0 0 1 1 1 0 0 0 0 0 0
-%!               0 0 0 1 1 1 0 0 0 0 0 0],
-%!              [1 1 1 1 1 1 1 1 1 1 1 1
-%!               1 1 1 1 1 1 1 1 1 1 1 1
-%!               0 0 0 0 0 0 0 0 0 1 1 1
-%!               0 0 0 0 0 0 0 0 0 1 1 1],
-%!              [1 1 1 0 0 0 0 0 0 1 1 1
-%!               1 1 1 0 0 0 0 0 0 1 1 1
-%!               1 1 1 1 1 1 0 0 0 1 1 1
-%!               1 1 1 1 1 1 0 0 0 1 1 1]))
+%!        cat (3,[1 1 1 1 1 1 1 1 1 0 0 0
+%!                1 1 1 1 1 1 1 1 1 0 0 0
+%!                0 0 0 1 1 1 0 0 0 0 0 0
+%!                0 0 0 1 1 1 0 0 0 0 0 0],
+%!               [1 1 1 1 1 1 1 1 1 1 1 1
+%!                1 1 1 1 1 1 1 1 1 1 1 1
+%!                0 0 0 0 0 0 0 0 0 1 1 1
+%!                0 0 0 0 0 0 0 0 0 1 1 1],
+%!               [1 1 1 0 0 0 0 0 0 1 1 1
+%!                1 1 1 0 0 0 0 0 0 1 1 1
+%!                1 1 1 1 1 1 0 0 0 1 1 1
+%!                1 1 1 1 1 1 0 0 0 1 1 1]))
 %!assert (repelem (cat(3,[1 1 1 0;0 1 0 0],[1 1 1 1;0 0 0 1],[1 0 0 1;1 1 0 1]),
 %!                2, [3 3 3 3]), ...
-%!        cat(3,[1 1 1 1 1 1 1 1 1 0 0 0
-%!               1 1 1 1 1 1 1 1 1 0 0 0
-%!               0 0 0 1 1 1 0 0 0 0 0 0
-%!               0 0 0 1 1 1 0 0 0 0 0 0], ...
-%!              [1 1 1 1 1 1 1 1 1 1 1 1
-%!               1 1 1 1 1 1 1 1 1 1 1 1
-%!               0 0 0 0 0 0 0 0 0 1 1 1
-%!               0 0 0 0 0 0 0 0 0 1 1 1], ...
-%!              [1 1 1 0 0 0 0 0 0 1 1 1
-%!               1 1 1 0 0 0 0 0 0 1 1 1
-%!               1 1 1 1 1 1 0 0 0 1 1 1
-%!               1 1 1 1 1 1 0 0 0 1 1 1]));
+%!        cat (3,[1 1 1 1 1 1 1 1 1 0 0 0
+%!                1 1 1 1 1 1 1 1 1 0 0 0
+%!                0 0 0 1 1 1 0 0 0 0 0 0
+%!                0 0 0 1 1 1 0 0 0 0 0 0], ...
+%!               [1 1 1 1 1 1 1 1 1 1 1 1
+%!                1 1 1 1 1 1 1 1 1 1 1 1
+%!                0 0 0 0 0 0 0 0 0 1 1 1
+%!                0 0 0 0 0 0 0 0 0 1 1 1], ...
+%!               [1 1 1 0 0 0 0 0 0 1 1 1
+%!                1 1 1 0 0 0 0 0 0 1 1 1
+%!                1 1 1 1 1 1 0 0 0 1 1 1
+%!                1 1 1 1 1 1 0 0 0 1 1 1]));
 %!assert (repelem ([1 2 3 4 5], 2,[2 1 2 0 2]), [1 1 2 3 3 5 5;1 1 2 3 3 5 5])
 %
 ## nargin > 3 tests
@@ -405,16 +405,16 @@
 %!assert (repelem (repmat([-1 0;0 1],1,1,2,3),2,2,2,2,2), ...
 %!        repmat([-1 -1 0 0;-1 -1 0 0;0 0 1 1; 0 0 1 1],1,1,4,6,2))
 %!assert (repelem ([1,0,-1;-1,0,1],[2 3],[2 3 4],2), ...
-%!        cat(3,[ 1  1 0 0 0 -1 -1 -1 -1
-%!                1  1 0 0 0 -1 -1 -1 -1
-%!               -1 -1 0 0 0  1  1  1  1
-%!               -1 -1 0 0 0  1  1  1  1
-%!               -1 -1 0 0 0  1  1  1  1], ...
-%!              [ 1  1 0 0 0 -1 -1 -1 -1
-%!                1  1 0 0 0 -1 -1 -1 -1
-%!               -1 -1 0 0 0  1  1  1  1
-%!               -1 -1 0 0 0  1  1  1  1
-%!               -1 -1 0 0 0  1  1  1  1]));
+%!        cat (3,[ 1  1 0 0 0 -1 -1 -1 -1
+%!                 1  1 0 0 0 -1 -1 -1 -1
+%!                -1 -1 0 0 0  1  1  1  1
+%!                -1 -1 0 0 0  1  1  1  1
+%!                -1 -1 0 0 0  1  1  1  1], ...
+%!               [ 1  1 0 0 0 -1 -1 -1 -1
+%!                 1  1 0 0 0 -1 -1 -1 -1
+%!                -1 -1 0 0 0  1  1  1  1
+%!                -1 -1 0 0 0  1  1  1  1
+%!                -1 -1 0 0 0  1  1  1  1]));
 %!assert (repelem ([1 2 3;4 5 6],[0 2],2,2), repmat([4 4 5 5 6 6],2,1,2))
 
 ## test with structures
@@ -438,34 +438,33 @@
 %! assert (repelem (11:13, [1 3 0]), [11 12 12 12]);
 
 ## nargin <= 1 error tests
-%!error (repelem ());
-%!error (repelem ([]));
-%!error (repelem (5));
-%!error (repelem (5,[]));
-%!error (repelem ([1 2 3 3 2 1]));
-%!error (repelem ([1 2 3; 3 2 1]));
+%!error <Invalid call> repelem ()
+%!error <Invalid call> repelem (1)
+%!error repelem (5,[])
+%!error repelem ([1 2 3 3 2 1])
+%!error repelem ([1 2 3; 3 2 1])
 
 ## nargin == 2 error tests
-%!error (repelem ([1 2 3; 3 2 1],[]));
-%!error (repelem ([1 2 3; 3 2 1],2));
-%!error (repelem ([1 2 3; 3 2 1],2));
-%!error (repelem ([1 2 3; 3 2 1],[1 2 3]));
-%!error (repelem ([1 2 3; 3 2 1],[1 2 3]'));
-%!error (repelem ([1 2 3; 3 2 1],[1 2 2 1]));
-%!error (repelem ([1 2 3; 3 2 1],[1 2 3;4 5 6]));
-%!error (repelem ([1 2 3 4 5],[1 2 3 4 5;1 2 3 4 5]));
+%!error repelem ([1 2 3; 3 2 1],[])
+%!error repelem ([1 2 3; 3 2 1],2)
+%!error repelem ([1 2 3; 3 2 1],2)
+%!error repelem ([1 2 3; 3 2 1],[1 2 3])
+%!error repelem ([1 2 3; 3 2 1],[1 2 3]')
+%!error repelem ([1 2 3; 3 2 1],[1 2 2 1])
+%!error repelem ([1 2 3; 3 2 1],[1 2 3;4 5 6])
+%!error repelem ([1 2 3 4 5],[1 2 3 4 5;1 2 3 4 5])
 
 ## nargin == 3 error tests
-%!error (repelem ([1 2 3; 3 2 1], 1, [1 2;1 2]));
-%!error (repelem ([1 2 3; 3 2 1], 1, [1 2]));
-%!error (repelem ([1 2 3; 3 2 1], 2, []));
-%!error (repelem ([1 2 3; 3 2 1], [1 2 3], [1 2 3]));
-%!error (repelem ([1 2 3; 3 2 1], [1 2 3], [1 2 3 4]));
-%!error (repelem ([1 2 3; 3 2 1], [1 2], [1 2 3 4]));
+%!error repelem ([1 2 3; 3 2 1], 1, [1 2;1 2])
+%!error repelem ([1 2 3; 3 2 1], 1, [1 2])
+%!error repelem ([1 2 3; 3 2 1], 2, [])
+%!error repelem ([1 2 3; 3 2 1], [1 2 3], [1 2 3])
+%!error repelem ([1 2 3; 3 2 1], [1 2 3], [1 2 3 4])
+%!error repelem ([1 2 3; 3 2 1], [1 2], [1 2 3 4])
 
 ## nargin > 3 error tests
-%!error (repelem ([1 2 3; 3 2 1], 1, [1 2;1 2],1,2,3));
-%!error (repelem ([1 2 3; 3 2 1], [],1,2,3));
-%!error (repelem ([1 2 3; 3 2 1], [1 2], [1 2 3],1,2,[1 2;1 2]));
-%!error (repelem ([1 2 3; 3 2 1], [1 2 3], [1 2 3],1,2));
-%!error (repelem ([1 2 3; 3 2 1], [1 2], [1 2 3 4],1,2));
+%!error repelem ([1 2 3; 3 2 1], 1, [1 2;1 2],1,2,3)
+%!error repelem ([1 2 3; 3 2 1], [],1,2,3)
+%!error repelem ([1 2 3; 3 2 1], [1 2], [1 2 3],1,2,[1 2;1 2])
+%!error repelem ([1 2 3; 3 2 1], [1 2 3], [1 2 3],1,2)
+%!error repelem ([1 2 3; 3 2 1], [1 2], [1 2 3 4],1,2)
--- a/scripts/general/repmat.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/repmat.m	Thu Nov 19 13:08:00 2020 -0800
@@ -221,4 +221,4 @@
 %!assert (size (repmat ({1}, [0, 1])), [0, 1])
 %!assert (size (repmat ({1}, [0, 5])), [0, 5])
 
-%!error (size (repmat (".", -1, -1)))
+%!error size (repmat (".", -1, -1))
--- a/scripts/general/rescale.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/rescale.m	Thu Nov 19 13:08:00 2020 -0800
@@ -162,11 +162,11 @@
 %!assert (class (rescale (logical ([0, 1]))), "double")
 
 ## Test input validation
-%!error rescale ()
-%!error rescale (1, 2)
-%!error rescale (1, 2, 3, 4)
-%!error rescale (1, 2, 3, 4, 5, 6)
-%!error rescale (1, 2, 3, 4, 5, 6, 7, 8)
+%!error <Invalid call> rescale ()
+%!error <Invalid call> rescale (1, 2)
+%!error <Invalid call> rescale (1, 2, 3, 4)
+%!error <Invalid call> rescale (1, 2, 3, 4, 5, 6)
+%!error <Invalid call> rescale (1, 2, 3, 4, 5, 6, 7, 8)
 %!error <A must be a numeric or logical matrix> rescale ("abc")
 %!error <A must be a numeric or logical matrix> rescale ({ [1] })
 %!error <U must be numeric> rescale (1, 0, "A")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/general/rng.m	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,306 @@
+########################################################################
+##
+## Copyright (C) 2020 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn  {} {} rng (@var{seed})
+## @deftypefnx {} {} rng (@var{seed}, "@var{generator}")
+## @deftypefnx {} {} rng ("shuffle")
+## @deftypefnx {} {} rng ("shuffle", "@var{generator}")
+## @deftypefnx {} {} rng ("default")
+## @deftypefnx {} {@var{s} =} rng ()
+## @deftypefnx {} {} rng (@var{s})
+## @deftypefnx {} {@var{s} =} rng (@dots{})
+## Set or query the seed of the random number generator used by @code{rand} and
+## @code{randn}.
+##
+## The input @var{seed} is a scalar numeric value used to initialize the state
+## vector of the random number generator.
+##
+## The optional string @var{generator} specifies the type of random number
+## generator to be used.  Its value can be @qcode{"twister"},
+## @qcode{"v5uniform"}, or @qcode{"v5normal"}.  The @qcode{"twister"} keyword
+## is described below.  @qcode{"v5uniform"} and @qcode{"v5normal"} refer to
+## older versions of Octave that used to use a different random number
+## generator.
+##
+## The state or seed of the random number generator can be reset to a new
+## random value using the @qcode{"shuffle"} keyword.
+##
+## The random number generator can be reset to default values using the
+## @qcode{"default"} keyword.  The default values are to use the Mersenne
+## Twister generator with a seed of 0.
+##
+## The optional return value @var{s} contains the state of the random number
+## generator at the time the function is called (i.e., before it might be
+## modified according to the input arguments).  It is encoded as a structure
+## variable with three fields: @qcode{"Type"}, @qcode{"Seed"}, and
+## @qcode{"State"}.  The random number generator can be restored to the state
+## @var{s} using @code{rng (@var{s})}.  This is useful when the identical
+## sequence of pseudo-random numbers is required for an algorithm.
+##
+## By default, and with the @qcode{"twister"} option, pseudo-random sequences
+## are computed using the Mersenne Twister with a period of @math{2^{19937}-1}
+## (See @nospell{M. Matsumoto and T. Nishimura},
+## @cite{Mersenne Twister: A 623-dimensionally equidistributed uniform
+## pseudorandom number generator},
+## @nospell{ACM} Trans.@: on Modeling and Computer Simulation Vol.@: 8, No.@: 1,
+## pp.@: 3--30, January 1998,
+## @url{http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html}).
+## Do @strong{not} use for cryptography without securely hashing several
+## returned values together, otherwise the generator state can be learned after
+## reading 624 consecutive values.
+##
+## @seealso{rand, randn}
+## @end deftypefn
+
+function retval = rng (varargin)
+
+  if (nargin > 2)
+    print_usage ();
+  endif
+
+  ## Store current settings of random number generator
+  ## FIXME: there doesn't seem to be a way to query the type of generator
+  ##        currently used in Octave - assume "twister".
+  ## FIXME: there doesn't seem to be a way to query the seed initialization
+  ##        value - use "Not applicable".
+  ## FIXME: rand and randn use different generators - storing both states.
+  ## For older Matlab generators (v4, v5), the settings are stored like this:
+  ##   struct ("Type","Legacy", "Seed", "Not applicable", "State",{[],[],...})
+
+  ## Type is the generator name.
+  ## Seed is the initial seed value.
+  ## State is a structure describing internal state of the generator.
+  s = struct ("Type", "twister",
+              "Seed", "Not applicable",
+              "State", {{rand("state"), randn("state")}});
+
+  if (nargin == 0)
+    retval = s;
+    return;
+  endif
+
+  arg1 = varargin{1};
+  if (isscalar (arg1) && isnumeric (arg1) && isreal (arg1) && arg1 >= 0)
+    s_rand = s_randn = arg1;
+    generator = check_generator (varargin(2:end));
+
+  elseif (ischar (arg1) && strcmpi (arg1, "shuffle"))
+    ## Seed the random number generator based on the current time
+    s_rand = s_randn = "reset";  # or sum (1000*clock)
+    generator = check_generator (varargin(2:end));
+
+  elseif (ischar (arg1) && strcmpi (arg1, "default") && nargin == 1)
+    generator = "twister";
+    s_rand = s_randn = 0;  # FIXME: In Matlab, seed 0 corresponds to 5489
+
+  elseif (isstruct (arg1) && isscalar (arg1) && nargin == 1)
+    if (numfields (arg1) != 3
+        || ! all (isfield (arg1, {"Type", "Seed", "State"})))
+      error ('rng: input structure requires "Type", "Seed", "State" fields"');
+    endif
+    ## Only the internal state "State" and generator type "Type" are needed
+    generator = arg1.Type;
+    if (iscell (arg1.State))
+      [s_rand, s_randn] = deal (arg1.State{:});
+    else
+      s_rand = s_randn = arg1.State;
+    endif
+
+  else
+    print_usage ();
+  endif
+
+  ## Set the type of random number generator and seed it
+  if (isempty (generator))
+    generator = s.Type;
+  endif
+  switch (generator)
+    case "twister"
+      rand ("state", s_rand);
+      randn ("state", s_randn);
+
+    case "legacy"
+      rand ("seed", s_rand);
+      randn ("seed", s_randn);
+
+    case "v5uniform"
+      rand ("seed", s_rand);
+
+    case "v5normal"
+      randn ("seed", s_randn);
+
+    otherwise
+      error ('rng: invalid GENERATOR: "%s"', generator);
+
+  endswitch
+
+  if (nargout > 0)
+    retval = s;
+  endif
+
+endfunction
+
+
+function gen = check_generator (val)
+
+  if (isempty (val))
+    gen = "";
+    return;
+  elseif (! iscellstr (val))
+    error ("rng: GENERATOR must be a string");
+  endif
+
+  gen = tolower (char (val));
+  if (any (strcmp (gen, {"simdtwister", "combrecursive", "philox", "threefry", "multfibonacci", "v4"})))
+    error ('rng: random number generator "%s" is not available in Octave', gen);
+  elseif (! any (strcmp (gen, {"twister", "v5uniform", "v5normal"})))
+    error ('rng: unknown random number generator "%s"', gen);
+  endif
+
+endfunction
+
+
+%!test
+%! state = rng ();
+%! unwind_protect
+%!   rng (42);
+%!   ru1 = rand ();
+%!   rn1 = randn ();
+%!   rng (42);
+%!   ru2 = rand ();
+%!   rn2 = randn ();
+%!   assert (ru2, ru1);
+%!   assert (rn2, rn1);
+%!   s1 = rng ();
+%!   s2 = rng (42);
+%!   assert (isequal (s1, s2));
+%!   ru1 = rand ();
+%!   rn1 = randn ();
+%!   s3 = rng (42);
+%!   ru2 = rand ();
+%!   rn2 = randn ();
+%!   assert (ru2, ru1);
+%!   assert (rn2, rn1);
+%! unwind_protect_cleanup
+%!   rng (state);
+%! end_unwind_protect
+
+%!test
+%! state = rng ();
+%! unwind_protect
+%!   rng (42, "twister");
+%!   ru1 = rand ();
+%!   rn1 = randn ();
+%!   rng (42, "twister");
+%!   ru2 = rand ();
+%!   rn2 = randn ();
+%!   assert (ru2, ru1);
+%!   assert (rn2, rn1);
+%!   s1 = rng ();
+%!   s2 = rng (42, "twister");
+%!   assert (isequal (s1, s2));
+%!   ru1 = rand ();
+%!   rn1 = randn ();
+%!   s3 = rng (42, "twister");
+%!   ru2 = rand ();
+%!   rn2 = randn ();
+%!   assert (ru2, ru1);
+%!   assert (rn2, rn1);
+%! unwind_protect_cleanup
+%!   rng (state);
+%! end_unwind_protect
+
+%!test
+%! state = rng ();
+%! unwind_protect
+%!   rng ("shuffle");
+%!   rng ("shuffle", "twister");
+%!   s = rng ("shuffle");
+%!   assert (! isequal (s, rng ("shuffle")));
+%!   s = rng ("shuffle", "twister");
+%!   assert (! isequal (s, rng ("shuffle", "twister")));
+%! unwind_protect_cleanup
+%!   rng (state);
+%! end_unwind_protect
+
+%!test
+%! state = rng ();
+%! unwind_protect
+%!   rng ("default");
+%!   ru1 = rand ();
+%!   rn1 = randn ();
+%!   rng (0, "twister");
+%!   ru2 = rand ();
+%!   rn2 = randn ();
+%!   assert (ru2, ru1);
+%!   assert (rn2, rn1);
+%!   rng (0, "twister");
+%!   s = rng ("default");
+%!   assert (isequal (s, rng ()));
+%! unwind_protect_cleanup
+%!   rng (state);
+%! end_unwind_protect
+
+%!test
+%! state = rng ();
+%! unwind_protect
+%!   s = rng ();
+%!   ru1 = rand ();
+%!   rn1 = randn ();
+%!   rng (s);
+%!   ru2 = rand ();
+%!   rn2 = randn ();
+%!   assert (ru2, ru1);
+%!   assert (rn2, rn1);
+%!   rng (42);  rand (1,2);  x = rand (1,2);
+%!   rng (42);  rand (1,2);  s = rng ();  y = rand (1,2);
+%!   assert (x, y);
+%!   rng (s);  z = rand (1,2);
+%!   assert (x, z);
+%!   s1 = rng ();
+%!   s2 = rng (s1);
+%!   assert (isequal (s1, s2));
+%! unwind_protect_cleanup
+%!   rng (state);
+%! end_unwind_protect
+
+## Test input validation
+%!error <Invalid call> rng (1, 2, 3)
+%!error <Invalid call> rng (eye (2))
+%!error <Invalid call> rng ({})
+%!error <Invalid call> rng (2i)
+%!error <Invalid call> rng (-2)
+%!error <Invalid call> rng ("foobar")
+%!error <Invalid call> rng ("default", "twister")
+%!error <Invalid call> rng (struct ("Seed", {1, 2}))
+%!error <Invalid call> rng (struct ("Type",[],"State",[],"Seed",[]), "twister")
+%!error <input structure requires "Type"> rng (struct ())
+%!error <input structure requires "Type">
+%! rng (struct ("Type1",[],"State",[],"Seed",[]));
+%!error <GENERATOR must be a string> rng (0, struct ())
+%!error <"philox" is not available in Octave> rng (0, "philox")
+%!error <GENERATOR must be a string> rng ("shuffle", struct ())
+%!error <unknown random number generator "foobar"> rng ("shuffle", "foobar")
--- a/scripts/general/rot90.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/rot90.m	Thu Nov 19 13:08:00 2020 -0800
@@ -65,7 +65,7 @@
 
 function B = rot90 (A, k = 1)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -140,8 +140,7 @@
 %! assert (rot90 (a, 3), rot90 (b, 2));
 
 ## Test input validation
-%!error rot90 ()
-%!error rot90 (1, 2, 3)
+%!error <Invalid call> rot90 ()
 %!error rot90 (1, ones (2))
 %!error rot90 (1, 1.5)
 %!error rot90 (1, 1+i)
--- a/scripts/general/rotdim.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/rotdim.m	Thu Nov 19 13:08:00 2020 -0800
@@ -65,7 +65,7 @@
 
 function y = rotdim (x, n, plane)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -164,5 +164,4 @@
 ## FIXME: We need tests for multidimensional arrays
 ##        and different values of PLANE.
 
-%!error rotdim ()
-%!error rotdim (1, 2, 3, 4)
+%!error <Invalid call> rotdim ()
--- a/scripts/general/shift.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/shift.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,7 +36,7 @@
 
 function y = shift (x, b, dim)
 
-  if (nargin != 2 && nargin != 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -91,11 +91,11 @@
 %! assert (shift (m, -2), [c; a; b]);
 
 ## Test input validation
-%!error shift ()
-%!error shift (1, 2, 3, 4)
-%!error shift ([], 1)
-%!error shift (ones (2), ones (2))
-%!error shift (ones (2), 1.5)
-%!error shift (1, 1, 1.5)
-%!error shift (1, 1, 0)
-%!error shift (1, 1, 3)
+%!error <Invalid call> shift ()
+%!error <Invalid call> shift (1)
+%!error <X must not be empty> shift ([], 1)
+%!error <B must be an integer> shift (ones (2), ones (2))
+%!error <B must be an integer> shift (ones (2), 1.5)
+%!error <DIM must be an integer> shift (1, 1, 1.5)
+%!error <DIM must be .* a valid dimension> shift (1, 1, 0)
+%!error <DIM must be .* a valid dimension> shift (1, 1, 3)
--- a/scripts/general/shiftdim.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/shiftdim.m	Thu Nov 19 13:08:00 2020 -0800
@@ -59,7 +59,7 @@
 
 function [y, ns]  = shiftdim (x, n)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -104,7 +104,6 @@
 %!assert (size (shiftdim (rand (0, 1, 2))), [0 1 2])
 
 ## Test input validation
-%!error (shiftdim ())
-%!error (shiftdim (1,2,3))
-%!error (shiftdim (1, ones (2)))
-%!error (shiftdim (1, 1.5))
+%!error <Invalid call> shiftdim ()
+%!error shiftdim (1, ones (2))
+%!error shiftdim (1, 1.5)
--- a/scripts/general/sortrows.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/sortrows.m	Thu Nov 19 13:08:00 2020 -0800
@@ -53,7 +53,7 @@
 
 function [s, i] = sortrows (A, c)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -159,8 +159,7 @@
 %! assert (C2, flipud (C));
 
 ## Test input validation
-%!error sortrows ()
-%!error sortrows (1, 2, 3)
+%!error <Invalid call> sortrows ()
 %!error sortrows (1, "ascend")
 %!error sortrows (1, ones (2,2))
 %!error sortrows (1, 0)
--- a/scripts/general/sph2cart.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/sph2cart.m	Thu Nov 19 13:08:00 2020 -0800
@@ -26,22 +26,45 @@
 ## -*- texinfo -*-
 ## @deftypefn  {} {[@var{x}, @var{y}, @var{z}] =} sph2cart (@var{theta}, @var{phi}, @var{r})
 ## @deftypefnx {} {[@var{x}, @var{y}, @var{z}] =} sph2cart (@var{S})
-## @deftypefnx {} {@var{C} =} sph2cart (@dots{})
 ## Transform spherical coordinates to Cartesian coordinates.
 ##
 ## The inputs @var{theta}, @var{phi}, and @var{r} must be the same shape, or
 ## scalar.  If called with a single matrix argument then each row of @var{S}
-## represents the spherical coordinate (@var{theta}, @var{phi}, @var{r}).
+## must represent a spherical coordinate triplet (@var{theta}, @var{phi},
+## @var{r}).
 ##
-## @var{theta} describes the angle relative to the positive x-axis.
+## The outputs @var{x}, @var{y}, @var{z} match the shape of the inputs.  For a
+## matrix input @var{S} the outputs are column vectors with rows corresponding
+## to the rows of the input matrix.
 ##
-## @var{phi} is the angle relative to the xy-plane.
+## @var{theta} describes the azimuth angle relative to the positive x-axis
+## measured in the xy-plane.
+##
+## @var{phi} is the elevation angle measured relative to the xy-plane.
 ##
 ## @var{r} is the distance to the origin @w{(0, 0, 0)}.
 ##
-## If only a single return argument is requested then return a matrix @var{C}
-## where each row represents one Cartesian coordinate
-## (@var{x}, @var{y}, @var{z}).
+## The coordinate transformation is computed using:
+##
+## @tex
+## $$ x = r \cos \phi  \cos \theta $$
+## $$ y = r \cos \phi  \sin \theta $$
+## $$ z = r \sin \phi $$
+## @end tex
+## @ifnottex
+##
+## @example
+## @group
+## @var{x} = r * cos (@var{phi}) * cos (@var{theta})
+## @var{y} = r * cos (@var{phi}) * sin (@var{theta})
+## @var{z} = r * sin (@var{phi})
+## @end group
+## @end example
+##
+## @end ifnottex
+## @c FIXME: Remove this note in Octave 9.1 (two releases after 7.1).
+## Note: For @sc{matlab} compatibility, this function no longer returns a full
+## coordinate matrix when called with a single return argument.
 ## @seealso{cart2sph, pol2cart, cart2pol}
 ## @end deftypefn
 
@@ -52,19 +75,30 @@
   endif
 
   if (nargin == 1)
-    if (! (isnumeric (theta) && ismatrix (theta) && columns (theta) == 3))
-      error ("sph2cart: matrix input must have 3 columns [THETA, PHI, R]");
+    if (! (isnumeric (theta) && ismatrix (theta)))
+      error ("sph2cart: matrix input must be a 2-D numeric array");
+    endif
+    if (columns (theta) != 3 && numel (theta) != 3)
+      error ("sph2cart: matrix input must be a 3-element vector or 3-column array");
     endif
-    r = theta(:,3);
-    phi = theta(:,2);
-    theta = theta(:,1);
+
+    if (numel (theta) == 3)
+      r = theta(3);
+      phi = theta(2);
+      theta = theta(1);
+    else
+      r = theta(:,3);
+      phi = theta(:,2);
+      theta = theta(:,1);
+    endif
+
   else
-    if (! isnumeric (theta) || ! isnumeric (phi) || ! isnumeric (r))
-      error ("sph2cart: THETA, PHI, R must be numeric arrays of the same size, or scalar");
+    if (! (isnumeric (theta) && isnumeric (phi) && isnumeric (r)))
+      error ("sph2cart: THETA, PHI, R must be numeric arrays or scalars");
     endif
     [err, theta, phi, r] = common_size (theta, phi, r);
     if (err)
-      error ("sph2cart: THETA, PHI, R must be numeric arrays of the same size, or scalar");
+      error ("sph2cart: THETA, PHI, R must be the same size or scalars");
     endif
   endif
 
@@ -72,10 +106,6 @@
   y = r .* cos (phi) .* sin (theta);
   z = r .* sin (phi);
 
-  if (nargout <= 1)
-    x = [x(:), y(:), z(:)];
-  endif
-
 endfunction
 
 
@@ -89,13 +119,22 @@
 %! assert (z, [0, 0, 0]);
 
 %!test
+%! t = [0; 0; 0];
+%! p = [0; 0; 0];
+%! r = [0; 1; 2];
+%! [x, y, z] = sph2cart (t, p, r);
+%! assert (x, [0; 1; 2]);
+%! assert (y, [0; 0; 0]);
+%! assert (z, [0; 0; 0]);
+
+%!test
 %! t = 0;
 %! p = [0, 0, 0];
 %! r = [0, 1, 2];
-%! C = sph2cart (t, p, r);
-%! assert (C(:,1), r(:));
-%! assert (C(:,2), [0; 0; 0]);
-%! assert (C(:,3), [0; 0; 0]);
+%! [x, y, z] = sph2cart (t, p, r);
+%! assert (x, [0, 1, 2]);
+%! assert (y, [0, 0, 0]);
+%! assert (z, [0, 0, 0]);
 
 %!test
 %! t = [0, 0, 0];
@@ -123,31 +162,42 @@
 
 %!test
 %! S = [ 0, 0, 1; 0.5*pi, 0, 1; pi, 0, 1];
-%! C = [ 1, 0, 0; 0, 1, 0; -1, 0, 0];
-%! assert (sph2cart (S), C, eps);
+%! [x, y, z] = sph2cart (S);
+%! assert (x, [1; 0; -1], eps);
+%! assert (y, [0; 1; 0], eps);
+%! assert (z, [0; 0; 0], eps);
+
+%!test
+%! S = [ 0, 0, 1; 0.5*pi, 0, 1; pi, 0, 1; pi, pi, 1];
+%! [x, y, z] = sph2cart (S);
+%! assert (x, [1; 0; -1; 1], eps);
+%! assert (y, [0; 1; 0; 0], eps);
+%! assert (z, [0; 0; 0; 0], eps);
+
 
 %!test
 %! [t, p, r] = meshgrid ([0, pi/2], [0, pi/2], [0, 1]);
 %! [x, y, z] = sph2cart (t, p, r);
-%! X = zeros(2, 2, 2);
+%! X = zeros (2, 2, 2);
 %! X(1, 1, 2) = 1;
-%! Y = zeros(2, 2, 2);
+%! Y = zeros (2, 2, 2);
 %! Y(1, 2, 2) = 1;
-%! Z = zeros(2, 2, 2);
+%! Z = zeros (2, 2, 2);
 %! Z(2, :, 2) = [1 1];
 %! assert (x, X, eps);
 %! assert (y, Y, eps);
 %! assert (z, Z);
 
 ## Test input validation
-%!error sph2cart ()
-%!error sph2cart (1,2)
-%!error sph2cart (1,2,3,4)
-%!error <matrix input must have 3 columns> sph2cart ({1,2,3})
-%!error <matrix input must have 3 columns> sph2cart (ones (3,3,2))
-%!error <matrix input must have 3 columns> sph2cart ([1,2,3,4])
-%!error <numeric arrays of the same size> sph2cart ({1,2,3}, [1,2,3], [1,2,3])
-%!error <numeric arrays of the same size> sph2cart ([1,2,3], {1,2,3}, [1,2,3])
-%!error <numeric arrays of the same size> sph2cart ([1,2,3], [1,2,3], {1,2,3})
-%!error <numeric arrays of the same size> sph2cart (ones (3,3,3), 1, ones (3,2,3))
-%!error <numeric arrays of the same size> sph2cart (ones (3,3,3), ones (3,2,3), 1)
+%!error <Invalid call> sph2cart ()
+%!error <Invalid call> sph2cart (1,2)
+%!error <matrix input must be a 2-D numeric array> sph2cart ({1,2,3})
+%!error <matrix input must be a 2-D numeric array> sph2cart (ones (3,3,2))
+%!error <matrix input must be a 3-element> sph2cart ([1,2,3,4])
+%!error <matrix input must be a 3-element> sph2cart ([1,2,3,4; 1,2,3,4; 1,2,3,4])
+%!error <must be numeric arrays or scalars> sph2cart ({1,2,3}, [1,2,3], [1,2,3])
+%!error <must be numeric arrays or scalars> sph2cart ([1,2,3], {1,2,3}, [1,2,3])
+%!error <must be numeric arrays or scalars> sph2cart ([1,2,3], [1,2,3], {1,2,3})
+%!error <must be the same size or scalars> sph2cart ([1,2,3], [1,2,3], [1,2,3]')
+%!error <must be the same size or scalars> sph2cart (ones (3,3,3), 1, ones (3,2,3))
+%!error <must be the same size or scalars> sph2cart (ones (3,3,3), ones (3,2,3), 1)
--- a/scripts/general/structfun.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/structfun.m	Thu Nov 19 13:08:00 2020 -0800
@@ -70,7 +70,7 @@
 ## elements @qcode{"identifier"}, @qcode{"message"} and @qcode{"index"},
 ## giving respectively the error identifier, the error message, and the index
 ## into the input arguments of the element that caused the error.  For an
-## example on how to use an error handler, @pxref{XREFcellfun,,cellfun}.
+## example on how to use an error handler, @pxref{XREFcellfun,,@code{cellfun}}.
 ##
 ## @seealso{cellfun, arrayfun, spfun}
 ## @end deftypefn
--- a/scripts/general/subsindex.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/subsindex.m	Thu Nov 19 13:08:00 2020 -0800
@@ -69,7 +69,7 @@
 
 function idx = subsindex (obj)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -82,5 +82,4 @@
 %!error <not defined for class "double"> subsindex (1)
 
 ## Test input validation
-%!error subsindex ()
-%!error subsindex (1, 2)
+%!error <Invalid call> subsindex ()
--- a/scripts/general/trapz.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/trapz.m	Thu Nov 19 13:08:00 2020 -0800
@@ -67,7 +67,7 @@
 
 function z = trapz (x, y, dim)
 
-  if (nargin < 1) || (nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -153,8 +153,7 @@
 %!assert <*54277> (trapz (ones (3,1), 2), zeros (3,1))
 
 ## Test input validation
-%!error trapz ()
-%!error trapz (1,2,3,4)
+%!error <Invalid call> trapz ()
 %!error <DIM must be an integer> trapz (1, 2, [1 2])
 %!error <DIM must be an integer> trapz (1, 2, 1.5)
 %!error <DIM must be .* a valid dimension> trapz (1, 2, 0)
--- a/scripts/general/xor.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/general/xor.m	Thu Nov 19 13:08:00 2020 -0800
@@ -98,6 +98,6 @@
 %!assert (xor ([1 0], [1 1], [0 0]), logical ([0 1]))
 
 ## Test input validation
-%!error xor ()
-%!error xor (1)
+%!error <Invalid call> xor ()
+%!error <Invalid call> xor (1)
 %!error <X and Y must be of compatible size> xor (ones (3,2), ones (2,3))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/geometry/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/geometry/convhull.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/geometry/convhull.m	Thu Nov 19 13:08:00 2020 -0800
@@ -193,12 +193,12 @@
 %! assert (V == 2);
 
 ## Input validation tests
-%!error convhull ()
-%!error convhull (1,2,3,4,5)
+%!error <Invalid call> convhull ()
+%!error <Invalid call> convhull (1,2,3,4,5)
 %!error <X must be a matrix with 2 or 3 columns> convhull (ones (2,4))
-%!error <OPTIONS must be a string or cell array> convhull (ones (2,2), struct())
+%!error <OPTIONS must be a string or cell array> convhull (ones (2,2), struct ())
 %!error <X must be a matrix with 2 or 3 columns> convhull (ones (2,4), "")
-%!error <OPTIONS must be a string or cell array> convhull (ones (2,2), ones (2,2), struct())
-%!error <OPTIONS must be a string or cell array> convhull (ones (2,2), ones (2,2), ones (2,2), struct())
+%!error <OPTIONS must be a string or cell array> convhull (ones (2,2), ones (2,2), struct ())
+%!error <OPTIONS must be a string or cell array> convhull (ones (2,2), ones (2,2), ones (2,2), struct ())
 %!error <X and Y must be the same size> convhull (1, [1 2])
 %!error <X, Y, and Z must be the same size> convhull (1, [1 2], [1 2])
--- a/scripts/geometry/delaunay.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/geometry/delaunay.m	Thu Nov 19 13:08:00 2020 -0800
@@ -209,12 +209,12 @@
 %! assert (sortrows (sort (delaunay (x, y, z), 2)), [1,2,3,4;1,2,4,5]);
 
 ## Input validation tests
-%!error delaunay ()
-%!error delaunay (1,2,3,4,5)
+%!error <Invalid call> delaunay ()
+%!error <Invalid call> delaunay (1,2,3,4,5)
 %!error <X must be a matrix with 2 or 3 columns> delaunay (ones (2,4))
-%!error <OPTIONS must be a string or cell array> delaunay (ones (2,2), struct())
+%!error <OPTIONS must be a string or cell array> delaunay (ones (2,2), struct ())
 %!error <X must be a matrix with 2 or 3 columns> delaunay (ones (2,4), "")
-%!error <OPTIONS must be a string or cell array> delaunay (ones (2,2), ones (2,2), struct())
-%!error <OPTIONS must be a string or cell array> delaunay (ones (2,2), ones (2,2), ones (2,2), struct())
+%!error <OPTIONS must be a string or cell array> delaunay (ones (2,2), ones (2,2), struct ())
+%!error <OPTIONS must be a string or cell array> delaunay (ones (2,2), ones (2,2), ones (2,2), struct ())
 %!error <X and Y must be the same size> delaunay (1, [1 2])
 %!error <X, Y, and Z must be the same size> delaunay (1, [1 2], [1 2])
--- a/scripts/geometry/delaunayn.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/geometry/delaunayn.m	Thu Nov 19 13:08:00 2020 -0800
@@ -106,8 +106,8 @@
     p12 = p1 - p2;
     p23 = p2 - p3;
     det = cross (p12, p23, 2);
-    idx = abs (det(:,3) ./ sqrt (sumsq (p12, 2))) < tol & ...
-          abs (det(:,3) ./ sqrt (sumsq (p23, 2))) < tol;
+    idx = abs (det (:,3) ./ sqrt (sumsq (p12, 2))) < tol & ...
+          abs (det (:,3) ./ sqrt (sumsq (p23, 2))) < tol;
   else
     ## FIXME: Vectorize this for loop or convert delaunayn to .oct function
     idx = [];
@@ -135,4 +135,4 @@
 ## FIXME: Need tests for delaunayn
 
 ## Input validation tests
-%!error delaunayn ()
+%!error <Invalid call> delaunayn ()
--- a/scripts/geometry/dsearch.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/geometry/dsearch.m	Thu Nov 19 13:08:00 2020 -0800
@@ -35,7 +35,7 @@
 
 function idx = dsearch (x, y, tri, xi, yi, s)
 
-  if (nargin < 5 || nargin > 6)
+  if (nargin < 5)
     print_usage ();
   endif
 
--- a/scripts/geometry/dsearchn.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/geometry/dsearchn.m	Thu Nov 19 13:08:00 2020 -0800
@@ -39,7 +39,7 @@
 
 function [idx, d] = dsearchn (x, tri, xi, outval)
 
-  if (nargin < 2 || nargin > 4)
+  if (nargin < 2)
     print_usage ();
   endif
 
--- a/scripts/geometry/griddata.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/geometry/griddata.m	Thu Nov 19 13:08:00 2020 -0800
@@ -27,123 +27,232 @@
 ## @deftypefn  {} {@var{zi} =} griddata (@var{x}, @var{y}, @var{z}, @var{xi}, @var{yi})
 ## @deftypefnx {} {@var{zi} =} griddata (@var{x}, @var{y}, @var{z}, @var{xi}, @var{yi}, @var{method})
 ## @deftypefnx {} {[@var{xi}, @var{yi}, @var{zi}] =} griddata (@dots{})
+## @deftypefnx {} {@var{vi} =} griddata (@var{x}, @var{y}, @var{z}, @var{v}, @var{xi}, @var{yi}, @var{zi})
+## @deftypefnx {} {@var{vi} =} griddata (@var{x}, @var{y}, @var{z}, @var{v}, @var{xi}, @var{yi}, @var{zi}, @var{method})
+## @deftypefnx {} {@var{vi} =} griddata (@var{x}, @var{y}, @var{z}, @var{v}, @var{xi}, @var{yi}, @var{zi}, @var{method}, @var{options})
 ##
-## Generate a regular mesh from irregular data using interpolation.
+## Interpolate irregular 2-D and 3-D source data at specified points.
+##
+## For 2-D interpolation, the inputs @var{x} and @var{y} define the points
+## where the function @code{@var{z} = f (@var{x}, @var{y})} is evaluated.
+## The inputs @var{x}, @var{y}, @var{z} are either vectors of the same length,
+## or the unequal vectors @var{x}, @var{y} are expanded to a 2-D grid with
+## @code{meshgrid} and @var{z} is a 2-D matrix matching the resulting size of
+## the X-Y grid.
+##
+## The interpolation points are (@var{xi}, @var{yi}).  If, and only if,
+## @var{xi} is a row vector and @var{yi} is a column vector, then
+## @code{meshgrid} will be used to create a mesh of interpolation points.
 ##
-## The function is defined by @code{@var{z} = f (@var{x}, @var{y})}.  Inputs
-## @code{@var{x}, @var{y}, @var{z}} are vectors of the same length or
-## @code{@var{x}, @var{y}} are vectors and @code{@var{z}} is matrix.
+## For 3-D interpolation, the inputs @var{x}, @var{y}, and @var{z} define the
+## points where the function @code{@var{v} = f (@var{x}, @var{y}, @var{z})}
+## is evaluated.  The inputs @var{x}, @var{y}, @var{z} are either vectors of
+## the same length, or if they are of unequal length, then they are expanded to
+## a 3-D grid with @code{meshgrid}.  The size of the input @var{v} must match
+## the size of the original data, either as a vector or a matrix.
 ##
-## The interpolation points are all @code{(@var{xi}, @var{yi})}.  If @var{xi},
-## @var{yi} are vectors then they are made into a 2-D mesh.
+## The optional input interpolation @var{method} can be @qcode{"nearest"},
+## @qcode{"linear"}, or for 2-D data @qcode{"v4"}.  When the method is
+## @qcode{"nearest"}, the output @var{vi} will be the closest point in the
+## original data (@var{x}, @var{y}, @var{z}) to the query point (@var{xi},
+## @var{yi}, @var{zi}).  When the method is @qcode{"linear"}, the output
+## @var{vi} will be a linear interpolation between the two closest points in
+## the original source data in each dimension.  For 2-D cases only, the
+## @qcode{"v4"} method is also available which implements a biharmonic spline
+## interpolation.  If @var{method} is omitted or empty, it defaults to
+## @qcode{"linear"}.
 ##
-## The interpolation method can be @qcode{"nearest"}, @qcode{"cubic"} or
-## @qcode{"linear"}.  If method is omitted it defaults to @qcode{"linear"}.
+## For 3-D interpolation, the optional argument @var{options} is passed
+## directly to Qhull when computing the Delaunay triangulation used for
+## interpolation.  For more information on the defaults and how to pass
+## different values, @pxref{XREFdelaunayn,,@code{delaunayn}}.
+##
+## Programming Notes: If the input is complex the real and imaginary parts
+## are interpolated separately.  Interpolation is normally based on a
+## Delaunay triangulation.  Any query values outside the convex hull of the
+## input points will return @code{NaN}.  However, the @qcode{"v4"} method does
+## not use the triangulation and will return values outside the original data
+## (extrapolation).
 ## @seealso{griddata3, griddatan, delaunay}
 ## @end deftypefn
 
-## Algorithm: xi and yi are not "meshgridded" if both are vectors
-##            of the same size (for compatibility)
+function [rx, ry, rz] = griddata (x, y, z, varargin)
 
-function [rx, ry, rz] = griddata (x, y, z, xi, yi, method = "linear")
-
-  if (nargin < 5 || nargin > 7)
+  if (nargin < 5)
     print_usage ();
   endif
 
-  if (ischar (method))
-    method = tolower (method);
-  endif
-
-  ## Meshgrid if x and y are vectors but z is matrix
-  if (isvector (x) && isvector (y) && all ([numel(y), numel(x)] == size (z)))
-    [x, y] = meshgrid (x, y);
-  endif
-
-  if (isvector (x) && isvector (y) && isvector (z))
-    if (! isequal (length (x), length (y), length (z)))
-      error ("griddata: X, Y, and Z must be vectors of the same length");
-    endif
-  elseif (! size_equal (x, y, z))
-    error ("griddata: lengths of X, Y must match the columns and rows of Z");
-  endif
-
-  ## Meshgrid xi and yi if they are a row and column vector.
-  if (rows (xi) == 1 && columns (yi) == 1)
-    [xi, yi] = meshgrid (xi, yi);
-  elseif (isvector (xi) && isvector (yi))
-    ## Otherwise, convert to column vectors
-    xi = xi(:);
-    yi = yi(:);
-  endif
-
-  if (! size_equal (xi, yi))
-    error ("griddata: XI and YI must be vectors or matrices of same size");
-  endif
-
-  x = x(:);
-  y = y(:);
-  z = z(:);
-
-  ## Triangulate data.
-  tri = delaunay (x, y);
-  zi = NaN (size (xi));
-
-  if (strcmp (method, "cubic"))
-    error ("griddata: cubic interpolation not yet implemented");
+  if (nargin > 6)
+    ## Current 2D implementation has nargin max = 6, since no triangulation
+    ## options are passed to the 2D algorithm. 3D algorithm requires nargin >=7
 
-  elseif (strcmp (method, "nearest"))
-    ## Search index of nearest point.
-    idx = dsearch (x, y, tri, xi, yi);
-    valid = ! isnan (idx);
-    zi(valid) = z(idx(valid));
-
-  elseif (strcmp (method, "linear"))
-    ## Search for every point the enclosing triangle.
-    tri_list = tsearch (x, y, tri, xi(:), yi(:));
-
-    ## Only keep the points within triangles.
-    valid = ! isnan (tri_list);
-    tri_list = tri_list(valid);
-    nr_t = rows (tri_list);
-
-    tri = tri(tri_list,:);
-
-    ## Assign x,y,z for each point of triangle.
-    x1 = x(tri(:,1));
-    x2 = x(tri(:,2));
-    x3 = x(tri(:,3));
-
-    y1 = y(tri(:,1));
-    y2 = y(tri(:,2));
-    y3 = y(tri(:,3));
-
-    z1 = z(tri(:,1));
-    z2 = z(tri(:,2));
-    z3 = z(tri(:,3));
-
-    ## Calculate norm vector.
-    N = cross ([x2-x1, y2-y1, z2-z1], [x3-x1, y3-y1, z3-z1]);
-    ## Normalize.
-    N = diag (norm (N, "rows")) \ N;
-
-    ## Calculate D of plane equation
-    ## Ax+By+Cz+D = 0;
-    D = -(N(:,1) .* x1 + N(:,2) .* y1 + N(:,3) .* z1);
-
-    ## Calculate zi by solving plane equation for xi, yi.
-    zi(valid) = -(N(:,1).*xi(:)(valid) + N(:,2).*yi(:)(valid) + D) ./ N(:,3);
+    if (nargout > 1)
+      error ("griddata: only one output argument valid for 3-D interpolation");
+    endif
+    rx = griddata3 (x, y, z, varargin{:});
 
   else
-    error ("griddata: unknown interpolation METHOD");
-  endif
+    ## for nargin 5 or 6, assign varargin terms to variables for 2D algorithm
+    xi = varargin{1};
+    yi = varargin{2};
+
+    ## Meshgrid if x and y are vectors but z is matrix
+    if (isvector (x) && isvector (y) && all ([numel(y), numel(x)] == size (z)))
+      [x, y] = meshgrid (x, y);
+    endif
+
+    if (isvector (x) && isvector (y) && isvector (z))
+      if (! isequal (length (x), length (y), length (z)))
+        error ("griddata: X, Y, and Z must be vectors of the same length");
+      endif
+    elseif (! size_equal (x, y, z))
+      error ("griddata: lengths of X, Y must match the columns and rows of Z");
+    endif
+
+    ## Meshgrid xi and yi if they are a row and column vector, but not
+    ## if they are simply vectors of the same size (for compatibility).
+    if (isrow (xi) && iscolumn (yi))
+      [xi, yi] = meshgrid (xi, yi);
+    elseif (isvector (xi) && isvector (yi))
+      ## Otherwise, convert to column vectors
+      xi = xi(:);
+      yi = yi(:);
+    endif
+
+    if (! size_equal (xi, yi))
+      error ("griddata: XI and YI must be vectors or matrices of same size");
+    endif
+
+    if (nargin == 6)
+      method = varargin{3};
+      if (isempty (method))
+        method = "linear";
+      elseif (! ischar (method))
+        error ("griddata: METHOD must be a string");
+      else
+        method = tolower (method);
+      endif
+
+      if (any (strcmp (method, {"linear", "nearest", "v4"})))
+        ## Do nothing, these are implemented methods
+      elseif (any (strcmp (method, {"cubic", "natural"})))
+        ## FIXME: implement missing interpolation methods.
+        error ('griddata: "%s" interpolation not yet implemented', method);
+      else
+        error ('griddata: unknown interpolation METHOD: "%s"', method);
+      endif
+    else
+      method = "linear";
+    endif
+
+    x = x(:);
+    y = y(:);
+    z = z(:);
+
+    ## Triangulate data.
+    if (! strcmp (method, "v4"))
+      tri = delaunay (x, y);
+    endif
+    zi = NaN (size (xi));
+
+    if (strcmp (method, "linear"))
+      ## Search for every point the enclosing triangle.
+      tri_list = tsearch (x, y, tri, xi(:), yi(:));
+
+      ## Only keep the points within triangles.
+      valid = ! isnan (tri_list);
+      tri_list = tri_list(valid);
+      nr_t = rows (tri_list);
+
+      tri = tri(tri_list,:);
+
+      ## Assign x,y,z for each point of triangle.
+      x1 = x(tri(:,1));
+      x2 = x(tri(:,2));
+      x3 = x(tri(:,3));
 
-  if (nargout > 1)
-    rx = xi;
-    ry = yi;
-    rz = zi;
-  else
-    rx = zi;
+      y1 = y(tri(:,1));
+      y2 = y(tri(:,2));
+      y3 = y(tri(:,3));
+
+      z1 = z(tri(:,1));
+      z2 = z(tri(:,2));
+      z3 = z(tri(:,3));
+
+      ## Calculate norm vector.
+      N = cross ([x2-x1, y2-y1, z2-z1], [x3-x1, y3-y1, z3-z1]);
+      ## Normalize.
+      N = diag (norm (N, "rows")) \ N;
+
+      ## Calculate D of plane equation: Ax+By+Cz+D = 0
+      D = -(N(:,1) .* x1 + N(:,2) .* y1 + N(:,3) .* z1);
+
+      ## Calculate zi by solving plane equation for xi, yi.
+      zi(valid) = -(N(:,1).*xi(:)(valid) + N(:,2).*yi(:)(valid) + D) ./ N(:,3);
+
+    elseif (strcmp (method, "nearest"))
+      ## Search index of nearest point.
+      idx = dsearch (x, y, tri, xi, yi);
+      valid = ! isnan (idx);
+      zi(valid) = z(idx(valid));
+
+    elseif (strcmp (method, "v4"))
+      ## Use Biharmonic Spline Interpolation Green's Function method.
+      ## Compatible with Matlab v4 interpolation method, based on
+      ## D. Sandwell 1987 and Deng & Tang 2011.
+
+      ## The free space Green Function which solves the two dimensional
+      ## Biharmonic PDE
+      ##
+      ## Delta(Delta(G(X))) = delta(X)
+      ##
+      ## for a point source yields
+      ##
+      ## G(X) = |X|^2 * (ln|X|-1) / (8 * pi)
+      ##
+      ## An N-point Biharmonic Interpolation at the point X is given by
+      ##
+      ## z(X) = sum_j_N (alpha_j * G(X-Xj))
+      ##      = sum_j_N (alpha_j * G(rj))
+      ##
+      ## in which the coefficients alpha_j are the unknowns.  rj is the
+      ## Euclidean distance between X and Xj.
+      ## From N datapoints {zi, Xi} an equation system can be formed:
+      ##
+      ## zi(Xi) = sum_j_N (alpha_j * G(Xi-Xj))
+      ##        = sum_j_N (alpha_j * G(rij))
+      ##
+      ## Its inverse yields the unknowns alpha_j.
+
+      ## Step1: Solve for weight coefficients alpha_j depending on the
+      ## Euclidean distances and the training data set {x,y,z}
+      r = sqrt ((x - x.').^2 + (y - y.').^2);  # size N^2
+      D = (r.^2) .* (log (r) - 1);
+      D(isnan (D)) = 0;  # Fix Green Function for r=0
+      alpha_j = D \ z;
+
+      ## Step2 - Use alphas and Green's functions to get interpolated points.
+      ## Use dim3 projection for vectorized calculation to avoid loops.
+      ## Memory usage is proportional to Ni x N.
+      ## FIXME: if this approach is too memory intensive, revert portion to loop
+      x = permute (x, [3, 2, 1]);
+      y = permute (y, [3, 2, 1]);
+      alpha_j = permute (alpha_j, [3, 2, 1]);
+      r_i = sqrt ((xi - x).^2 + (yi - y).^2);  # size Ni x N
+      Di = (r_i.^2) .* (log (r_i) - 1);
+      Di(isnan (Di)) = 0;  # Fix Green's Function for r==0
+      zi = sum (Di .* alpha_j, 3);
+
+    endif
+
+    if (nargout > 1)
+      rx = xi;
+      ry = yi;
+      rz = zi;
+    else
+      rx = zi;
+    endif
+
   endif
 
 endfunction
@@ -155,10 +264,10 @@
 %! x = 2*rand (100,1) - 1;
 %! y = 2*rand (size (x)) - 1;
 %! z = sin (2*(x.^2 + y.^2));
-%! [xx,yy] = meshgrid (linspace (-1,1,32));
+%! [xx,yy] = meshgrid (linspace (-1, 1, 32));
 %! zz = griddata (x,y,z,xx,yy);
 %! mesh (xx, yy, zz);
-%! title ("nonuniform grid sampled at 100 points");
+%! title ("non-uniform grid sampled at 100 points");
 
 %!demo
 %! clf;
@@ -166,10 +275,11 @@
 %! x = 2*rand (1000,1) - 1;
 %! y = 2*rand (size (x)) - 1;
 %! z = sin (2*(x.^2 + y.^2));
-%! [xx,yy] = meshgrid (linspace (-1,1,32));
+%! [xx,yy] = meshgrid (linspace (-1, 1, 32));
 %! zz = griddata (x,y,z,xx,yy);
 %! mesh (xx, yy, zz);
-%! title ("nonuniform grid sampled at 1000 points");
+%! title ({"non-uniform grid sampled at 1,000 points",
+%!         'method = "linear"'});
 
 %!demo
 %! clf;
@@ -177,34 +287,63 @@
 %! x = 2*rand (1000,1) - 1;
 %! y = 2*rand (size (x)) - 1;
 %! z = sin (2*(x.^2 + y.^2));
-%! [xx,yy] = meshgrid (linspace (-1,1,32));
+%! [xx,yy] = meshgrid (linspace (-1, 1, 32));
 %! zz = griddata (x,y,z,xx,yy,"nearest");
 %! mesh (xx, yy, zz);
-%! title ("nonuniform grid sampled at 1000 points with nearest neighbor");
+%! title ({"non-uniform grid sampled at 1,000 points",
+%!         'method = "nearest neighbor"'});
 
 %!testif HAVE_QHULL
-%! [xx,yy] = meshgrid (linspace (-1,1,32));
+%! [xx, yy] = meshgrid (linspace (-1, 1, 32));
 %! x = xx(:);
 %! x = x + 10*(2*round (rand (size (x))) - 1) * eps;
 %! y = yy(:);
 %! y = y + 10*(2*round (rand (size (y))) - 1) * eps;
 %! z = sin (2*(x.^2 + y.^2));
-%! zz = griddata (x,y,z,xx,yy,"linear");
+%! zz = griddata (x,y,z,xx,yy, "linear");
 %! zz2 = sin (2*(xx.^2 + yy.^2));
 %! zz2(isnan (zz)) = NaN;
 %! assert (zz, zz2, 100*eps);
 
+%!testif HAVE_QHULL
+%! [xx, yy] = meshgrid (linspace (-1, 1, 5));
+%! x = xx(:);
+%! x = x + 10*(2*round (rand (size (x))) - 1) * eps;
+%! y = yy(:);
+%! y = y + 10*(2*round (rand (size (y))) - 1) * eps;
+%! z = 2*(x.^2 + y.^2);
+%! zz = griddata (x,y,z,xx,yy, "v4");
+%! zz2 = 2*(xx.^2 + yy.^2);
+%! zz2(isnan (zz)) = NaN;
+%! assert (zz, zz2, 100*eps);
+
+%!testif HAVE_QHULL
+%! [xx, yy] = meshgrid (linspace (-1, 1, 5));
+%! x = xx(:);
+%! x = x + 10*(2*round (rand (size (x))) - 1) * eps;
+%! y = yy(:);
+%! y = y + 10*(2*round (rand (size (y))) - 1) * eps;
+%! z = 2*(x.^2 + y.^2);
+%! zz = griddata (x,y,z,xx,yy, "nearest");
+%! zz2 = 2*(xx.^2 + yy.^2);
+%! zz2(isnan (zz)) = NaN;
+%! assert (zz, zz2, 100*eps);
+
 ## Test input validation
-%!error griddata ()
-%!error griddata (1)
-%!error griddata (1,2)
-%!error griddata (1,2,3)
-%!error griddata (1,2,3,4)
-%!error griddata (1,2,3,4,5,6,7)
+%!error <Invalid call> griddata ()
+%!error <Invalid call> griddata (1)
+%!error <Invalid call> griddata (1,2)
+%!error <Invalid call> griddata (1,2,3)
+%!error <Invalid call> griddata (1,2,3,4)
+%!error <only one output argument> [xi,yi] = griddata (1,2,3,4,5,6,7)
+%!error <vectors of the same length> griddata (1:4, 1:3, 1:3, 1:3, 1:3)
+%!error <vectors of the same length> griddata (1:3, 1:4, 1:3, 1:3, 1:3)
 %!error <vectors of the same length> griddata (1:3, 1:3, 1:4, 1:3, 1:3)
-%!error <vectors of the same length> griddata (1:3, 1:4, 1:3, 1:3, 1:3)
-%!error <vectors of the same length> griddata (1:4, 1:3, 1:3, 1:3, 1:3)
 %!error <the columns and rows of Z> griddata (1:4, 1:3, ones (4,4), 1:3, 1:3)
 %!error <the columns and rows of Z> griddata (1:4, 1:3, ones (3,5), 1:3, 1:3)
-%!error <matrices of same size> griddata (1:3, 1:3, 1:3, 1:4, 1:3)
-%!error <matrices of same size> griddata (1:3, 1:3, 1:3, 1:3, 1:4)
+%!error <XI and YI .* matrices of same size> griddata (1:3, 1:3, 1:3, 1:4, 1:3)
+%!error <XI and YI .* matrices of same size> griddata (1:3, 1:3, 1:3, 1:3, 1:4)
+%!error <METHOD must be a string> griddata (1,2,3,4,5, {"linear"})
+%!error <"cubic" .* not yet implemented> griddata (1,2,3,4,5, "cubic")
+%!error <"natural" .* not yet implemented> griddata (1,2,3,4,5, "natural")
+%!error <unknown interpolation METHOD: "foobar"> griddata (1,2,3,4,5, "foobar")
--- a/scripts/geometry/griddata3.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/geometry/griddata3.m	Thu Nov 19 13:08:00 2020 -0800
@@ -28,18 +28,34 @@
 ## @deftypefnx {} {@var{vi} =} griddata3 (@var{x}, @var{y}, @var{z}, @var{v}, @var{xi}, @var{yi}, @var{zi}, @var{method})
 ## @deftypefnx {} {@var{vi} =} griddata3 (@var{x}, @var{y}, @var{z}, @var{v}, @var{xi}, @var{yi}, @var{zi}, @var{method}, @var{options})
 ##
-## Generate a regular mesh from irregular data using interpolation.
+## Interpolate irregular 3-D source data at specified points.
 ##
-## The function is defined by @code{@var{v} = f (@var{x}, @var{y}, @var{z})}.
+## The inputs @var{x}, @var{y}, and @var{z} define the points where the
+## function @code{@var{v} = f (@var{x}, @var{y}, @var{z})} is evaluated.  The
+## inputs @var{x}, @var{y}, @var{z} are either vectors of the same length, or
+## if they are of unequal length, then they are expanded to a 3-D grid with
+## @code{meshgrid}.  The size of the input @var{v} must match the size of the
+## original data, either as a vector or a matrix.
+##
 ## The interpolation points are specified by @var{xi}, @var{yi}, @var{zi}.
 ##
-## The interpolation method can be @qcode{"nearest"} or @qcode{"linear"}.
-## If method is omitted it defaults to @qcode{"linear"}.
+## The optional input interpolation @var{method} can be @qcode{"nearest"} or
+## @qcode{"linear"}.  When the method is @qcode{"nearest"}, the output @var{vi}
+## will be the closest point in the original data (@var{x}, @var{y}, @var{z})
+## to the query point (@var{xi}, @var{yi}, @var{zi}).  When the method is
+## @qcode{"linear"}, the output @var{vi} will be a linear interpolation between
+## the two closest points in the original source data in each dimension.
+## If @var{method} is omitted or empty, it defaults to @qcode{"linear"}.
 ##
 ## The optional argument @var{options} is passed directly to Qhull when
 ## computing the Delaunay triangulation used for interpolation.  See
 ## @code{delaunayn} for information on the defaults and how to pass different
 ## values.
+##
+## Programming Notes: If the input is complex the real and imaginary parts
+## are interpolated separately.  Interpolation is based on a Delaunay
+## triangulation and any query values outside the convex hull of the input
+## points will return @code{NaN}.
 ## @seealso{griddata, griddatan, delaunayn}
 ## @end deftypefn
 
@@ -105,3 +121,7 @@
 %! vi = griddata3 (x, y, z, v, xi, yi, zi, "nearest");
 %! vv = vi - xi.^2 - yi.^2 - zi.^2;
 %! assert (max (abs (vv(:))), 0.385, 0.1);
+
+## FIXME: Ideally, there should be BIST tests for input validation.
+## However, this function is deprecated in Matlab and it probably isn't worth
+## the coding time to work on a function that will be removed soon.
--- a/scripts/geometry/griddatan.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/geometry/griddatan.m	Thu Nov 19 13:08:00 2020 -0800
@@ -28,18 +28,56 @@
 ## @deftypefnx {} {@var{yi} =} griddatan (@var{x}, @var{y}, @var{xi}, @var{method})
 ## @deftypefnx {} {@var{yi} =} griddatan (@var{x}, @var{y}, @var{xi}, @var{method}, @var{options})
 ##
-## Generate a regular mesh from irregular data using interpolation.
+## Interpolate irregular source data @var{x}, @var{y} at points specified by
+## @var{xi}.
 ##
-## The function is defined by @code{@var{y} = f (@var{x})}.
-## The interpolation points are all @var{xi}.
+## The input @var{x} is an MxN matrix representing M points in an N-dimensional
+## space.  The input @var{y} is a single-valued column vector (Mx1)
+## representing a function evaluated at the points @var{x}, i.e.,
+## @code{@var{y} = fcn (@var{x})}.  The input @var{xi} is a list of points
+## for which the function output @var{yi} should be approximated through
+## interpolation.  @var{xi} must have the same number of columns (@var{N})
+## as @var{x} so that the dimensionality matches.
 ##
-## The interpolation method can be @qcode{"nearest"} or @qcode{"linear"}.
-## If method is omitted it defaults to @qcode{"linear"}.
+## The optional input interpolation @var{method} can be @qcode{"nearest"} or
+## @qcode{"linear"}.  When the method is @qcode{"nearest"}, the output @var{yi}
+## will be the closest point in the original data @var{x} to the query point
+## @var{xi}.  When the method is @qcode{"linear"}, the output @var{yi} will
+## be a linear interpolation between the two closest points in the original
+## source data.  If @var{method} is omitted or empty, it defaults to
+## @qcode{"linear"}.
 ##
 ## The optional argument @var{options} is passed directly to Qhull when
 ## computing the Delaunay triangulation used for interpolation.  See
 ## @code{delaunayn} for information on the defaults and how to pass different
 ## values.
+##
+## Example
+##
+## @example
+## @group
+## ## Evaluate sombrero() function at irregular data points
+## x = 16*gallery ("uniformdata", [200,1], 1) - 8;
+## y = 16*gallery ("uniformdata", [200,1], 11) - 8;
+## z = sin (sqrt (x.^2 + y.^2)) ./ sqrt (x.^2 + y.^2);
+## ## Create a regular grid and interpolate data
+## [xi, yi] = ndgrid (linspace (-8, 8, 50));
+## zi = griddatan ([x, y], z, [xi(:), yi(:)]);
+## zi = reshape (zi, size (xi));
+## ## Plot results
+## clf ();
+## plot3 (x, y, z, "or");
+## hold on
+## surf (xi, yi, zi);
+## legend ("Original Data", "Interpolated Data");
+## @end group
+## @end example
+##
+## Programming Notes: If the input is complex the real and imaginary parts
+## are interpolated separately.  Interpolation is based on a Delaunay
+## triangulation and any query values outside the convex hull of the input
+## points will return @code{NaN}.  For 2-D and 3-D data additional
+## interpolation methods are available by using the @code{griddata} function.
 ## @seealso{griddata, griddata3, delaunayn}
 ## @end deftypefn
 
@@ -49,15 +87,41 @@
     print_usage ();
   endif
 
-  if (ischar (method))
-    method = tolower (method);
-  endif
-
   [m, n] = size (x);
   [mi, ni] = size (xi);
 
-  if (n != ni || rows (y) != m || columns (y) != 1)
-    error ("griddatan: dimensional mismatch");
+  if (m < n + 1)
+    error ("griddatan: number of points in X (rows of X) must be greater than dimensionality of data + 1 (columns of X + 1)");
+  endif
+  if (! iscolumn (y) || rows (y) != m)
+    error ("griddatan: Y must be a column vector with the same number of points (rows) as X");
+  endif
+  if (n != ni)
+    error ("griddatan: dimension of query data XI (columns) must match X");
+  endif
+
+  if (nargin > 3)
+    if (isempty (method))
+      method = "linear";
+    elseif (! ischar (method))
+      error ("griddatan: METHOD must be a string");
+    else
+      method = tolower (method);
+    endif
+
+    if (strcmp (method, "linear") || strcmp (method, "nearest"))
+      ## Do nothing, these are implemented methods
+    elseif (strcmp (method, "v4"))
+      error ('griddatan: "%s" METHOD is available for 2-D inputs by using "griddata"', method);
+
+    elseif (any (strcmp (method, {"cubic", "natural"})))
+      ## FIXME: Remove when griddata.m supports these methods.
+      error ('griddatan: "%s" interpolation METHOD not yet implemented', method);
+
+    else
+      error ('griddatan: unknown interpolation METHOD: "%s"', method);
+    endif
+
   endif
 
   ## triangulate data
@@ -65,13 +129,7 @@
 
   yi = NaN (mi, 1);
 
-  if (strcmp (method, "nearest"))
-    ## search index of nearest point
-    idx = dsearchn (x, tri, xi);
-    valid = ! isnan (idx);
-    yi(valid) = y(idx(valid));
-
-  elseif (strcmp (method, "linear"))
+  if (strcmp (method, "linear"))
     ## search for every point the enclosing triangle
     [tri_list, bary_list] = tsearchn (x, tri, xi);
 
@@ -90,7 +148,11 @@
     endif
 
   else
-    error ("griddatan: unknown interpolation METHOD");
+    ## search index of nearest point
+    idx = dsearchn (x, tri, xi);
+    valid = ! isnan (idx);
+    yi(valid) = y(idx(valid));
+
   endif
 
 endfunction
@@ -102,8 +164,8 @@
 %! x = 2*rand (100,2) - 1;
 %! x = [x;1,1;1,-1;-1,-1;-1,1];
 %! y = sin (2 * sum (x.^2,2));
-%! zz = griddatan (x,y,xi,"linear");
-%! zz2 = griddata (x(:,1),x(:,2),y,xi(:,1),xi(:,2),"linear");
+%! zz = griddatan (x,y,xi, "linear");
+%! zz2 = griddata (x(:,1),x(:,2),y,xi(:,1),xi(:,2), "linear");
 %! assert (zz, zz2, 1e-10);
 
 %!testif HAVE_QHULL
@@ -112,8 +174,8 @@
 %! x = 2*rand (100,2) - 1;
 %! x = [x;1,1;1,-1;-1,-1;-1,1];
 %! y = sin (2*sum (x.^2,2));
-%! zz = griddatan (x,y,xi,"nearest");
-%! zz2 = griddata (x(:,1),x(:,2),y,xi(:,1),xi(:,2),"nearest");
+%! zz = griddatan (x,y,xi, "nearest");
+%! zz2 = griddata (x(:,1),x(:,2),y,xi(:,1),xi(:,2), "nearest");
 %! assert (zz, zz2, 1e-10);
 
 %!testif HAVE_QHULL <*56515>
@@ -121,3 +183,17 @@
 %! y = [ 1; 2; 3; 4 ];
 %! xi = [ .5, .5 ];
 %! yi = griddatan (x, y, xi);
+
+## Test input validation
+%!error <Invalid call> griddatan ()
+%!error <Invalid call> griddatan (1)
+%!error <Invalid call> griddatan (1,2)
+%!error <number of points in X> griddatan (1,2,3)
+%!error <Y must be a column vector> griddatan ([1;2],[3,4], 1)
+%!error <Y must .* same number of points .* as X> griddatan ([1;2],[3;4;5], 1)
+%!error <dimension of .* XI .* must match X> griddatan ([1;2],[3;4], [1, 2])
+%!error <METHOD must be a string> griddatan ([1;2],[3;4], 1, 5)
+%!error <"v4" METHOD is available for 2-D> griddatan ([1;2],[3;4], 1, "v4")
+%!error <"cubic" .* not yet implemented> griddatan ([1;2],[3;4], 1, "cubic")
+%!error <"natural" .* not yet implemented> griddatan ([1;2],[3;4], 1, "natural")
+%!error <unknown .* METHOD: "foobar"> griddatan ([1;2],[3;4], 1, "foobar")
--- a/scripts/geometry/inpolygon.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/geometry/inpolygon.m	Thu Nov 19 13:08:00 2020 -0800
@@ -158,10 +158,9 @@
 %! assert (on, ON);
 
 ## Test input validation
-%!error inpolygon ()
-%!error inpolygon (1, 2)
-%!error inpolygon (1, 2, 3)
-%!error inpolygon (1, 2, 3, 4, 5)
+%!error <Invalid call> inpolygon ()
+%!error <Invalid call> inpolygon (1, 2)
+%!error <Invalid call> inpolygon (1, 2, 3)
 %!error <X and Y must be real> inpolygon (1i, 1, [3, 4], [5, 6])
 %!error <X and Y must be real> inpolygon (1, {1}, [3, 4], [5, 6])
 %!error <X and Y must be .* the same size> inpolygon (1, [1,2], [3, 4], [5, 6])
--- a/scripts/geometry/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/geometry/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/convhull.m \
   %reldir%/delaunay.m \
   %reldir%/delaunayn.m \
--- a/scripts/geometry/rotx.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/geometry/rotx.m	Thu Nov 19 13:08:00 2020 -0800
@@ -27,8 +27,8 @@
 ## @deftypefn {} {@var{T} =} rotx (@var{angle})
 ##
 ## @code{rotx} returns the 3x3 transformation matrix corresponding to an active
-## rotation of the vector about the x-axis by the specified @var{angle}, given
-## in degrees, where a positive angle corresponds to a counterclockwise
+## rotation of a vector about the x-axis by the specified @var{angle}, given in
+## degrees, where a positive angle corresponds to a counterclockwise
 ## rotation when viewing the y-z plane from the positive x side.
 ##
 ## The form of the transformation matrix is:
@@ -51,7 +51,8 @@
 ## @end ifnottex
 ##
 ## This rotation matrix is intended to be used as a left-multiplying matrix
-## when acting on a column vector, using the notation @var{v} = @var{T}@var{u}.
+## when acting on a column vector, using the notation
+## @code{@var{v} = @var{T}*@var{u}}.
 ## For example, a vector, @var{u}, pointing along the positive y-axis, rotated
 ## 90-degrees about the x-axis, will result in a vector pointing along the
 ## positive z-axis:
@@ -81,28 +82,28 @@
 ## @seealso{roty, rotz}
 ## @end deftypefn
 
-function retmat = rotx (angle_in_deg)
+function T = rotx (angle)
 
-  if ((nargin != 1) || ! isscalar (angle_in_deg))
+  if (nargin < 1 || ! isscalar (angle))
     print_usage ();
   endif
 
-  angle_in_rad = angle_in_deg * pi / 180;
+  angle *= pi / 180;
 
-  s = sin (angle_in_rad);
-  c = cos (angle_in_rad);
+  s = sin (angle);
+  c = cos (angle);
 
-  retmat = [1 0 0; 0 c -s; 0 s c];
+  T = [1 0 0; 0 c -s; 0 s c];
 
 endfunction
 
+
 ## Function output tests
-%!assert (rotx (0), [1 0 0; 0 1 0; 0 0 1]);
-%!assert (rotx (45), [1, 0, 0; [0; 0],[(sqrt(2)/2).*[1 -1; 1 1]]], 1e-12);
-%!assert (rotx (90), [1 0 0; 0 0 -1; 0 1 0], 1e-12);
-%!assert (rotx (180), [1 0 0; 0 -1 0; 0 0 -1], 1e-12);
+%!assert (rotx (0), [1 0 0; 0 1 0; 0 0 1])
+%!assert (rotx (45), [1, 0, 0; [0; 0],[(sqrt(2)/2).*[1 -1; 1 1]]], 1e-12)
+%!assert (rotx (90), [1 0 0; 0 0 -1; 0 1 0], 1e-12)
+%!assert (rotx (180), [1 0 0; 0 -1 0; 0 0 -1], 1e-12)
 
 ## Test input validation
-%!error rotx ()
-%!error rotx (1, 2)
-%!error rotx ([1 2 3])
+%!error <Invalid call> rotx ()
+%!error <Invalid call> rotx ([1 2 3])
--- a/scripts/geometry/roty.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/geometry/roty.m	Thu Nov 19 13:08:00 2020 -0800
@@ -51,7 +51,8 @@
 ## @end ifnottex
 ##
 ## This rotation matrix is intended to be used as a left-multiplying matrix
-## when acting on a column vector, using the notation @var{v} = @var{T}@var{u}.
+## when acting on a column vector, using the notation
+## @code{@var{v} = @var{T}*@var{u}}.
 ## For example, a vector, @var{u}, pointing along the positive z-axis, rotated
 ## 90-degrees about the y-axis, will result in a vector pointing along the
 ## positive x-axis:
@@ -81,28 +82,28 @@
 ## @seealso{rotx, rotz}
 ## @end deftypefn
 
-function retmat = roty (angle_in_deg)
+function T = roty (angle)
 
-  if ((nargin != 1) || ! isscalar (angle_in_deg))
+  if (nargin < 1 || ! isscalar (angle))
     print_usage ();
   endif
 
-  angle_in_rad = angle_in_deg * pi / 180;
+  angle *= pi / 180;
 
-  s = sin (angle_in_rad);
-  c = cos (angle_in_rad);
+  s = sin (angle);
+  c = cos (angle);
 
-  retmat = [c 0 s; 0 1 0; -s 0 c];
+  T = [c 0 s; 0 1 0; -s 0 c];
 
 endfunction
 
+
 ## Function output tests
-%!assert (roty (0), [1 0 0; 0 1 0; 0 0 1]);
-%!assert (roty (45), [sqrt(2) 0 sqrt(2); 0 2 0; -sqrt(2) 0 sqrt(2)]./2, 1e-12);
-%!assert (roty (90), [0 0 1; 0 1 0; -1 0 0], 1e-12);
-%!assert (roty (180), [-1 0 0; 0 1 0; 0 0 -1], 1e-12);
+%!assert (roty (0), [1 0 0; 0 1 0; 0 0 1])
+%!assert (roty (45), [sqrt(2) 0 sqrt(2); 0 2 0; -sqrt(2) 0 sqrt(2)]./2, 1e-12)
+%!assert (roty (90), [0 0 1; 0 1 0; -1 0 0], 1e-12)
+%!assert (roty (180), [-1 0 0; 0 1 0; 0 0 -1], 1e-12)
 
 ## Test input validation
-%!error roty ()
-%!error roty (1, 2)
-%!error roty ([1 2 3])
+%!error <Invalid call> roty ()
+%!error <Invalid call> roty ([1 2 3])
--- a/scripts/geometry/rotz.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/geometry/rotz.m	Thu Nov 19 13:08:00 2020 -0800
@@ -51,7 +51,8 @@
 ## @end ifnottex
 ##
 ## This rotation matrix is intended to be used as a left-multiplying matrix
-## when acting on a column vector, using the notation @var{v} = @var{T}@var{u}.
+## when acting on a column vector, using the notation
+## @code{@var{v} = @var{T}*@var{u}}.
 ## For example, a vector, @var{u}, pointing along the positive x-axis, rotated
 ## 90-degrees about the z-axis, will result in a vector pointing along the
 ## positive y-axis:
@@ -81,28 +82,28 @@
 ## @seealso{rotx, roty}
 ## @end deftypefn
 
-function retmat = rotz (angle_in_deg)
+function T = rotz (angle)
 
-  if ((nargin != 1) || ! isscalar (angle_in_deg))
+  if (nargin < 1 || ! isscalar (angle))
     print_usage ();
   endif
 
-  angle_in_rad = angle_in_deg * pi / 180;
+  angle = angle * pi / 180;
 
-  s = sin (angle_in_rad);
-  c = cos (angle_in_rad);
+  s = sin (angle);
+  c = cos (angle);
 
-  retmat = [c -s 0; s c 0; 0 0 1];
+  T = [c -s 0; s c 0; 0 0 1];
 
 endfunction
 
+
 ## Function output tests
-%!assert (rotz (0), [1 0 0; 0 1 0; 0 0 1]);
-%!assert (rotz (45), [(sqrt(2)/2).*[1 -1; 1 1] ,[0; 0]; 0, 0, 1], 1e-12);
-%!assert (rotz (90), [0 -1 0; 1 0 0; 0 0 1], 1e-12);
-%!assert (rotz (180), [-1 0 0; 0 -1 0; 0 0 1], 1e-12);
+%!assert (rotz (0), [1 0 0; 0 1 0; 0 0 1])
+%!assert (rotz (45), [(sqrt(2)/2).*[1 -1; 1 1] ,[0; 0]; 0, 0, 1], 1e-12)
+%!assert (rotz (90), [0 -1 0; 1 0 0; 0 0 1], 1e-12)
+%!assert (rotz (180), [-1 0 0; 0 -1 0; 0 0 1], 1e-12)
 
 ## Test input validation
-%!error rotz ()
-%!error rotz (1, 2)
-%!error rotz ([1 2 3])
+%!error <Invalid call> rotz ()
+%!error <Invalid call> rotz ([1 2 3])
--- a/scripts/geometry/voronoi.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/geometry/voronoi.m	Thu Nov 19 13:08:00 2020 -0800
@@ -224,7 +224,7 @@
 
 
 ## Input validation tests
-%!error voronoi ()
+%!error <Invalid call> voronoi ()
 %!error voronoi (ones (3,1))
 %!error voronoi (ones (3,1), ones (3,1), "invalid1", "invalid2", "invalid3")
 %!error <HAX argument must be an axes object> voronoi (0, ones (3,1), ones (3,1))
--- a/scripts/geometry/voronoin.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/geometry/voronoin.m	Thu Nov 19 13:08:00 2020 -0800
@@ -57,7 +57,7 @@
 
 function [C, F] = voronoin (pts, options)
 
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -80,6 +80,5 @@
 
 ## FIXME: Need functional tests
 
-%!error voronoin ()
-%!error voronoin (1,2,3)
+%!error <Invalid call> voronoin ()
 %!error <number of points must be greater than their dimension> voronoin ([1 2])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/gui/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/gui/errordlg.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/gui/errordlg.m	Thu Nov 19 13:08:00 2020 -0800
@@ -39,7 +39,7 @@
 ## ("\n"), or it may be a cellstr array with one element for each line.
 ##
 ## The third optional argument @var{opt} controls the behavior of the dialog.
-## See @code{msgbox} for details.
+## For details, @pxref{XREFmsgbox,,@code{msgbox}}.
 ##
 ## The return value @var{h} is a handle to the figure object used for
 ## building the dialog.
--- a/scripts/gui/getappdata.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/gui/getappdata.m	Thu Nov 19 13:08:00 2020 -0800
@@ -38,7 +38,7 @@
 
 function value = getappdata (h, name)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -90,8 +90,7 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error getappdata ()
-%!error getappdata (1,2,3)
+%!error <Invalid call> getappdata ()
 %!error <H must be a scalar .* graphic handle> getappdata (-1, "hello")
 %!error <NAME must be a string> getappdata (0, 1)
 %!error <Only one handle H may be used when fetching appdata> getappdata ([0 0])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/gui/getpixelposition.m	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,126 @@
+########################################################################
+##
+## Copyright (C) 2020 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn  {} {@var{pos} =} getpixelposition (@var{h})
+## @deftypefnx {} {@var{pos} =} getpixelposition (@var{h}, @var{rel_to_fig})
+## Return the position of a user interface component in pixel units.
+##
+## The first argument @var{h} must be a handle to a valid graphics object of
+## type uibuttongroup, uicontrol, uipanel, uitable, axes, or figure.  For other
+## object types, the function returns zeros.
+##
+## By default, the position is returned relative to the object's parent.
+## If the second argument @var{rel_to_fig} is logically true, the position
+## is computed relative to the enclosing figure object.
+##
+## The return value @var{pos} is a 4-element vector with values
+## @code{[ lower_left_X, lower_left_Y, width, height ]}.
+##
+## @seealso{get}
+## @end deftypefn
+
+function pos = getpixelposition (h, rel_to_fig = false)
+
+  if (nargin < 1)
+    print_usage ();
+  endif
+
+  if (! isscalar (h) || ! ishghandle (h))
+    error ("getpixelposition: H must be a scalar graphics handle");
+  endif
+
+  if (! any (strcmp (get (h, "type"), {"uibuttongroup", "uicontrol", ...
+                                       "uitable", "uipanel", ...
+                                       "axes", "figure"})))
+    pos = zeros (1, 4);
+    return;
+  endif
+
+  pos = __get_position__ (h, "pixels");
+
+  if (rel_to_fig)
+    while (! isfigure (h))
+      h = get (h, "parent");
+      pos(1:2) += __get_position__ (h, "pixels")(1:2);
+    endwhile
+  endif
+
+endfunction
+
+
+%!demo
+%! clf ();
+%! hax = axes ("position", [0.25 0.25 0.5 0.5])
+%! pos = getpixelposition (hax);
+%! han = annotation ("rectangle");
+%! set (han, "units", "pixels", "position", pos, "color", "r")
+
+%!demo
+%! hf = clf ();
+%! hbg = uibuttongroup (hf, "position", [0.2 0.7 0.2 0.2]);
+%! hb1 = uicontrol (hbg, "style", "radiobutton", ...
+%!                       "string", "Choice 1", ...
+%!                       "units", "normalized", ...
+%!                       "position", [0.01 0.5 0.98 0.5]);
+%! hb2 = uicontrol (hbg, "style", "radiobutton", ...
+%!                       "string", "Choice 2", ...
+%!                       "units", "normalized", ...
+%!                       "position", [0.01 0 0.98 0.5]);
+%! pos = getpixelposition (hbg);
+%! han = annotation ("rectangle");
+%! set (han, "units", "pixels", "position", pos, "color", "r")
+
+
+%!test
+%! pos = [0 0 400 400];
+%! hf = figure ("visible", "off", "menubar", "none", "position", pos);
+%! unwind_protect
+%!   hp = uipanel (hf, "position", [0.5 0.5 0.5 0.5]);
+%!   hax = axes (hp, "position", [0.5 0.5 0.5 0.5]);
+%!   assert (getpixelposition (hax), [100 100 100 100], 2);
+%!   assert (getpixelposition (hax, true), [300 300 100 100], 2);
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
+%!test
+%! ## Compatibility: return zeros for root figure
+%! assert (getpixelposition (groot), zeros (1, 4));
+
+%!test
+%! ## Compatibility: return the same for figures regardless of rel_to_fig
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   assert (getpixelposition (hf), getpixelposition (hf, true));
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
+## Test input validation
+%!error <Invalid call> getpixelposition ()
+%!error <H must be a scalar> getpixelposition ([1, 2])
+%!error <H must be a .* graphics handle> getpixelposition (-1)
+
--- a/scripts/gui/guidata.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/gui/guidata.m	Thu Nov 19 13:08:00 2020 -0800
@@ -40,7 +40,7 @@
 
 function dataout = guidata (h, data)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -65,7 +65,6 @@
 
 
 ## Test input validation
-%!error guidata ()
-%!error guidata (1,2,3)
+%!error <Invalid call> guidata ()
 %!error <H must be a valid object handle> guidata ({1})
 %!error <no ancestor figure of H found> guidata (0)
--- a/scripts/gui/guihandles.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/gui/guihandles.m	Thu Nov 19 13:08:00 2020 -0800
@@ -42,10 +42,6 @@
 
 function hdata = guihandles (h)
 
-  if (nargin > 2)
-    print_usage ();
-  endif
-
   if (nargin == 1)
     if (! ishghandle (h))
       error ("guidata: H must be a valid object handle");
--- a/scripts/gui/isappdata.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/gui/isappdata.m	Thu Nov 19 13:08:00 2020 -0800
@@ -34,7 +34,7 @@
 
 function valid = isappdata (h, name)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -66,7 +66,6 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error isappdata ()
-%!error isappdata (1,2,3)
+%!error <Invalid call> isappdata ()
 %!error <H must be a scalar .* graphic handle> isappdata (-1, "hello")
 %!error <NAME must be a string> isappdata (0, 1)
--- a/scripts/gui/listdlg.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/gui/listdlg.m	Thu Nov 19 13:08:00 2020 -0800
@@ -200,7 +200,8 @@
 %! endfor
 
 ## Test input validation
-%!error listdlg ()
+%!error <Invalid call> listdlg ()
+%!error <Invalid call> listdlg (1)
 %!error listdlg ("SelectionMode")
 %!error <must occur in pairs> listdlg ("SelectionMode", "multiple", "Name")
 %!error <invalid KEY .FooBar.> listdlg ("FooBar", 1)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/gui/listfonts.m	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,74 @@
+########################################################################
+##
+## Copyright (C) 2020 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn  {} {fonts =} listfonts ()
+## @deftypefnx {} {fonts =} listfonts (@var{h})
+## List system fonts.
+##
+## If a handle to a graphics object @var{h} is provided, also include the
+## font from the object's @qcode{"FontName"} property in the list.
+##
+## Programming Note: On systems that don't use FontConfig natively (all but
+## Linux), the font cache is built when Octave is installed.  You will need to
+## run @code{system ("fc-cache -fv")} manually after installing new fonts.
+##
+## @seealso{uisetfont, text, axes, uicontrol}
+## @end deftypefn
+
+function fonts = listfonts (h)
+
+  if (nargin == 1 && (! ishghandle (h) || ! isprop (h, "fontname")))
+    error (['listfonts: H must be a handle to a graphics object ', ...
+            'with a "fontname" property']);
+  endif
+
+  persistent sysfonts = get_fonts ();
+  fonts = sysfonts;
+
+  if (nargin == 1 && ! isempty (h))
+    font = get (h, "fontname");
+    if (! strcmp (font, "*"))
+      fonts = unique ([fonts font]);
+    endif
+  endif
+
+endfunction
+
+function fonts = get_fonts ()
+
+  fontfiles = __get_system_fonts__ ();
+
+  fonts = unique ({fontfiles.family, "FreeSans"});
+
+endfunction
+
+
+## Test input validation
+%!error listfonts (0, 0)
+%!error <H must be a handle to a graphics object with a "fontname" property>
+%! s = listfonts (0);
+%!error <H must be a handle to a graphics object>
+%! s = listfonts (struct ());
--- a/scripts/gui/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/gui/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -14,14 +14,17 @@
   %reldir%/private/__uiputfile_fltk__.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/dialog.m \
   %reldir%/errordlg.m \
   %reldir%/getappdata.m \
+  %reldir%/getpixelposition.m \
   %reldir%/guidata.m \
   %reldir%/guihandles.m \
   %reldir%/helpdlg.m \
   %reldir%/inputdlg.m \
   %reldir%/isappdata.m \
+  %reldir%/listfonts.m \
   %reldir%/listdlg.m \
   %reldir%/movegui.m \
   %reldir%/msgbox.m \
--- a/scripts/gui/movegui.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/gui/movegui.m	Thu Nov 19 13:08:00 2020 -0800
@@ -185,8 +185,8 @@
         if (fpos(2) > y(3))
           fpos(2) = y(3) - 30;
         endif
-        fpos(1) = max(fpos(1), 30);
-        fpos(2) = max(fpos(2), 30);
+        fpos(1) = max (fpos(1), 30);
+        fpos(2) = max (fpos(2), 30);
       otherwise
         error ("movegui: invalid position");
     endswitch
--- a/scripts/gui/msgbox.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/gui/msgbox.m	Thu Nov 19 13:08:00 2020 -0800
@@ -359,7 +359,7 @@
 %!         "Dialog Title", "custom", cdata, copper (64));
 
 ## Test input validation
-%!error msgbox ()
+%!error <Invalid call> msgbox ()
 %!error <MSG must be a string or cell array of strings> msgbox (1)
 %!error <invalid value "foobar" for WindowStyle>
 %! msgbox ("msg", struct ("WindowStyle", "foobar"))
--- a/scripts/gui/private/__file_filter__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/gui/private/__file_filter__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -30,7 +30,6 @@
 
 function [retval, defname, defdir] = __file_filter__ (caller, file_filter)
 
-  #keyboard;
   retval = {};
   defname = "";
   defdir = "";
--- a/scripts/gui/private/__ok_cancel_dlg__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/gui/private/__ok_cancel_dlg__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -24,14 +24,14 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn {} {[@var{hf}, @var{hok}, @var{hcancel}] =} __ok_cancel_dlg__ (@var{title})
+## @deftypefn {} {[@var{hf}, @var{hok}, @var{hcancel}] =} __ok_cancel_dlg__ (@var{dlg_title})
 ## Undocumented internal function.
 ## @seealso{}
 ## @end deftypefn
 
-function [hf, hok, hcancel, hpanel] = __ok_cancel_dlg__ (ttl, varargin)
+function [hf, hok, hcancel, hpanel] = __ok_cancel_dlg__ (dlg_title, varargin)
 
-  hf = dialog ("name", ttl, varargin{:});
+  hf = dialog ("name", dlg_title, varargin{:});
   setappdata (hf, "__ok_cancel_btn__", "cancel");
 
   hpanel = uipanel (hf, "units", "pixels", "bordertype", "none");
@@ -46,6 +46,7 @@
 endfunction
 
 function  cb_fix_button_position (hf, evt, hcancel, hok, hpanel)
+
   persistent margin = 20;
   persistent hgt = 30;
   persistent wd = 70;
@@ -62,4 +63,5 @@
   unwind_protect_cleanup
     set (hf, "units", units);
   end_unwind_protect
+
 endfunction
--- a/scripts/gui/private/__uiobject_split_args__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/gui/private/__uiobject_split_args__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -39,20 +39,20 @@
       parent = in_args{1};
       offset = 2;
     elseif (! ischar (in_args{1}) && ! isstruct (in_args{1}))
-      error ("%s: invalid parent handle.", who);
+      error ("%s: invalid parent handle", who);
     endif
 
     args = in_args(offset:end);
   endif
 
   if (! isempty (args))
-    i = find (strcmpi (args, "parent"), 1, "first");
-    if (! isempty (i) && numel (args) > i)
-      parent = args{i+1};
+    i = find (strcmpi (args(1:2:end), "parent"), 1, "first");
+    if (! isempty (i) && numel (args) >= 2*i)
+      parent = args{2*i};
       if (! ishghandle (parent))
-        error ("%s: invalid parent handle.", who);
+        error ("%s: invalid parent handle", who);
       endif
-      args(i:i+1) = [];
+      args((2*i-1):2*i) = [];
     endif
   endif
 
--- a/scripts/gui/questdlg.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/gui/questdlg.m	Thu Nov 19 13:08:00 2020 -0800
@@ -186,8 +186,8 @@
 %! endif
 
 ## Test input validation
-%!error questdlg ()
-%!error questdlg (1,2,3,4,5,6,7)
+%!error <Invalid call> questdlg ()
+%!error <Invalid call> questdlg (1,2,3,4,5,6,7)
 %!error <MSG must be a character string or cellstr array> questdlg (1)
 %!error <TITLE must be a character string> questdlg ("msg", 1)
 %!error <DEFAULT must match one of the button> questdlg ("msg", "title", "ABC")
--- a/scripts/gui/rmappdata.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/gui/rmappdata.m	Thu Nov 19 13:08:00 2020 -0800
@@ -78,8 +78,8 @@
 %! assert (isappdata (0, "%data2%"), false);
 
 ## Test input validation
-%!error rmappdata ()
-%!error rmappdata (1)
+%!error <Invalid call> rmappdata ()
+%!error <Invalid call> rmappdata (1)
 %!error <H must be a scalar .* graphic handle> rmappdata (-1, "hello")
 %!error <NAME must be a string> rmappdata (0, 1)
 %!error <appdata 'foobar' is not present> rmappdata (0, "foobar")
--- a/scripts/gui/setappdata.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/gui/setappdata.m	Thu Nov 19 13:08:00 2020 -0800
@@ -127,9 +127,9 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error setappdata ()
-%!error setappdata (0)
-%!error setappdata (0, "name")
+%!error <Invalid call> setappdata ()
+%!error <Invalid call> setappdata (0)
+%!error <Invalid call> setappdata (0, "name")
 %!error <H must be a scalar .* graphic handle> setappdata (-1, "foo", "bar")
 %!error <NAME/VALUE arguments must occur in pairs> setappdata (0, "1", 2, "3")
 %!error <only 3 arguments possible> setappdata (0, {"1"}, 2, "3", 4)
--- a/scripts/gui/uicontrol.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/gui/uicontrol.m	Thu Nov 19 13:08:00 2020 -0800
@@ -119,6 +119,16 @@
 
   [h, args] = __uiobject_split_args__ ("uicontrol", varargin,
                                        {"figure", "uipanel", "uibuttongroup"});
+
+  ## Validate style
+  idx = find (strcmpi (args(1:2:end), "style"), 1, "last");
+  if (! isempty (idx) && 2*idx <= numel (args))
+    if (strcmpi (args{2*idx}, "frame"))
+      warning ("Octave:unimplemented-matlab-functionality",
+               'uicontrol: "frame" style is not implemented.  Use uipanel() or uibuttongroup() instead');
+    endif
+  endif
+
   htmp = __go_uicontrol__ (h, args{:});
 
   if (nargout > 0)
@@ -126,3 +136,12 @@
   endif
 
 endfunction
+
+
+%!warning <"frame" style is not implemented>
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   h = uicontrol (hf, "string", "Hello World", "Style", "frame");
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
--- a/scripts/gui/uigetdir.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/gui/uigetdir.m	Thu Nov 19 13:08:00 2020 -0800
@@ -41,10 +41,6 @@
 
 function dirname = uigetdir (init_path = pwd, dialog_name = "Select Directory to Open")
 
-  if (nargin > 2)
-    print_usage ();
-  endif
-
   if (! ischar (init_path) || ! ischar (dialog_name))
     error ("uigetdir: INIT_PATH and DIALOG_NAME must be string arguments");
   endif
--- a/scripts/gui/uisetfont.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/gui/uisetfont.m	Thu Nov 19 13:08:00 2020 -0800
@@ -38,14 +38,18 @@
 ## @code{FontWeight}, @code{FontAngle}, @code{FontUnits}, and @code{FontSize},
 ## indicating the initially selected font.
 ##
-## The title of the dialog window can be changed using the last argument
+## The title of the dialog window can be specified by using the last argument
 ## @var{title}.
 ##
 ## If an output argument @var{fontstruct} is requested, the selected font
 ## structure is returned.  Otherwise, the font information is displayed
 ## onscreen.
 ##
-## @seealso{text, axes, uicontrol}
+## Programming Note: On systems that don't use FontConfig natively (all but
+## Linux), the font cache is built when Octave is installed.  You will need to
+## run @code{system ("fc-cache -fv")} manually after installing new fonts.
+##
+## @seealso{listfonts, text, axes, uicontrol}
 ## @end deftypefn
 
 function varargout = uisetfont (varargin)
@@ -71,7 +75,7 @@
     typ = get (h, "type");
     if (! any (strcmp (typ, {"axes", "text", "uicontrol"})))
       error ("Octave:uisetfont:bad-object",
-             'uisetfont: unhandled object type "%s"', typ);
+             "uisetfont: H must be a handle to an axes, text, or uicontrol object");
     endif
     nargin--;
     varargin(1) = [];
@@ -333,7 +337,7 @@
 
 endfunction
 
-function cb_button (h, evt, hlists, role)
+function cb_button (h, ~, hlists, role)
 
   fontstruct = [];
   if (strcmp (role, "ok"))
@@ -345,7 +349,7 @@
 
 endfunction
 
-function cb_list_value_changed (h, evt, hlists, htext, sysfonts)
+function cb_list_value_changed (h, ~, hlists, htext, sysfonts)
 
   if (h == hlists(1))
     set (hlists(2), "string", getstylestring (sysfonts(get (h, "value"))),
@@ -363,7 +367,7 @@
 %!testif HAVE_FONTCONFIG
 %! fail ("uisetfont (110, struct ())", "Invalid call");
 %!testif HAVE_FONTCONFIG
-%! fail ("uisetfont (groot ())", "unhandled object type");
+%! fail ("uisetfont (groot ())", "H must be a handle to an axes");
 %!testif HAVE_FONTCONFIG
 %! fail ("uisetfont (struct ())", "FONTSTRUCT .* must have fields FontName,.*");
 %!testif HAVE_FONTCONFIG
--- a/scripts/gui/waitforbuttonpress.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/gui/waitforbuttonpress.m	Thu Nov 19 13:08:00 2020 -0800
@@ -39,10 +39,6 @@
 
 function b = waitforbuttonpress ()
 
-  if (nargin != 0 || nargout > 1)
-    print_usage ();
-  endif
-
   [x, y, k] = ginput (1);
 
   if (nargout == 1)
@@ -54,8 +50,3 @@
   endif
 
 endfunction
-
-
-## Test input validation
-%!error waitforbuttonpress (1)
-%!error [a,b,c] = waitforbuttonpress ()
--- a/scripts/gui/warndlg.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/gui/warndlg.m	Thu Nov 19 13:08:00 2020 -0800
@@ -40,7 +40,7 @@
 ## ("\n"), or it may be a cellstr array with one element for each line.
 ##
 ## The third optional argument @var{opt} controls the behavior of the dialog.
-## See @code{msgbox} for details.
+## For details, @pxref{XREFmsgbox,,@code{msgbox}}.
 ##
 ## The return value @var{h} is a handle to the figure object used for
 ## building the dialog.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/help/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/help/__gripe_missing_component__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/help/__gripe_missing_component__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -62,14 +62,13 @@
 endfunction
 
 
-## WARNING: Tests cannot rely on the exact error strings shown above because we
-##          specifically allow these messages to be overridden by
-##          missing_component_hook.  The prefix is all we can be sure of.
+## NOTE: Tests cannot rely on the exact error strings shown above because we
+##       specifically allow these messages to be overridden by
+##       missing_component_hook.  The prefix is all we can be sure of.
 %!error <abc: .*> __gripe_missing_component__ ("abc", "info-file")
 %!error <abc: .*> __gripe_missing_component__ ("abc", "octave")
 %!error <abc: .*> __gripe_missing_component__ ("abc", "octave-config")
 %!error <abc: .*> __gripe_missing_component__ ("abc", "xyz")
 
-%!error __gripe_missing_component__ ()
-%!error __gripe_missing_component__ ("fcn")
-%!error __gripe_missing_component__ ("fcn", 1 , 2)
+%!error <Invalid call> __gripe_missing_component__ ()
+%!error <Invalid call> __gripe_missing_component__ ("fcn")
--- a/scripts/help/__makeinfo__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/help/__makeinfo__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -67,7 +67,7 @@
 function [retval, status] = __makeinfo__ (text, output_type = "plain text", fsee_also)
 
   ## Check input
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -161,8 +161,8 @@
       ## original return value usually more useful
       if (status_force)
         status = status_force;
-      end
-    end
+      endif
+    endif
 
     ## Clean up extra newlines generated by makeinfo
     if (strcmpi (output_type, "plain text"))
--- a/scripts/help/__unimplemented__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/help/__unimplemented__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -39,7 +39,7 @@
 
 function txt = __unimplemented__ (fcn)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -561,7 +561,7 @@
           txt = sprintf (["'%s' is a method of class '%s'; it must be ", ...
                           "called with a '%s' argument (see 'help @@%s/%s')."],
                          fcn, cls, cls, cls, fcn);
-          return
+          return;
         endif
       endfor
       txt = sprintf ("%s but has not yet been implemented.", txt);
@@ -736,7 +736,6 @@
   "edges",
   "empty",
   "enableservice",
-  "endsWith",
   "enumeration",
   "eraseBetween",
   "eventlisteners",
@@ -813,7 +812,6 @@
   "getNumOutputs",
   "getNumRows",
   "getOpenFiles",
-  "getpixelposition",
   "getpoints",
   "getProfiles",
   "getqualitydesc",
@@ -959,8 +957,6 @@
   "javaMethodEDT",
   "javaObjectEDT",
   "join",
-  "jsondecode",
-  "jsonencode",
   "juliandate",
   "labeledge",
   "labelnode",
@@ -975,7 +971,6 @@
   "libpointer",
   "libstruct",
   "linkdata",
-  "listfonts",
   "loadlibrary",
   "lsqminnorm",
   "lsqr",
@@ -990,15 +985,11 @@
   "memmapfile",
   "memoize",
   "MemoizedFunction",
-  "memory",
   "mergecats",
   "meta.abstractDetails",
-  "meta.class.fromName",
   "meta.DynamicProperty",
   "meta.EnumeratedValue",
   "meta.MetaData",
-  "meta.package.fromName",
-  "meta.package.getAllPackages",
   "methodsview",
   "MException",
   "milliseconds",
@@ -1053,7 +1044,6 @@
   "odextend",
   "openFile",
   "opengl",
-  "ordqz",
   "outdegree",
   "outerjoin",
   "pad",
@@ -1086,7 +1076,6 @@
   "printpreview",
   "profsave",
   "propedit",
-  "properties",
   "propertyeditor",
   "PutCharArray",
   "PutFullMatrix",
@@ -1129,10 +1118,8 @@
   "replace",
   "replaceBetween",
   "resample",
-  "rescale",
   "retime",
   "reverse",
-  "rgb2gray",
   "rlim",
   "rmboundary",
   "rmedge",
@@ -1140,7 +1127,6 @@
   "rmmissing",
   "rmnode",
   "rmslivers",
-  "rng",
   "rowfun",
   "rtickangle",
   "rtickformat",
@@ -1165,7 +1151,6 @@
   "setHCompSmooth",
   "setinterpmethod",
   "setpixelposition",
-  "setstr",
   "setTileDim",
   "settimeseriesnames",
   "setTscale",
@@ -1193,13 +1178,11 @@
   "ss2tf",
   "stack",
   "standardizeMissing",
-  "startsWith",
   "stats",
   "step",
   "stopasync",
   "str2mat",
   "streamparticles",
-  "streamribbon",
   "streamslice",
   "string",
   "strings",
@@ -1336,20 +1319,18 @@
   "xmlread",
   "xmlwrite",
   "xslt",
-  "xtickangle",
   "xtickformat",
   "year",
   "years",
   "ymd",
-  "ytickangle",
   "ytickformat",
   "yyaxis",
   "yyyymmdd",
-  "ztickangle",
   "ztickformat",
   };
 
   rlist = list;
+
 endfunction
 
 
--- a/scripts/help/bessel.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/help/bessel.m	Thu Nov 19 13:08:00 2020 -0800
@@ -101,4 +101,4 @@
 endfunction
 
 
-%!error bessel ()
+%!error <you must use besselj, ...> bessel ()
--- a/scripts/help/doc.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/help/doc.m	Thu Nov 19 13:08:00 2020 -0800
@@ -41,10 +41,6 @@
 
 function retval = doc (function_name)
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   if (nargin == 1)
     if (! ischar (function_name))
       error ("doc: FUNCTION_NAME must be a string");
--- a/scripts/help/get_first_help_sentence.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/help/get_first_help_sentence.m	Thu Nov 19 13:08:00 2020 -0800
@@ -52,7 +52,7 @@
 
 function [text, status] = get_first_help_sentence (name, max_len = 80)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -109,7 +109,9 @@
       text = help_text(1:max_len);
     endif
   endif
+
   status = 0;
+
 endfunction
 
 ## This function extracts the first sentence from a Texinfo help text.
@@ -182,8 +184,7 @@
 %!        "Return the first sentence...")
 
 ## Test input validation
-%!error get_first_help_sentence ()
-%!error get_first_help_sentence (1, 2, 3)
+%!error <Invalid call> get_first_help_sentence ()
 %!error <NAME must be a string> get_first_help_sentence (1)
 %!error <MAX_LEN must be positive integer> get_first_help_sentence ("ls", "a")
 %!error <MAX_LEN must be positive integer> get_first_help_sentence ("ls", 0)
--- a/scripts/help/help.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/help/help.m	Thu Nov 19 13:08:00 2020 -0800
@@ -224,5 +224,5 @@
 
 ## Test input validation
 %!error <invalid input> help (42)
-%!error <invalid input> help ("abc", "def")
+%!error <called with too many inputs> help ("abc", "def")
 %!error <'_! UNLIKELY_FCN! _' not found> help ("_! UNLIKELY_FCN! _")
--- a/scripts/help/lookfor.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/help/lookfor.m	Thu Nov 19 13:08:00 2020 -0800
@@ -49,7 +49,8 @@
 ## related functions that are not a part of Octave.
 ##
 ## The speed of lookup is greatly enhanced by having a cached documentation
-## file.  See @code{doc_cache_create} for more information.
+## file.  For more information,
+## @pxref{XREFdoc_cache_create,,@code{doc_cache_create}}.
 ## @seealso{help, doc, which, path, doc_cache_create}
 ## @end deftypefn
 
--- a/scripts/help/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/help/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -7,6 +7,7 @@
   %reldir%/private/__strip_html_tags__.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/__gripe_missing_component__.m \
   %reldir%/__makeinfo__.m \
   %reldir%/__unimplemented__.m \
--- a/scripts/help/print_usage.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/help/print_usage.m	Thu Nov 19 13:08:00 2020 -0800
@@ -45,7 +45,7 @@
       error ("Octave:invalid-context", "print_usage: invalid function\n");
     endif
     fullname = evalin ("caller", 'mfilename ("fullpath")');
-    if (strcmp (fullname(end-length(name)+1:end), name))
+    if (strcmp (fullname(end-length (name)+1:end), name))
       fullname = [fullname ".m"];
     endif
   elseif (! ischar (name))
--- a/scripts/help/private/__strip_html_tags__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/help/private/__strip_html_tags__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -37,7 +37,7 @@
   stop  = find (html_text == ">");
   if (length (start) == length (stop))
     text = html_text;
-    for n = length(start):-1:1
+    for n = length (start):-1:1
       text (start (n):stop (n)) = [];
     endfor
     text = strip_superfluous_endlines (text);
--- a/scripts/help/slash.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/help/slash.m	Thu Nov 19 13:08:00 2020 -0800
@@ -61,10 +61,10 @@
 ##
 ## For dense matrices, backslash uses the Gaussian Elimination algorithm
 ## with partial pivoting.  For sparse matrices, backslash uses a direct
-## method to compute an LU factorization (@pxref{XREFlu,,lu}).  The direct
-## method tries to minimize ``fill-in'' of zeros but it could nonetheless use a
-## lot of memory; if this is a concern, consider an iterative method
-## (@pxref{XREFcgs,,cgs} or @pxref{XREFgmres,,gmres}).
+## method to compute an LU factorization (@pxref{XREFlu,,@code{lu}}).  The
+## direct method tries to minimize ``fill-in'' of zeros but it could
+## nonetheless use a lot of memory; if this is a concern, consider an iterative
+## method (@pxref{XREFcgs,,@code{cgs}} or @pxref{XREFgmres,,@code{gmres}}).
 ##
 ## @item @code{/} Matrix Right Division
 ## The forward slash notation can be used to solve systems of the form
--- a/scripts/help/type.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/help/type.m	Thu Nov 19 13:08:00 2020 -0800
@@ -155,5 +155,5 @@
 %!assert (type ("+"){1}, "+ is an operator")
 %!assert (type ("end"){1}, "end is a keyword")
 
-%!error type ()
+%!error <Invalid call> type ()
 %!error <'__NO_NAME__' undefined> type ('__NO_NAME__')
--- a/scripts/help/warning_ids.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/help/warning_ids.m	Thu Nov 19 13:08:00 2020 -0800
@@ -139,6 +139,13 @@
 ## By default, the @code{Octave:built-in-variable-assignment} warning is
 ## enabled.
 ##
+## @item Octave:charmat-truncated
+## If the @code{Octave:charmat-truncated} warning is enabled, a warning is
+## printed when a character matrix with multiple rows is converted to a string.
+## In this case, the Octave interpreter keeps only the first row and discards
+## the others.
+## By default, the @code{Octave:charmat-truncated} warning is enabled.
+##
 ## @item Octave:classdef-to-struct
 ## If the @code{Octave:classdef-to-struct} warning is enabled, a warning
 ## is issued when a classdef object is forcibly converted into a struct with
@@ -230,6 +237,12 @@
 ## printed for implicit conversions of complex numbers to real numbers.
 ## By default, the @code{Octave:imag-to-real} warning is disabled.
 ##
+## @item Octave:infinite-loop
+## If the @code{Octave:infinite-loop} warning is enabled, a warning is
+## printed when an infinite loop is detected such as @code{for i = 1:Inf} or
+## @code{while (1)}.
+## By default, the @code{Octave:infinite-loop} warning is enabled.
+##
 ## @item Octave:language-extension
 ## Print warnings when using features that are unique to the Octave
 ## language and that may still be missing in @sc{matlab}.
@@ -384,6 +397,14 @@
 ## the warning message is printed just once per Octave session.
 ## By default, the @code{Octave:glyph-render} warning is enabled.
 ##
+## @item Octave:unimplemented-matlab-functionality
+## If the @code{Octave:unimplemented-matlab-functionality} warning is enabled,
+## a warning is printed when a @sc{matlab} code construct is used which the
+## Octave interpreter parses as valid, but for which Octave does not yet
+## implement the functionality.
+## By default, the @code{Octave:unimplemented-matlab-functionality} warning is
+## enabled.
+##
 ## @item Octave:variable-switch-label
 ## If the @code{Octave:variable-switch-label} warning is enabled, Octave
 ## will print a warning if a switch label is not a constant or constant
--- a/scripts/help/which.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/help/which.m	Thu Nov 19 13:08:00 2020 -0800
@@ -113,6 +113,6 @@
 %! str = which ("fftw");
 %! assert (str(end-7:end), "fftw.oct");
 
-%!error which ()
-%!error which (1)
+%!error <Invalid call> which ()
+%!error <Invalid call> which (1)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/image/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/image/autumn.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/autumn.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,9 +36,7 @@
 
 function map = autumn (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("autumn: N must be a scalar");
     endif
--- a/scripts/image/bone.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/bone.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,9 +36,7 @@
 
 function map = bone (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("bone: N must be a scalar");
     endif
--- a/scripts/image/brighten.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/brighten.m	Thu Nov 19 13:08:00 2020 -0800
@@ -46,7 +46,7 @@
 
 function rmap = brighten (arg1, beta)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/image/cmpermute.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/cmpermute.m	Thu Nov 19 13:08:00 2020 -0800
@@ -43,7 +43,7 @@
 
 function [Y, newmap] = cmpermute (X, map, index)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -131,8 +131,8 @@
 %! assert (X, max (Y(:)) + 1 - Y);
 
 ## Test input validation
-%!error cmpermute ()
-%!error cmpermute (1,2,3,4)
+%!error <Invalid call> cmpermute ()
+%!error <Invalid call> cmpermute (1)
 %!error <invalid data type 'uint32'> cmpermute (uint32 (magic (16)), jet (256))
 %!error <X must be an indexed image> cmpermute (1+i, jet (256))
 %!error <X must be an indexed image> cmpermute (sparse (1), jet (256))
--- a/scripts/image/cmunique.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/cmunique.m	Thu Nov 19 13:08:00 2020 -0800
@@ -60,7 +60,7 @@
 
 function [Y, newmap] = cmunique (X, map)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -193,8 +193,7 @@
 %! assert (Id, newmap(:,3)(Y+1));
 
 ## Test input validation
-%!error cmpermute ()
-%!error cmpermute (1,2,3)
+%!error <Invalid call> cmunique ()
 %!error <X is of invalid data type> cmunique (uint32 (magic (16)))
 %!error <MAP must be a valid colormap> cmunique (1, "a")
 %!error <MAP must be a valid colormap> cmunique (1, i)
--- a/scripts/image/colorcube.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/colorcube.m	Thu Nov 19 13:08:00 2020 -0800
@@ -42,12 +42,8 @@
 
   if (nargin == 0)
     n = rows (colormap);
-  elseif (nargin == 1)
-    if (! isscalar (n))
-      error ("colorcube: N must be a scalar");
-    endif
-  else
-    print_usage ();
+  elseif (! isscalar (n))
+    error ("colorcube: N must be a scalar");
   endif
 
   if (n < 9)
--- a/scripts/image/colormap.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/colormap.m	Thu Nov 19 13:08:00 2020 -0800
@@ -177,7 +177,7 @@
 %!error colormap (1,2,3)
 %!error <MAP must be a real-valued N x 3> colormap ({1,2,3})
 %!error <MAP must be a real-valued N x 3> colormap ([1 i 1])
-%!error <MAP must be a real-valued N x 3> colormap (ones(3,3,3))
+%!error <MAP must be a real-valued N x 3> colormap (ones (3,3,3))
 %!error <MAP must be a real-valued N x 3> colormap ([1 0 1 0])
 %!error <all MAP values must be in the range> colormap ([-1 0 0])
 %!error <all MAP values must be in the range> colormap ([2 0 0])
--- a/scripts/image/contrast.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/contrast.m	Thu Nov 19 13:08:00 2020 -0800
@@ -35,9 +35,7 @@
 
 function cmap = contrast (x, n)
 
-  if (nargin > 2)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     hf = get (0, "currentfigure");
     if (! isempty (hf))
       n = rows (get (hf, "colormap"));
--- a/scripts/image/cool.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/cool.m	Thu Nov 19 13:08:00 2020 -0800
@@ -35,9 +35,7 @@
 
 function map = cool (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("cool: N must be a scalar");
     endif
--- a/scripts/image/copper.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/copper.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,9 +36,7 @@
 
 function map = copper (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("copper: N must be a scalar");
     endif
--- a/scripts/image/cubehelix.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/cubehelix.m	Thu Nov 19 13:08:00 2020 -0800
@@ -26,6 +26,7 @@
 ## -*- texinfo -*-
 ## @deftypefn  {} {@var{map} =} cubehelix ()
 ## @deftypefnx {} {@var{map} =} cubehelix (@var{n})
+## @deftypefnx {} {@var{map} =} cubehelix (@var{n}, @var{start}, @var{rots}, @var{hue}, @var{gamma})
 ## Create cubehelix colormap.
 ##
 ## This colormap varies from black to white going though blue, green, and red
@@ -50,9 +51,7 @@
 
 function map = cubehelix (n, start = 0.5, rots = -1.5, hue = 1, gamma = 1)
 
-  if (nargin > 5)
-    print_usage ();
-  elseif (nargin > 0)
+  if (nargin > 0)
     if (! isscalar (n))
       error ("cubehelix: N must be a scalar");
     endif
--- a/scripts/image/flag.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/flag.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,9 +36,7 @@
 
 function map = flag (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("flag: N must be a scalar");
     endif
--- a/scripts/image/frame2im.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/frame2im.m	Thu Nov 19 13:08:00 2020 -0800
@@ -40,7 +40,7 @@
 
 function [x, map] = frame2im (frame)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   elseif (! all (isfield (frame, {"cdata", "colormap"})))
     error ("frame2im: F must be a struct with the fields colormap and cdata");
--- a/scripts/image/gray.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/gray.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,9 +36,7 @@
 
 function map = gray (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("gray: N must be a scalar");
     endif
--- a/scripts/image/gray2ind.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/gray2ind.m	Thu Nov 19 13:08:00 2020 -0800
@@ -42,9 +42,9 @@
 
 function [I, map] = gray2ind (I, n = 64)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
-  elseif (! isreal (I) || issparse (I) || ! ismatrix(I))
+  elseif (! isreal (I) || issparse (I) || ! ismatrix (I))
     error ("gray2ind: I must be a grayscale or binary image");
   elseif (! isscalar (n) || n < 1 || n > 65536)
     error ("gray2ind: N must be a positive integer in the range [1, 65536]");
@@ -106,8 +106,7 @@
 %! assert (class (gray2ind ([0.0 0.5 1.0], 257)), "uint16");
 
 ## Test input validation
-%!error gray2ind ()
-%!error gray2ind (1,2,3)
+%!error <Invalid call> gray2ind ()
 %!error <I must be a grayscale or binary image> gray2ind ({1})
 %!error <I must be a grayscale or binary image> gray2ind ([1+i])
 %!error <I must be a grayscale or binary image> gray2ind (sparse ([1]))
--- a/scripts/image/hot.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/hot.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,9 +36,7 @@
 
 function map = hot (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("hot: N must be a scalar");
     endif
--- a/scripts/image/hsv.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/hsv.m	Thu Nov 19 13:08:00 2020 -0800
@@ -40,9 +40,7 @@
 
 function map = hsv (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("hsv: N must be a scalar");
     endif
--- a/scripts/image/hsv2rgb.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/hsv2rgb.m	Thu Nov 19 13:08:00 2020 -0800
@@ -64,7 +64,7 @@
   ## where f_x(hue) is a piecewise defined function for
   ## each color with f_r(hue-2/3) = f_g(hue) = f_b(hue-1/3).
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -136,8 +136,7 @@
 %!assert (hsv2rgb (sparse ([1 1 1])), sparse ([1 0 0]))
 
 ## Test input validation
-%!error hsv2rgb ()
-%!error hsv2rgb (1,2)
+%!error <Invalid call> hsv2rgb ()
 %!error <invalid data type> hsv2rgb ({1})
 %!error <HSV must be a colormap or HSV image> hsv2rgb (ones (2,2))
 
--- a/scripts/image/im2double.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/im2double.m	Thu Nov 19 13:08:00 2020 -0800
@@ -57,7 +57,7 @@
 
 function img = im2double (img, im_type)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/image/im2frame.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/im2frame.m	Thu Nov 19 13:08:00 2020 -0800
@@ -41,7 +41,7 @@
 
 function frame = im2frame (x, map = [])
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   elseif (ndims (x) > 4)
     error ("im2frame: X and RGB must be a single image");
--- a/scripts/image/imfinfo.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/imfinfo.m	Thu Nov 19 13:08:00 2020 -0800
@@ -188,7 +188,7 @@
 %! assert (error_thrown, true);
 
 ## Test input validation
-%!error imfinfo ()
-%!error imfinfo (1,2,3)
+%!error <Invalid call> imfinfo ()
+%!error <Invalid call> imfinfo (1,2,3)
 %!error <FILENAME must be a string> imfinfo (1)
 %!error <EXT must be a string> imfinfo ("foo", 1)
--- a/scripts/image/imformats.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/imformats.m	Thu Nov 19 13:08:00 2020 -0800
@@ -77,11 +77,7 @@
 
 function varargout = imformats (arg1, arg2, arg3)
 
-  if (nargin > 3)
-    print_usage ();
-  endif
-
-  mlock (); # prevent formats to be removed by "clear all"
+  mlock ();  # prevent formats being removed by "clear all"
   persistent formats = default_formats ();
 
   if (nargin == 0 && nargout == 0)
@@ -96,7 +92,7 @@
       switch (tolower (arg1))
         case "add",
           if (! isstruct (arg2))
-            error ("imformats: FORMAT to %s must be a structure.", arg1);
+            error ("imformats: FORMAT to %s must be a structure", arg1);
           endif
           arrayfun (@is_valid_format, arg2);
           formats(end + 1: end + numel (arg2)) = arg2;
@@ -104,21 +100,21 @@
 
         case {"remove", "update"},
           if (! ischar (arg2))
-            error ("imformats: EXT to %s must be a string.", arg1);
+            error ("imformats: EXT to %s must be a string", arg1);
           endif
-          ## FIXME: suppose a format with multiple extensions.  If one of
+          ## FIXME: Suppose a format with multiple extensions; if one of
           ##        them is requested to be removed, should we remove the
           ##        whole format, or just that extension from the format?
           match = find_ext_idx (formats, arg2);
           if (! any (match))
-            error ("imformats: no EXT '%s' found.", arg2);
+            error ("imformats: no EXT '%s' found", arg2);
           endif
           if (strcmpi (arg1, "remove"))
             formats(match) = [];
           else
             ## then it's update
             if (! isstruct (arg3))
-              error ("imformats: FORMAT to update must be a structure.");
+              error ("imformats: FORMAT to update must be a structure");
             endif
             is_valid_format (arg3);
             formats(match) = arg3;
@@ -130,7 +126,7 @@
         otherwise
           ## then we look for a format with that extension.
           match = find_ext_idx (formats, arg1);
-          ## For matlab compatibility, if we don't find any format we must
+          ## For Matlab compatibility, if we don't find any format we must
           ## return an empty struct with NO fields.  We can't use match as mask
           if (any (match))
             varargout{1} = formats(match);
@@ -139,7 +135,7 @@
           endif
       endswitch
     else
-      error ("imformats: first argument must be either a structure or string.");
+      error ("imformats: first argument must be either a structure or string");
     endif
   else
     varargout{1} = formats;
@@ -247,7 +243,7 @@
             "XWD",  {"xwd"},          false;
             };
 
-  for fidx = 1: rows(coders)
+  for fidx = 1:rows (coders)
     formats(fidx).coder = coders{fidx, 1};
     formats(fidx).ext   = coders{fidx, 2};
     formats(fidx).alpha = coders{fidx, 3};
@@ -268,21 +264,24 @@
 endfunction
 
 function is_valid_format (format)
+
   ## the minimal list of fields required in the structure.  We don't
   ## require multipage because it doesn't exist in matlab
   min_fields  = {"ext", "read", "isa", "write", "info", "alpha", "description"};
   fields_mask = isfield (format, min_fields);
   if (! all (fields_mask))
-    error ("imformats: structure has missing field '%s'.", min_fields(! fields_mask){1});
+    error ("imformats: structure has missing field '%s'", min_fields(! fields_mask){1});
   endif
 
 endfunction
 
 function match = find_ext_idx (formats, ext)
+
   ## FIXME: what should we do if there's more than one hit?
   ##        Should this function prevent the addition of
   ##        duplicated extensions?
   match = cellfun (@(x) any (strcmpi (x, ext)), {formats.ext});
+
 endfunction
 
 function bool = isa_magick (coder, filename)
@@ -372,7 +371,7 @@
 %! unwind_protect
 %!   fmt = imformats ("jpg"); # take jpg as template
 %!   fmt.ext = "new_fmt";
-%!   fmt.read = @() true ();
+%!   fmt.read = @(~) true ();
 %!   imformats ("add", fmt);
 %!   assert (imread (fname), true);
 %! unwind_protect_cleanup
@@ -391,7 +390,7 @@
 %! unwind_protect
 %!   fmt = imformats ("jpg"); # take jpg as template
 %!   fmt.ext = "new_fmt1";
-%!   fmt.read = @() true();
+%!   fmt.read = @(~) true ();
 %!   fmt(2) = fmt(1);
 %!   fmt(2).ext = "new_fmt2";
 %!   imformats ("add", fmt);
--- a/scripts/image/imshow.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/imshow.m	Thu Nov 19 13:08:00 2020 -0800
@@ -268,7 +268,7 @@
 %! title ({"imshow with random 100x100x3 matrix", "RGB values > 1 are clipped"});
 
 ## Test input validation
-%!error imshow ()
+%!error <Invalid call> imshow ()
 %!error <IM must be an image> imshow ({"cell"})
 %!error <TrueColor image must be uint8> imshow (ones (3,3,3, "uint32"))
 %!error <TrueColor image must be uint8> imshow (ones (3,3,3, "int16"))
--- a/scripts/image/imwrite.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/imwrite.m	Thu Nov 19 13:08:00 2020 -0800
@@ -129,8 +129,8 @@
 
 
 ## Test input validation
-%!error imwrite ()                            # Wrong # of args
-%!error imwrite (1)                           # Wrong # of args
+%!error <Invalid call> imwrite ()             # Wrong # of args
+%!error <Invalid call> imwrite (1)            # Wrong # of args
 %!error imwrite ({"cell"}, "filename.jpg")    # Wrong class for img
 %!error imwrite (1, [], "filename.jpg")       # Empty image map
 %!error imwrite (1, 2, 3)                     # No filename specified
--- a/scripts/image/ind2gray.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/ind2gray.m	Thu Nov 19 13:08:00 2020 -0800
@@ -77,9 +77,8 @@
 %!assert (gray2ind (i2g, 100), uint8 (0:99))
 
 ## Test input validation
-%!error ind2gray ()
-%!error ind2gray (1)
-%!error ind2gray (1,2,3)
+%!error <Invalid call> ind2gray ()
+%!error <Invalid call> ind2gray (1)
 %!error <X must be an indexed image> ind2gray (ones (3,3,3), jet (64))
 %!error <X must be an indexed image> ind2gray (1+i, jet (64))
 %!error <X must be an indexed image> ind2gray (sparse (1), jet (64))
--- a/scripts/image/ind2rgb.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/ind2rgb.m	Thu Nov 19 13:08:00 2020 -0800
@@ -66,7 +66,7 @@
                    [1 2 4 3]);
     else
       ## we should never reach here since ind2x() should filter them out
-      error ("ind2rgb: an indexed image must have 2 or 4 dimensions.");
+      error ("ind2rgb: an indexed image must have 2 or 4 dimensions");
     endif
   endif
 
@@ -102,8 +102,8 @@
 %! assert (rgb(:,3,:), 1/63 * ones (1,1,3));
 
 ## Test input validation
-%!error ind2rgb ()
-%!error ind2rgb (1,2,3)
+%!error <Invalid call> ind2rgb ()
+%!error <Invalid call> ind2rgb (1)
 %!error <X must be an indexed image> ind2rgb (ones (3,3,3), jet (64))
 %!error <X must be an indexed image> ind2rgb (1+i, jet (64))
 %!error <X must be an indexed image> ind2rgb (sparse (1), jet (64))
@@ -127,10 +127,10 @@
 %! cmap = repmat (linspace (0, 1, 9)(:), [1 3]);
 %! ind = [0 3 6; 1 4 7; 2 5 8];
 %! rgb = repmat (reshape (linspace (0, 1, 9), [3 3]), [1 1 3]);
-%! assert (ind2rgb (uint8  (ind), cmap), rgb)
-%! assert (ind2rgb (uint16 (ind), cmap), rgb)
-%! assert (ind2rgb (uint32 (ind), cmap), rgb)
-%! assert (ind2rgb (uint64 (ind), cmap), rgb)
+%! assert (ind2rgb (uint8  (ind), cmap), rgb);
+%! assert (ind2rgb (uint16 (ind), cmap), rgb);
+%! assert (ind2rgb (uint32 (ind), cmap), rgb);
+%! assert (ind2rgb (uint64 (ind), cmap), rgb);
 %! fail ("ind2rgb (int8  (ind), cmap)", "X must be an indexed image")
 %! fail ("ind2rgb (int16 (ind), cmap)", "X must be an indexed image")
 %! fail ("ind2rgb (int32 (ind), cmap)", "X must be an indexed image")
@@ -139,5 +139,10 @@
 %! cmap(65541,:) = cmap(9,:); # index outside the uint16 range
 %! cmap(9,:) = 0;
 %! ind(3,3) = 65540;
-%! assert (ind2rgb (uint32 (ind), cmap), rgb)
-%! assert (ind2rgb (uint64 (ind), cmap), rgb)
+%! assert (ind2rgb (uint32 (ind), cmap), rgb);
+%! assert (ind2rgb (uint64 (ind), cmap), rgb);
+
+%!test <*59242>
+%! warning ("off", "Octave:ind2rgb:invalid-idx-img", "local");
+%! assert (ind2rgb (uint64 (intmax ("uint64")), jet (64)), ...
+%!         reshape ([0.5,0,0], [1,1,3]));
--- a/scripts/image/iscolormap.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/iscolormap.m	Thu Nov 19 13:08:00 2020 -0800
@@ -40,8 +40,8 @@
 
 function retval = iscolormap (cmap)
 
-  if (nargin != 1)
-    print_usage;
+  if (nargin < 1)
+    print_usage ();
   endif
 
   retval = (isnumeric (cmap) && isreal (cmap)
--- a/scripts/image/jet.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/jet.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,9 +36,7 @@
 
 function map = jet (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("jet: N must be a scalar");
     endif
--- a/scripts/image/lines.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/lines.m	Thu Nov 19 13:08:00 2020 -0800
@@ -38,9 +38,7 @@
 function map = lines (n)
 
   hf = get (groot, "currentfigure");
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("lines: N must be a scalar");
     endif
--- a/scripts/image/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -13,6 +13,7 @@
   %reldir%/private/ind2x.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/autumn.m \
   %reldir%/bone.m \
   %reldir%/brighten.m \
--- a/scripts/image/movie.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/movie.m	Thu Nov 19 13:08:00 2020 -0800
@@ -244,7 +244,8 @@
 %! movie (mov, 3, 25);
 
 ## Test input validation
-%!error movie ()
+%!error <Invalid call> movie ()
+%!error <Invalid call> movie (1,2,3,4,5)
 %!error <MOV must be a frame struct array> movie ({2})
 %!error <MOV must contain at least two frames>
 %! movie (struct ("cdata", [], "colormap", []));
--- a/scripts/image/ocean.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/ocean.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,9 +36,7 @@
 
 function map = ocean (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("ocean: N must be a scalar");
     endif
--- a/scripts/image/pink.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/pink.m	Thu Nov 19 13:08:00 2020 -0800
@@ -38,9 +38,7 @@
 
 function map = pink (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("pink: N must be a scalar");
     endif
--- a/scripts/image/prism.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/prism.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,9 +36,7 @@
 
 function map = prism (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("prism: N must be a scalar");
     endif
--- a/scripts/image/private/__imfinfo__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/private/__imfinfo__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -30,7 +30,7 @@
 
 function info = __imfinfo__ (filename)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ("imfinfo");
   elseif (! ischar (filename))
     error ("imfinfo: FILENAME must be a string");
--- a/scripts/image/private/ind2x.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/private/ind2x.m	Thu Nov 19 13:08:00 2020 -0800
@@ -58,22 +58,28 @@
   ## It is possible that an integer storage class may not have enough room
   ## to make the switch, in which case we convert the data to single.
   maxidx = max (x(:));
-  if (isinteger (x))
+  is_int = isinteger (x);
+  if (is_int)
     if (maxidx == intmax (x))
       x = single (x);
     endif
-    x      += 1;
-    maxidx += 1;
+    x += 1;
   endif
 
   ## When there are more colors in the image, than there are in the map,
   ## pad the colormap with the last color in the map for Matlab compatibility.
   num_colors = rows (map);
-  if (num_colors < maxidx)
+  if (num_colors - is_int < maxidx)
     warning (["Octave:" caller ":invalid-idx-img"],
              [caller ": indexed image contains colors outside of colormap"]);
-    pad = repmat (map(end,:), maxidx - num_colors, 1);
-    map(end+1:maxidx, :) = pad;
+    if (numel (x) > maxidx - num_colors + is_int)
+      ## The image is large. So extend the map.
+      pad = repmat (map(end,:), maxidx - num_colors + is_int, 1);
+      map(end+(1:rows (pad)), :) = pad;
+    else
+      ## The map extension would be large. So clip the image.
+      x(x > rows (map)) = rows (map);
+    endif
   endif
 
 endfunction
--- a/scripts/image/rainbow.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/rainbow.m	Thu Nov 19 13:08:00 2020 -0800
@@ -39,9 +39,7 @@
 
 function map = rainbow (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("rainbow: N must be a scalar");
     endif
--- a/scripts/image/rgb2gray.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/rgb2gray.m	Thu Nov 19 13:08:00 2020 -0800
@@ -49,7 +49,7 @@
 
 function I = rgb2gray (rgb)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -161,7 +161,6 @@
 %! assert (rgb2gray (single (rgb_double)), single (expected));
 
 ## Test input validation
-%!error rgb2gray ()
-%!error rgb2gray (1,2)
+%!error <Invalid call> rgb2gray ()
 %!error <invalid data type 'cell'> rgb2gray ({1})
 %!error <RGB must be a colormap or RGB image> rgb2gray (ones (2,2))
--- a/scripts/image/rgb2hsv.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/rgb2hsv.m	Thu Nov 19 13:08:00 2020 -0800
@@ -43,7 +43,7 @@
 
 function hsv = rgb2hsv (rgb)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -113,8 +113,7 @@
 %!assert (rgb2hsv (sparse ([1 1 1])), sparse ([0 0 1]))
 
 ## Test input validation
-%!error rgb2hsv ()
-%!error rgb2hsv (1,2)
+%!error <Invalid call> rgb2hsv ()
 %!error <invalid data type 'cell'> rgb2hsv ({1})
 %!error <RGB must be a colormap or RGB image> rgb2hsv (ones (2,2))
 
--- a/scripts/image/rgb2ind.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/rgb2ind.m	Thu Nov 19 13:08:00 2020 -0800
@@ -103,8 +103,8 @@
 
 
 ## Test input validation
-%!error rgb2ind ()
-%!error rgb2ind (1,2,3,4,5,6,7)
+%!error <Invalid call> rgb2ind ()
+%!error <Invalid call> rgb2ind (1,2)
 %!error <RGB> rgb2ind (rand (10, 10, 4))
 
 ## FIXME: the following tests simply make sure that rgb2ind and ind2rgb
--- a/scripts/image/rgbplot.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/rgbplot.m	Thu Nov 19 13:08:00 2020 -0800
@@ -52,7 +52,7 @@
 
 function h = rgbplot (cmap, style = "profile")
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -91,8 +91,7 @@
 %!  rgbplot (ocean, "composite");
 
 ## Test input validation
-%!error rgbplot ()
-%!error rgbplot (1,2)
+%!error <Invalid call> rgbplot ()
 %!error <CMAP must be a valid colormap> rgbplot ({0 1 0})
 %!error <STYLE must be a string> rgbplot ([0 1 0], 2)
 %!error <unknown STYLE 'nostyle'> rgbplot ([0 1 0], "nostyle")
--- a/scripts/image/spinmap.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/spinmap.m	Thu Nov 19 13:08:00 2020 -0800
@@ -42,9 +42,7 @@
 
 function spinmap (t = 5, inc = 2)
 
-  if (nargin > 2)
-    print_usage ();
-  elseif (ischar (t))
+  if (ischar (t))
     if (strcmpi (t, "inf"))
       t = Inf;
     else
@@ -56,8 +54,8 @@
 
   cmap = cmap_orig = get (gcf (), "colormap");
 
-  t0 = clock;
-  while (etime (clock, t0) < t)
+  t0 = clock ();
+  while (etime (clock (), t0) < t)
     cmap = shift (cmap, inc, 1);
     set (gcf (), "colormap", cmap);
     drawnow ();
--- a/scripts/image/spring.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/spring.m	Thu Nov 19 13:08:00 2020 -0800
@@ -35,9 +35,7 @@
 
 function map = spring (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("spring: N must be a scalar");
     endif
--- a/scripts/image/summer.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/summer.m	Thu Nov 19 13:08:00 2020 -0800
@@ -35,9 +35,7 @@
 
 function map = summer (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("summer: N must be a scalar");
     endif
--- a/scripts/image/viridis.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/viridis.m	Thu Nov 19 13:08:00 2020 -0800
@@ -40,9 +40,7 @@
 
 function map = viridis (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("viridis: N must be a scalar");
     endif
--- a/scripts/image/white.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/white.m	Thu Nov 19 13:08:00 2020 -0800
@@ -35,9 +35,7 @@
 
 function map = white (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("white: N must be a scalar");
     endif
--- a/scripts/image/winter.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/image/winter.m	Thu Nov 19 13:08:00 2020 -0800
@@ -35,9 +35,7 @@
 
 function map = winter (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("winter: N must be a scalar");
     endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/io/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/io/beep.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/io/beep.m	Thu Nov 19 13:08:00 2020 -0800
@@ -35,13 +35,9 @@
 
 function beep ()
 
-  if (nargin != 0)
-    print_usage ();
-  endif
-
   puts ("\a");
 
 endfunction
 
 
-%!error (beep (1))
+%!error beep (1)
--- a/scripts/io/csvread.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/io/csvread.m	Thu Nov 19 13:08:00 2020 -0800
@@ -38,7 +38,7 @@
 ## @end example
 ##
 ## Any optional arguments are passed directly to @code{dlmread}
-## (@pxref{XREFdlmread,,dlmread}).
+## (@pxref{XREFdlmread,,@code{dlmread}}).
 ## @seealso{dlmread, textscan, csvwrite, dlmwrite}
 ## @end deftypefn
 
--- a/scripts/io/csvwrite.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/io/csvwrite.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,7 +36,7 @@
 ## @end example
 ##
 ## Any optional arguments are passed directly to @code{dlmwrite}
-## (@pxref{XREFdlmwrite,,dlmwrite}).
+## (@pxref{XREFdlmwrite,,@code{dlmwrite}}).
 ## @seealso{csvread, dlmwrite, dlmread}
 ## @end deftypefn
 
--- a/scripts/io/fileread.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/io/fileread.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function str = fileread (filename)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -64,6 +64,5 @@
 %! assert (str, [cstr{1} "\n" cstr{2} "\n" cstr{3} "\n"]);
 
 ## Test input validation
-%!error fileread ()
-%!error fileread (1, 2)
+%!error <Invalid call> fileread ()
 %!error <FILENAME argument must be a string> fileread (1)
--- a/scripts/io/importdata.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/io/importdata.m	Thu Nov 19 13:08:00 2020 -0800
@@ -69,7 +69,7 @@
 
 function [output, delimiter, header_rows] = importdata (fname, delimiter = "", header_rows = -1)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -82,7 +82,7 @@
   if (nargin > 1)
     if (! ischar (delimiter)
         || (length (delimiter) > 1 && ! strcmp (delimiter, '\t')))
-      error("importdata: DELIMITER must be a single character");
+      error ("importdata: DELIMITER must be a single character");
     endif
     if (strcmp (delimiter, '\t'))
       delimiter = "\t";
@@ -98,7 +98,7 @@
 
   ## Check file format
   ## Get the extension from the filename.
-  [~, ~, ext, ~] = fileparts (fname);
+  [~, ~, ext] = fileparts (fname);
   ext = lower (ext);
 
   switch (ext)
@@ -175,8 +175,8 @@
 
     ## If no delimiter determined yet, make a guess.
     if (isempty (delimiter))
-      ## This pattern can be fooled, but mostly does the job just fine.
-      delim = regexpi (row, '[-+\d.e*ij ]+([^-+\de.ij])[-+\de*.ij ]',
+      ## Look for number, DELIMITER, DELIMITER*, number
+      delim = regexpi (row, '[-+]?\d*[.]?\d+(?:[ed][-+]?\d+)?[ij]?([^-+\d.deij])\1*[-+]?\d*[.]?\d+(?:[ed][-+]?\d+)?[ij]?',
                        'tokens', 'once');
       if (! isempty (delim))
         delimiter = delim{1};
@@ -200,6 +200,14 @@
       row = -1;
       break;
     else
+      ## The number of header rows and header columns is now known.
+      header_cols = find (! isnan (row_data), 1) - 1;
+      has_rowheaders = (header_cols == 1);
+
+      ## Set colheaders output from textdata if appropriate
+      ## NOTE: Octave chooses to be Matlab incompatible and return
+      ## both 'rowheaders' and 'colheaders' when they are present.
+      ## Matlab allows only one to be present at a time.
       if (! isempty (output.textdata))
         if (delimiter == " ")
           output.colheaders = regexp (strtrim (output.textdata{end}),
@@ -207,9 +215,22 @@
         else
           output.colheaders = ostrsplit (output.textdata{end}, delimiter);
         endif
+
+        nc_hdr = numel (output.colheaders);
+        nc_dat = numel (row_data);
+        if (! has_rowheaders)
+          if (nc_hdr != nc_dat)
+            output = rmfield (output, {"rowheaders", "colheaders"});
+          else
+            output = rmfield (output, "rowheaders");
+          endif
+        else
+          if (nc_hdr != nc_dat-1)
+            output = rmfield (output, "colheaders");
+          endif
+        endif
       endif
-      header_cols = find (! isnan (row_data), 1) - 1;
-      ## The number of header rows and header columns is now known.
+
       break;
     endif
 
@@ -243,19 +264,31 @@
   fclose (fid);
 
   if (num_header_rows >= 0)
-    header_rows = num_header_rows;
+    ## User has defined a number of header rows which disagrees with the
+    ## auto-detected number.  Print a warning.
+    if (num_header_rows < header_rows)
+      warning ("Octave:importdata:headerrows_mismatch",
+               "importdata: detected %d header rows, but HEADER_ROWS input configured %d rows", header_rows, num_header_rows);
+    endif
+  else
+    ## use the automatically detected number of header rows
+    num_header_rows = header_rows;
   endif
 
   ## Now, let the efficient built-in routine do the bulk of the work.
   if (delimiter == " ")
-    output.data = dlmread (fname, "", header_rows, header_cols,
+    output.data = dlmread (fname, "", num_header_rows, header_cols,
                            "emptyvalue", NA);
   else
-    output.data = dlmread (fname, delimiter, header_rows, header_cols,
+    output.data = dlmread (fname, delimiter, num_header_rows, header_cols,
                            "emptyvalue", NA);
   endif
 
   ## Go back and correct any individual values that did not convert.
+  ## FIXME: This is only efficient when the number of bad conversions is small.
+  ##        Any file with 'rowheaders' will cause the for loop to execute over
+  ##        *every* line in the file.
+
   na_idx = isna (output.data);
   if (header_cols > 0)
     na_idx = [(true (rows (na_idx), header_cols)), na_idx];
@@ -265,8 +298,11 @@
     file_content = ostrsplit (fileread (fname), "\r\n", true);
 
     na_rows = find (any (na_idx, 2));
+    ## Prune text lines in header that were already collected
+    idx = (na_rows(1:min (header_rows, end)) + num_header_rows) <= header_rows;
+    na_rows(idx) = [];
     for ridx = na_rows(:)'
-      row = file_content{ridx+header_rows};
+      row = file_content{ridx+num_header_rows};
       if (delimiter == " ")
         fields = regexp (strtrim (row), ' +', 'split');
       else
@@ -277,28 +313,45 @@
       if (! size_equal (missing_idx, fields))
         ## Fields completely missing at end of line.  Replace with NA.
         col = columns (fields);
-        output.data(ridx, (col+1):end) = NA;
+        ## FIXME: This code should be redundant because dlmread was called
+        ##        with "emptyval", NA.  Delete if there are no problems
+        ##        detected after some time.  Commented out: 5/23/2020.
+        ##output.data(ridx, (col+1):end) = NA;
         missing_idx = missing_idx(1:col);
       endif
       text = fields(missing_idx);
 
       text = text(! strcmpi (text, "NA"));  #  Remove valid "NA" entries
+      text = text(! strcmpi (text, ""));    #  Remove empty entries
       if (! isempty (text))
-        output.textdata = [output.textdata; text(:)];
+        output.textdata(end+1, 1:columns (text)) = text;
       endif
 
-      if (header_cols)
-        output.rowheaders(end+1, :) = fields(1:header_cols);
+      if (has_rowheaders)
+        output.rowheaders(end+1, 1) = fields(1);
       endif
     endfor
 
   endif
 
-  ## Final cleanup to satisfy output configuration
+  ## Final cleanup to satisfy Matlab compatibility
   if (all (cellfun ("isempty", output.textdata)))
     output = output.data;
-  elseif (! isempty (output.rowheaders) && ! isempty (output.colheaders))
-    output = struct ("data", {output.data}, "textdata", {output.textdata});
+  else
+    ## Text fields should be cell array of strings, rather than just cell.
+    try
+      output.textdata = cellstr (output.textdata);
+    end_try_catch
+    try
+      output.rowheaders = cellstr (output.rowheaders);
+    end_try_catch
+    try
+      output.colheaders = cellstr (output.colheaders);
+    end_try_catch
+  endif
+
+  if (num_header_rows != header_rows)
+    header_rows = num_header_rows;
   endif
 
 endfunction
@@ -377,7 +430,6 @@
 %! A.data = [3.1 -7.2 0; 0.012 6.5 128];
 %! A.textdata = {"This is a header row."; ...
 %!               "this row does not contain any data, but the next one does."};
-%! A.colheaders = A.textdata (2);
 %! fn  = tempname ();
 %! fid = fopen (fn, "w");
 %! fprintf (fid, "%s\n", A.textdata{:});
@@ -393,6 +445,7 @@
 %! ## Column headers, only last row is returned in colheaders
 %! A.data = [3.1 -7.2 0; 0.012 6.5 128];
 %! A.textdata = {"Label1\tLabel2\tLabel3";
+%!               "";
 %!               "col 1\tcol 2\tcol 3"};
 %! A.colheaders = {"col 1", "col 2", "col 3"};
 %! fn  = tempname ();
@@ -404,7 +457,7 @@
 %! unlink (fn);
 %! assert (a, A);
 %! assert (d, "\t");
-%! assert (h, 2);
+%! assert (h, 3);
 
 %!test
 %! ## Row headers
@@ -425,9 +478,11 @@
 %! ## Row/Column headers and Header Text
 %! A.data = [3.1 -7.2 0; 0.012 6.5 128];
 %! A.textdata = {"This is introductory header text"
-%!               "      col1 col2 col3"
+%!               "col1\tcol2\tcol3"
 %!               "row1"
 %!               "row2"};
+%! A.rowheaders = A.textdata(3:4);
+%! A.colheaders = {"col1", "col2", "col3"};
 %! fn  = tempname ();
 %! fid = fopen (fn, "w");
 %! fprintf (fid, "%s\n", A.textdata{1:2});
@@ -511,8 +566,7 @@
 %!test
 %! ## Missing values and Text Values
 %! A.data = [3.1 NA 0; 0.012 NA 128];
-%! A.textdata = {char(zeros(1,0))
-%!               "NO DATA"};
+%! A.textdata = {"NO DATA"};
 %! fn  = tempname ();
 %! fid = fopen (fn, "w");
 %! fputs (fid, "3.1\t\t0\n0.012\tNO DATA\t128");
@@ -585,8 +639,37 @@
 %! assert (d, "");
 %! assert (h, 3);
 
-%!error importdata ()
-%!error importdata (1,2,3,4)
+%!test <*58294>
+%! ## Varying values of header lines field
+%! fn  = tempname ();
+%! fid = fopen (fn, "w");
+%! fputs (fid, "header1\nheader2\n3.1\n4.2");
+%! fclose (fid);
+%! warning ("off", "Octave:importdata:headerrows_mismatch", "local");
+%! ## Base import
+%! [a, d, h] = importdata (fn, "");
+%! assert (a.data, [3.1; 4.2]);
+%! assert (a.textdata, {"header1"; "header2"});
+%! assert (h, 2);
+%! ## Import with 0 header lines
+%! [a, d, h] = importdata (fn, "", 0);
+%! assert (a.data, [NA; NA; 3.1; 4.2]);
+%! assert (a.textdata, {"header1"; "header2"});
+%! assert (h, 0);
+%! ## Import with 1 header lines
+%! [a, d, h] = importdata (fn, "", 1);
+%! assert (a.data, [NA; 3.1; 4.2]);
+%! assert (a.textdata, {"header1"; "header2"});
+%! assert (h, 1);
+%! ## Import with 3 header lines
+%! [a, d, h] = importdata (fn, "", 3);
+%! assert (a.data, [4.2]);
+%! assert (a.textdata, {"header1"; "header2"; "3.1"});
+%! assert (h, 3);
+%! unlink (fn);
+
+## Test input validation
+%!error <Invalid call> importdata ()
 %!error <FNAME must be a string> importdata (1)
 %!error <option -pastespecial not implemented> importdata ("-pastespecial")
 %!error <DELIMITER must be a single character> importdata ("foo", 1)
@@ -594,3 +677,10 @@
 %!error <HEADER_ROWS must be an integer> importdata ("foo", " ", "1")
 %!error <HEADER_ROWS must be an integer> importdata ("foo", " ", 1.5)
 %!error <not implemented for file format .avi> importdata ("foo.avi")
+%!warning <detected 2 header rows, but HEADER_ROWS input configured 1 rows>
+%! fn  = tempname ();
+%! fid = fopen (fn, "w");
+%! fputs (fid, "header1\nheader2\n3.1");
+%! fclose (fid);
+%! a = importdata (fn, "", 1);
+%! unlink (fn);
--- a/scripts/io/is_valid_file_id.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/io/is_valid_file_id.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,18 +31,18 @@
 
 function retval = is_valid_file_id (fid)
 
+  if (nargin < 1)
+    print_usage ();
+  endif
+
   retval = false;
 
-  if (nargin == 1)
-    try
-      if (isscalar (fid))
-        [file, mode, arch] = fopen (fid);
-        retval = ! isempty (file);
-      endif
-    end_try_catch
-  else
-    print_usage ();
-  endif
+  try
+    if (isscalar (fid))
+      [file, mode, arch] = fopen (fid);
+      retval = ! isempty (file);
+    endif
+  end_try_catch
 
 endfunction
 
--- a/scripts/io/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/io/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/beep.m \
   %reldir%/csvread.m \
   %reldir%/csvwrite.m \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/java/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/java/javachk.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/java/javachk.m	Thu Nov 19 13:08:00 2020 -0800
@@ -69,7 +69,7 @@
 
 function msg = javachk (feature, caller = "")
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   elseif (! ischar (feature))
     error ("javachk: FEATURE must be a string");
@@ -133,7 +133,7 @@
 endfunction
 
 
-%!testif ; ! __octave_config_info__().build_features.JAVA
+%!testif ; ! __octave_config_info__ ().build_features.JAVA
 %! msg = javachk ("desktop");
 %! assert (msg.message, "javachk: this function is not supported, Octave was not compiled with Java support");
 %! assert (msg.identifier, "Octave:javachk:java-not-supported");
@@ -158,7 +158,7 @@
 %! assert (javachk ("jvm"), stnul);
 
 ## Test input validation
-%!error javachk ()
-%!error javachk (1)
+%!error <Invalid call> javachk ()
+%!error <FEATURE must be a string> javachk (1)
 %!error javachk ("jvm", 2)
 %!error javachk ("jvm", "feature", "ok")
--- a/scripts/java/javaclasspath.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/java/javaclasspath.m	Thu Nov 19 13:08:00 2020 -0800
@@ -62,10 +62,6 @@
 
 function [path1, path2] = javaclasspath (what = "")
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   ## dynamic classpath
   dynamic_path = javaMethod ("getClassPath", "org.octave.ClassHelper");
   dynamic_path_list = ostrsplit (dynamic_path, pathsep ());
--- a/scripts/java/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/java/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/javaArray.m \
   %reldir%/java_get.m \
   %reldir%/java_set.m \
--- a/scripts/java/usejava.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/java/usejava.m	Thu Nov 19 13:08:00 2020 -0800
@@ -54,7 +54,7 @@
 
 function retval = usejava (feature)
 
-  if (nargin != 1 || ! ischar (feature))
+  if (nargin < 1 || ! ischar (feature))
     print_usage ();
   endif
 
@@ -92,7 +92,6 @@
 %! assert (usejava ("jvm"), true);
 
 ## Test input validation
-%!error usejava ()
-%!error usejava (1, 2)
-%!error usejava (1)
+%!error <Invalid call> usejava ()
+%!error <Invalid call> usejava (1)
 %!error <unrecognized FEATURE> usejava ("abc")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/legacy/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/legacy/@inline/argnames.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/legacy/@inline/argnames.m	Thu Nov 19 13:08:00 2020 -0800
@@ -32,7 +32,7 @@
 
 function args = argnames (obj)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/legacy/@inline/char.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/legacy/@inline/char.m	Thu Nov 19 13:08:00 2020 -0800
@@ -34,7 +34,7 @@
 
 function expr = char (obj)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/legacy/@inline/formula.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/legacy/@inline/formula.m	Thu Nov 19 13:08:00 2020 -0800
@@ -34,7 +34,7 @@
 
 function expr = formula (obj)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/legacy/@inline/vectorize.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/legacy/@inline/vectorize.m	Thu Nov 19 13:08:00 2020 -0800
@@ -52,7 +52,7 @@
 
 function fcn = vectorize (obj)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/legacy/findstr.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/legacy/findstr.m	Thu Nov 19 13:08:00 2020 -0800
@@ -61,7 +61,7 @@
              "findstr is obsolete; use strfind instead\n");
   endif
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -157,6 +157,6 @@
 %!assert (findstr ("aba", "abababa", 0), [1, 5])
 
 ## Test input validation
-%!error findstr ()
-%!error findstr ("foo", "bar", 3, 4)
+%!error <Invalid call> findstr ()
+%!error <Invalid call> findstr ("str1")
 %!error <must have only one non-singleton dimension> findstr (["AB" ; "CD"], "C")
--- a/scripts/legacy/flipdim.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/legacy/flipdim.m	Thu Nov 19 13:08:00 2020 -0800
@@ -40,4 +40,5 @@
   endif
 
   y = flip (varargin{:});
+
 endfunction
--- a/scripts/legacy/genvarname.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/legacy/genvarname.m	Thu Nov 19 13:08:00 2020 -0800
@@ -114,7 +114,7 @@
              "genvarname is obsolete; use matlab.lang.makeValidName or matlab.lang.makeUniqueStrings instead\n");
   endif
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -227,8 +227,7 @@
 %!assert (genvarname ("x", {"a", "b"; "x", "d"}), "x1")
 
 ## Test input validation
-%!error genvarname ()
-%!error genvarname (1,2,3)
+%!error <Invalid call> genvarname ()
 %!error <more than one STR is given, it must be a cellstr> genvarname (char ("a", "b", "c"))
 %!error <STR must be a string or cellstr> genvarname (1)
 %!error <more than one exclusion is given, it must be a cellstr> genvarname ("x", char ("a", "b", "c"))
--- a/scripts/legacy/isdir.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/legacy/isdir.m	Thu Nov 19 13:08:00 2020 -0800
@@ -51,7 +51,7 @@
              "isdir is obsolete; use isfolder or dir_in_loadpath instead\n");
   endif
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -69,5 +69,4 @@
 %!assert (isdir (pwd ()))
 %!assert (! isdir (tempname ()))
 
-%!error isdir ()
-%!error isdir (1, 2)
+%!error <Invalid call> isdir ()
--- a/scripts/legacy/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/legacy/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/__vectorize__.m \
   %reldir%/findstr.m \
   %reldir%/flipdim.m \
--- a/scripts/legacy/setstr.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/legacy/setstr.m	Thu Nov 19 13:08:00 2020 -0800
@@ -7,19 +7,21 @@
 ##
 ## This file is part of Octave.
 ##
-## Octave is free software; you can redistribute it and/or modify it
+## Octave is free software: you can redistribute it and/or modify it
 ## under the terms of the GNU General Public License as published by
-## the Free Software Foundation; either version 3 of the License, or (at
-## your option) any later version.
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
 ##
 ## Octave is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-## General Public License for more details.
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Octave; see the file COPYING.  If not, see
-## <http://www.gnu.org/licenses/>.
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
 
 ## -*- texinfo -*-
 ## @deftypefn {} {@var{s} =} setstr (@var{x})
--- a/scripts/legacy/strmatch.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/legacy/strmatch.m	Thu Nov 19 13:08:00 2020 -0800
@@ -70,7 +70,7 @@
              "strmatch is obsolete; use strncmp or strcmp instead\n");
   endif
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -150,7 +150,7 @@
 ## Test input validation
 %!error <Invalid call to strmatch> strmatch ()
 %!error <Invalid call to strmatch> strmatch ("a")
-%!error <Invalid call to strmatch> strmatch ("a", "aaa", "exact", 1)
+%!error <called with too many inputs> strmatch ("a", "aaa", "exact", 1)
 %!error <S must contain only one string> strmatch ({"a", "b"}, "aaa")
 %!error <S must be a string> strmatch (1, "aaa")
 %!error <S must be a string> strmatch (char ("a", "bb"), "aaa")
--- a/scripts/legacy/strread.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/legacy/strread.m	Thu Nov 19 13:08:00 2020 -0800
@@ -354,7 +354,7 @@
     ## Check for unsupported format specifiers
     errpat = '(\[.*\]|[cq]|[nfdu]8|[nfdu]16|[nfdu]32|[nfdu]64)';
     if (! all (cellfun ("isempty", regexp (fmt_words(idy2), errpat))))
-      error ("strread: %q, %c, %[] or bit width format specifiers are not supported yet.");
+      error ("strread: %q, %c, %[] or bit width format specifiers are not supported yet");
     endif
 
     ## Format conversion specifiers following literals w/o space/delim
--- a/scripts/legacy/textread.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/legacy/textread.m	Thu Nov 19 13:08:00 2020 -0800
@@ -346,7 +346,7 @@
 ## Read multiple lines using empty format string
 %!test
 %! f = tempname ();
-%! unlink (f);
+%! sts = unlink (f);
 %! fid = fopen (f, "w");
 %! d = rand (1, 4);
 %! fprintf (fid, "  %f %f   %f  %f ", d);
@@ -358,7 +358,7 @@
 ## Empty format, corner case = one line w/o EOL
 %!test
 %! f = tempname ();
-%! unlink (f);
+%! sts = unlink (f);
 %! fid = fopen (f, "w");
 %! d = rand (1, 4);
 %! fprintf (fid, "  %f %f   %f  %f ", d);
--- a/scripts/legacy/vectorize.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/legacy/vectorize.m	Thu Nov 19 13:08:00 2020 -0800
@@ -48,7 +48,7 @@
              "vectorize is unreliable; its use is strongly discouraged\n");
   endif
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -68,8 +68,10 @@
   else
     error ("vectorize: FUN must be a string or anonymous function handle");
   endif
+
 endfunction
 
+
 %!assert (vectorize ("x.^2 + 1"), "x.^2 + 1")
 %!test
 %! fh = @(x) x.^2 + 1;
@@ -91,7 +93,5 @@
 %! assert (finfo.function, "@(x) 2 .^ x .^ 5");
 
 ## Test input validation
-%!error vectorize ()
-%!error vectorize (1, 2)
+%!error <Invalid call> vectorize ()
 %!error <FUN must be a string or anonymous function handle> vectorize (1)
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/linear-algebra/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/linear-algebra/bandwidth.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/bandwidth.m	Thu Nov 19 13:08:00 2020 -0800
@@ -40,7 +40,7 @@
 
 function [lower, upper] = bandwidth (A, type)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -108,8 +108,7 @@
 %! assert ([a,b], [4,4]);
 
 ## Test input validation
-%!error bandwidth ()
-%!error bandwidth (1,2,3)
+%!error <Invalid call> bandwidth ()
 %!error <A must be a 2-D numeric or logical> bandwidth ("string", "lower")
 %!error <A must be a 2-D numeric or logical> bandwidth (ones (3,3,3), "lower")
 %!error <TYPE must be "lower" or "upper"> bandwidth (ones (2), "uper")
--- a/scripts/linear-algebra/commutation_matrix.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/commutation_matrix.m	Thu Nov 19 13:08:00 2020 -0800
@@ -76,7 +76,7 @@
 
 function k = commutation_matrix (m, n)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   else
     if (! (isscalar (m) && m == fix (m) && m > 0))
--- a/scripts/linear-algebra/cond.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/cond.m	Thu Nov 19 13:08:00 2020 -0800
@@ -39,8 +39,8 @@
 ##
 ## By default, @code{@var{p} = 2} is used which implies a (relatively slow)
 ## singular value decomposition.  Other possible selections are
-## @code{@var{p} = 1, Inf, "fro"} which are generally faster.  See @code{norm}
-## for a full discussion of possible @var{p} values.
+## @code{@var{p} = 1, Inf, "fro"} which are generally faster.  For a full
+## discussion of possible @var{p} values, @pxref{XREFnorm,,@code{norm}}.
 ##
 ## The condition number of a matrix quantifies the sensitivity of the matrix
 ## inversion operation when small changes are made to matrix elements.  Ideally
@@ -53,7 +53,7 @@
 
 function retval = cond (A, p = 2)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -95,8 +95,7 @@
 %!assert (cond ([1, 2; 2, 1]), 3, sqrt (eps))
 %!assert (cond ([1, 2, 3; 4, 5, 6; 7, 8, 9]) > 1.0e+16)
 
-%!error cond ()
-%!error cond (1, 2, 3)
+%!error <Invalid call> cond ()
 %!error <A must be a 2-D matrix> cond (ones (1,3,3))
 %!error <A must not contain Inf or NaN value> cond ([1, 2;Inf 4])
 %!error <A must not contain Inf or NaN value> cond ([1, 2;NaN 4])
--- a/scripts/linear-algebra/condeig.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/condeig.m	Thu Nov 19 13:08:00 2020 -0800
@@ -67,7 +67,7 @@
 
 function [v, lambda, c] = condeig (a)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -134,12 +134,11 @@
 %! assert (lambda, expected_lambda, 0.001);
 %! assert (c, expected_c, 0.001);
 
-# Test empty input
+## Test empty input
 %!assert (condeig ([]), [])
 
 ## Test input validation
-%!error condeig ()
-%!error condeig (1,2)
+%!error <Invalid call> condeig ()
 %!error <A must be a square numeric matrix> condeig ({1})
 %!error <A must be a square numeric matrix> condeig (ones (3,2))
 %!error <A must be a square numeric matrix> condeig (ones (2,2,2))
--- a/scripts/linear-algebra/condest.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/condest.m	Thu Nov 19 13:08:00 2020 -0800
@@ -26,8 +26,12 @@
 ## -*- texinfo -*-
 ## @deftypefn  {} {@var{cest} =} condest (@var{A})
 ## @deftypefnx {} {@var{cest} =} condest (@var{A}, @var{t})
-## @deftypefnx {} {@var{cest} =} condest (@var{A}, @var{solvefun}, @var{t}, @var{p1}, @var{p2}, @dots{})
-## @deftypefnx {} {@var{cest} =} condest (@var{Afcn}, @var{solvefun}, @var{t}, @var{p1}, @var{p2}, @dots{})
+## @deftypefnx {} {@var{cest} =} condest (@var{A}, @var{Ainvfcn})
+## @deftypefnx {} {@var{cest} =} condest (@var{A}, @var{Ainvfcn}, @var{t})
+## @deftypefnx {} {@var{cest} =} condest (@var{A}, @var{Ainvfcn}, @var{t}, @var{p1}, @var{p2}, @dots{})
+## @deftypefnx {} {@var{cest} =} condest (@var{Afcn}, @var{Ainvfcn})
+## @deftypefnx {} {@var{cest} =} condest (@var{Afcn}, @var{Ainvfcn}, @var{t})
+## @deftypefnx {} {@var{cest} =} condest (@var{Afcn}, @var{Ainvfcn}, @var{t}, @var{p1}, @var{p2}, @dots{})
 ## @deftypefnx {} {[@var{cest}, @var{v}] =} condest (@dots{})
 ##
 ## Estimate the 1-norm condition number of a square matrix @var{A} using
@@ -35,54 +39,56 @@
 ##
 ## The optional input @var{t} specifies the number of test vectors (default 5).
 ##
-## If the matrix is not explicit, e.g., when estimating the condition number of
-## @var{A} given an LU@tie{}factorization, @code{condest} uses the following
-## functions:
+## The input may be a matrix @var{A} (the algorithm is particularly
+## appropriate for large, sparse matrices).  Alternatively, the behavior of
+## the matrix can be defined implicitly by functions.  When using an implicit
+## definition, @code{condest} requires the following functions:
 ##
 ## @itemize @minus
-## @item @var{Afcn} which must return
+## @item @code{@var{Afcn} (@var{flag}, @var{x})} which must return
 ##
 ## @itemize @bullet
 ## @item
-## the dimension @var{n} of @var{a}, if @var{flag} is @qcode{"dim"}
+## the dimension @var{n} of @var{A}, if @var{flag} is @qcode{"dim"}
 ##
 ## @item
-## true if @var{a} is a real operator, if @var{flag} is @qcode{"real"}
+## true if @var{A} is a real operator, if @var{flag} is @qcode{"real"}
 ##
 ## @item
-## the result @code{@var{a} * @var{x}}, if @var{flag} is "notransp"
+## the result @code{@var{A} * @var{x}}, if @var{flag} is "notransp"
 ##
 ## @item
-## the result @code{@var{a}' * @var{x}}, if @var{flag} is "transp"
+## the result @code{@var{A}' * @var{x}}, if @var{flag} is "transp"
 ## @end itemize
 ##
-## @item @var{solvefun} which must return
+## @item @code{@var{Ainvfcn} (@var{flag}, @var{x})} which must return
 ##
 ## @itemize @bullet
 ## @item
-## the dimension @var{n} of @var{a}, if @var{flag} is @qcode{"dim"}
+## the dimension @var{n} of @code{inv (@var{A})}, if @var{flag} is
+## @qcode{"dim"}
 ##
 ## @item
-## true if @var{a} is a real operator, if @var{flag} is @qcode{"real"}
+## true if @code{inv (@var{A})} is a real operator, if @var{flag} is
+## @qcode{"real"}
 ##
 ## @item
-## the result @code{@var{a} \ @var{x}}, if @var{flag} is "notransp"
+## the result @code{inv (@var{A}) * @var{x}}, if @var{flag} is "notransp"
 ##
 ## @item
-## the result @code{@var{a}' \ @var{x}}, if @var{flag} is "transp"
+## the result @code{inv (@var{A})' * @var{x}}, if @var{flag} is "transp"
 ## @end itemize
 ## @end itemize
 ##
-## The parameters @var{p1}, @var{p2}, @dots{} are arguments of
+## Any parameters @var{p1}, @var{p2}, @dots{} are additional arguments of
 ## @code{@var{Afcn} (@var{flag}, @var{x}, @var{p1}, @var{p2}, @dots{})}
-## and @code{@var{solvefcn} (@var{flag}, @var{x}, @var{p1}, @var{p2},
-## @dots{})}.
+## and @code{@var{Ainvfcn} (@var{flag}, @var{x}, @var{p1}, @var{p2}, @dots{})}.
 ##
 ## The principal output is the 1-norm condition number estimate @var{cest}.
 ##
-## The optional second output is an approximate null vector when @var{cest} is
-## large; it satisfies the equation
-## @code{norm (A*v, 1) == norm (A, 1) * norm (@var{v}, 1) / @var{est}}.
+## The optional second output @var{v} is an approximate null vector; it
+## satisfies the equation @code{norm (@var{A}*@var{v}, 1) ==
+## norm (@var{A}, 1) * norm (@var{v}, 1) / @var{cest}}.
 ##
 ## Algorithm Note: @code{condest} uses a randomized algorithm to approximate
 ## the 1-norms.  Therefore, if consistent results are required, the
@@ -104,7 +110,7 @@
 ## Pseudospectra}.  @url{https://citeseer.ist.psu.edu/223007.html}
 ## @end itemize
 ##
-## @seealso{cond, norm, normest1, normest}
+## @seealso{cond, rcond, norm, normest1, normest}
 ## @end deftypefn
 
 ## Code originally licensed under:
@@ -142,10 +148,6 @@
 ## OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 ## SUCH DAMAGE.
 
-## Author: Jason Riedy <ejr@cs.berkeley.edu>
-## Keywords: linear-algebra norm estimation
-## Version: 0.2
-
 function [cest, v] = condest (varargin)
 
   if (nargin < 1 || nargin > 6)
@@ -154,8 +156,8 @@
 
   have_A = false;
   have_t = false;
-  have_apply_normest1 = false;
-  have_solve_normest1 = false;
+  have_Afcn = false;
+  have_Ainvfcn = false;
 
   if (isnumeric (varargin{1}))
     A = varargin{1};
@@ -166,8 +168,8 @@
     n = rows (A);
     if (nargin > 1)
       if (is_function_handle (varargin{2}))
-        solve = varargin{2};
-        have_solve_normest1 = true;
+        Ainvfcn = varargin{2};
+        have_Ainvfcn = true;
         if (nargin > 2)
           t = varargin{3};
           have_t = true;
@@ -175,23 +177,20 @@
       else
         t = varargin{2};
         have_t = true;
-        real_op = isreal (A);
       endif
-    else
-      real_op = isreal (A);
     endif
   elseif (is_function_handle (varargin{1}))
     if (nargin == 1)
-      error("condest: must provide SOLVEFCN when using AFCN");
+      error ("condest: must provide AINVFCN when using AFCN");
     endif
-    apply = varargin{1};
-    have_apply_normest1 = true;
+    Afcn = varargin{1};
+    have_Afcn = true;
     if (! is_function_handle (varargin{2}))
-      error("condest: SOLVEFCN must be a function handle");
+      error ("condest: AINVFCN must be a function handle");
     endif
-    solve = varargin{2};
-    have_solve_normest1 = true;
-    n = apply ("dim", [], varargin{4:end});
+    Ainvfcn = varargin{2};
+    have_Ainvfcn = true;
+    n = Afcn ("dim", [], varargin{4:end});
     if (nargin > 2)
       t = varargin{3};
       have_t = true;
@@ -207,99 +206,131 @@
   ## Disable warnings which may be emitted during calculation process.
   warning ("off", "Octave:nearly-singular-matrix", "local");
 
-  if (! have_solve_normest1)
-    ## prepare solve in normest1 form
+  if (! have_Ainvfcn)
+    ## Prepare Ainvfcn in normest1 form
     if (issparse (A))
-      [L, U, P, Pc] = lu (A);
-      solve = @(flag, x) solve_sparse (flag, x, n, real_op, L, U, P, Pc);
+      [L, U, P, Q] = lu (A);
+      Ainvfcn = @inv_sparse_fcn;
     else
       [L, U, P] = lu (A);
-      solve = @(flag, x) solve_not_sparse (flag, x, n, real_op, L, U, P);
+      Q = [];
+      Ainvfcn = @inv_full_fcn;
     endif
 
-    ## Check for singular matrices before continuing
+    ## Check for singular matrices before continuing (bug #46737)
     if (any (diag (U) == 0))
       cest = Inf;
       v = [];
       return;
     endif
+
+    ## Initialize solver
+    Ainvfcn ("init", A, L, U, P, Q);
+    clear L U P Q;
   endif
 
   if (have_A)
     Anorm = norm (A, 1);
   else
-    Anorm = normest1 (apply, t, [], varargin{4:end});
+    Anorm = normest1 (Afcn, t, [], varargin{4:end});
   endif
-  [Ainv_norm, v, w] = normest1 (solve, t, [], varargin{4:end});
+  [Ainv_norm, v, w] = normest1 (Ainvfcn, t, [], varargin{4:end});
 
   cest = Anorm * Ainv_norm;
   if (isargout (2))
     v = w / norm (w, 1);
   endif
 
+  if (! have_Ainvfcn)
+    Ainvfcn ("clear");  # clear persistent memory in subfunction
+  endif
+
 endfunction
 
-function value = solve_sparse (flag, x, n, real_op, L , U , P , Pc)
-  ## FIXME: Sparse algorithm is less accurate than full matrix version
-  ##        See BIST test for non-orthogonal matrix where relative tolerance
+function retval = inv_sparse_fcn (flag, x, varargin)
+  ## FIXME: Sparse algorithm is less accurate than full matrix version.
+  ##        See BIST test for asymmetric matrix where relative tolerance
   ##        of 1e-12 is used for sparse, but 4e-16 for full matrix.
+  ##        BUT, does it really matter for an "estimate"?
+  persistent Ainv Ainvt n isreal_op;
+
   switch (flag)
     case "dim"
-      value = n;
+      retval = n;
     case "real"
-      value = real_op;
+      retval = isreal_op;
     case "notransp"
-      value = Pc' * (U \ (L \ (P * x)));
+      retval = Ainv * x;
     case "transp"
-      value = P' * (L' \ (U' \ (Pc * x)));
+      retval = Ainvt * x;
+    case "init"
+      n = rows (x);
+      isreal_op = isreal (x);
+      [L, U, P, Q] = deal (varargin{1:4});
+      Ainv = Q * (U \ (L \ P));
+      Ainvt = P' * (L' \ (U' \ Q'));
+    case "clear"  # called to free memory at end of condest function
+      clear Ainv Ainvt n isreal_op;
   endswitch
+
 endfunction
 
-function value = solve_not_sparse (flag, x, n, real_op, L, U, P)
+function retval = inv_full_fcn (flag, x, varargin)
+  persistent Ainv Ainvt n isreal_op;
+
   switch (flag)
     case "dim"
-      value = n;
+      retval = n;
     case "real"
-      value = real_op;
+      retval = isreal_op;
     case "notransp"
-      value = U \ (L \ (P * x));
+      retval = Ainv * x;
     case "transp"
-      value = P' * (L' \ (U' \ x));
+      retval = Ainvt \ x;
+    case "init"
+      n = rows (x);
+      isreal_op = isreal (x);
+      [L, U, P] = deal (varargin{1:3});
+      Ainv = U \ (L \ P);
+      Ainvt = P' * (L' \ U');
+    case "clear"  # called to free memory at end of condest function
+      clear Ainv Ainvt n isreal_op;
   endswitch
+
 endfunction
 
 
 ## Note: These test bounds are very loose.  There is enough randomization to
 ## trigger odd cases with hilb().
 
-%!function value = apply_fun (flag, x, A, m)
+%!function retval = __Afcn__ (flag, x, A, m)
 %!  if (nargin == 3)
 %!    m = 1;
 %!  endif
 %!  switch (flag)
 %!    case "dim"
-%!      value = length (A);
+%!      retval = length (A);
 %!    case "real"
-%!      value = isreal (A);
+%!      retval = isreal (A);
 %!    case "notransp"
-%!      value = x; for i = 1:m, value = A * value;, endfor
+%!      retval = x; for i = 1:m, retval = A * retval;, endfor
 %!    case "transp"
-%!      value = x; for i = 1:m, value = A' * value;, endfor
+%!      retval = x; for i = 1:m, retval = A' * retval;, endfor
 %!  endswitch
 %!endfunction
-%!function value = solve_fun (flag, x, A, m)
+%!function retval = __Ainvfcn__ (flag, x, A, m)
 %!  if (nargin == 3)
 %!    m = 1;
 %!  endif
 %!  switch (flag)
 %!    case "dim"
-%!      value = length (A);
+%!      retval = length (A);
 %!    case "real"
-%!      value = isreal (A);
+%!      retval = isreal (A);
 %!    case "notransp"
-%!      value = x; for i = 1:m, value = A \ value;, endfor
+%!      retval = x; for i = 1:m, retval = A \ retval;, endfor
 %!    case "transp"
-%!      value = x; for i = 1:m, value = A' \ value;, endfor
+%!      retval = x; for i = 1:m, retval = A' \ retval;, endfor
 %!  endswitch
 %!endfunction
 
@@ -320,25 +351,25 @@
 %!test
 %! N = 6;
 %! A = hilb (N);
-%! solve = @(flag, x) solve_fun (flag, x, A);
-%! cA = condest (A, solve);
+%! Ainvfcn = @(flag, x) __Ainvfcn__ (flag, x, A);
+%! cA = condest (A, Ainvfcn);
 %! cA_test = norm (inv (A), 1) * norm (A, 1);
 %! assert (cA, cA_test, -2^-6);
 
 %!test
 %! N = 6;
 %! A = hilb (N);
-%! apply = @(flag, x) apply_fun (flag, x, A);
-%! solve = @(flag, x) solve_fun (flag, x, A);
-%! cA = condest (apply, solve);
+%! Afcn = @(flag, x) __Afcn__ (flag, x, A);
+%! Ainvfcn = @(flag, x) __Ainvfcn__ (flag, x, A);
+%! cA = condest (Afcn, Ainvfcn);
 %! cA_test = norm (inv (A), 1) * norm (A, 1);
 %! assert (cA, cA_test, -2^-6);
 
-%!test # parameters for apply and solve functions
+%!test # parameters for apply and Ainvfcn functions
 %! N = 6;
 %! A = hilb (N);
 %! m = 2;
-%! cA = condest (@apply_fun, @solve_fun, [], A, m);
+%! cA = condest (@__Afcn__, @__Ainvfcn__, [], A, m);
 %! cA_test = norm (inv (A^2), 1) * norm (A^2, 1);
 %! assert (cA, cA_test, -2^-6);
 
@@ -351,7 +382,7 @@
 %! assert (cest, Inf);
 %! assert (v, []);
 
-## Test non-orthogonal matrices
+## Test asymmetric matrices
 %!test <*57968>
 %! A = reshape (sqrt (0:15), 4, 4);
 %! cexp = norm (A, 1) * norm (inv (A), 1);
@@ -365,9 +396,9 @@
 %! assert (cest, cexp, -1e-12);
 
 ## Test input validation
-%!error condest ()
-%!error condest (1,2,3,4,5,6,7)
-%!error <A must be square> condest ([1 2])
-%!error <must provide SOLVEFCN when using AFCN> condest (@sin)
-%!error <SOLVEFCN must be a function handle> condest (@sin, 1)
+%!error <Invalid call> condest ()
+%!error <Invalid call> condest (1,2,3,4,5,6,7)
+%!error <A must be square> condest ([1, 2])
+%!error <must provide AINVFCN when using AFCN> condest (@sin)
+%!error <AINVFCN must be a function handle> condest (@sin, 1)
 %!error <argument must be a square matrix or function handle> condest ({1})
--- a/scripts/linear-algebra/cross.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/cross.m	Thu Nov 19 13:08:00 2020 -0800
@@ -50,7 +50,7 @@
 
 function z = cross (x, y, dim)
 
-  if (nargin != 2 && nargin != 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -119,5 +119,8 @@
 %! assert (cross (x, y, 2), r, 2e-8);
 %! assert (cross (x, y, 1), -r, 2e-8);
 
-%!error cross (0,0)
-%!error cross ()
+## Test input validation
+%!error <Invalid call> cross ()
+%!error <Invalid call> cross (1)
+## FIXME: Need tests for other error() conditions and warning() calls.
+%!error <must have at least one dimension with 3 elements> cross (0,0)
--- a/scripts/linear-algebra/duplication_matrix.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/duplication_matrix.m	Thu Nov 19 13:08:00 2020 -0800
@@ -67,7 +67,7 @@
 
 function d = duplication_matrix (n)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -118,7 +118,7 @@
 %! assert (D * vech (B), vec (B), 1e-6);
 %! assert (D * vech (C), vec (C), 1e-6);
 
-%!error duplication_matrix ()
+%!error <Invalid call> duplication_matrix ()
 %!error duplication_matrix (0.5)
 %!error duplication_matrix (-1)
 %!error duplication_matrix (ones (1,4))
--- a/scripts/linear-algebra/expm.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/expm.m	Thu Nov 19 13:08:00 2020 -0800
@@ -81,7 +81,7 @@
 
 function r = expm (A)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -103,7 +103,7 @@
   n = rows (A);
   id = eye (n);
   ## Trace reduction.
-  A(A == -Inf) = -realmax;
+  A(A == -Inf) = -realmax ();
   trshift = trace (A) / n;
   if (trshift > 0)
     A -= trshift * id;
@@ -157,7 +157,6 @@
 %!assert (full (expm (10*eye (3))), expm (full (10*eye (3))), 8*eps)
 
 ## Test input validation
-%!error expm ()
-%!error expm (1, 2)
+%!error <Invalid call> expm ()
 %!error <expm: A must be a square matrix> expm ({1})
 %!error <expm: A must be a square matrix> expm ([1 0;0 1; 2 2])
--- a/scripts/linear-algebra/gls.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/gls.m	Thu Nov 19 13:08:00 2020 -0800
@@ -155,10 +155,9 @@
 %! assert (gls (y,x,o), [3; 2], 50*eps);
 
 ## Test input validation
-%!error gls ()
-%!error gls (1)
-%!error gls (1, 2)
-%!error gls (1, 2, 3, 4)
+%!error <Invalid call> gls ()
+%!error <Invalid call> gls (1)
+%!error <Invalid call> gls (1, 2)
 %!error gls ([true, true], [1, 2], ones (2))
 %!error gls ([1, 2], [true, true], ones (2))
 %!error gls ([1, 2], [1, 2], true (2))
--- a/scripts/linear-algebra/housh.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/housh.m	Thu Nov 19 13:08:00 2020 -0800
@@ -133,5 +133,6 @@
 %! assert (r, d, 2e-8);
 %! assert (z, 0, 2e-8);
 
-%!error housh ([0])
-%!error housh ()
+%!error <Invalid call> housh ()
+%!error <Invalid call> housh (1)
+%!error <Invalid call> housh (1,2)
--- a/scripts/linear-algebra/isbanded.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/isbanded.m	Thu Nov 19 13:08:00 2020 -0800
@@ -69,9 +69,9 @@
 
 %!assert (isbanded ([1, 1],1,1))
 %!assert (isbanded ([1; 1],1,1))
-%!assert (isbanded (eye(10),0,0))
-%!assert (isbanded (eye(10),1,1))
-%!assert (isbanded (i*eye(10),1,1))
+%!assert (isbanded (eye (10),0,0))
+%!assert (isbanded (eye (10),1,1))
+%!assert (isbanded (i*eye (10),1,1))
 %!assert (isbanded (logical (eye (10)),1,1))
 
 %! A = [2 3 0 0 0; 1 2 3 0 0; 0 1 2 3 0; 0 0 1 2 3; 0 0 0 1 2];
@@ -80,10 +80,9 @@
 %! assert (! isbanded (A,1,0));
 
 ## Test input validation
-%!error isbanded ()
-%!error isbanded (1)
-%!error isbanded (1,2)
-%!error isbanded (1,2,3,4)
+%!error <Invalid call> isbanded ()
+%!error <Invalid call> isbanded (1)
+%!error <Invalid call> isbanded (1,2)
 %!error <LOWER and UPPER must be non-negative> isbanded (1, -1, 1)
 %!error <LOWER and UPPER must be non-negative> isbanded (1, 1, -1)
 %!error <LOWER and UPPER must be non-negative> isbanded (1, {1}, 1)
--- a/scripts/linear-algebra/isdefinite.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/isdefinite.m	Thu Nov 19 13:08:00 2020 -0800
@@ -49,7 +49,7 @@
 
 function retval = isdefinite (A, tol)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -103,8 +103,7 @@
 
 %!assert (! isdefinite (magic (3)))
 
-%!error isdefinite ()
-%!error isdefinite (1,2,3)
+%!error <Invalid call> isdefinite ()
 %!error <TOL must be a scalar .= 0> isdefinite (1, {1})
 %!error <TOL must be a scalar .= 0> isdefinite (1, [1 1])
 %!error <TOL must be a scalar .= 0> isdefinite (1, -1)
--- a/scripts/linear-algebra/isdiag.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/isdiag.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function retval = isdiag (A)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -60,5 +60,4 @@
 %!assert (isdiag (diag (1:10)))
 
 ## Test input validation
-%!error isdiag ()
-%!error isdiag (1,2)
+%!error <Invalid call> isdiag ()
--- a/scripts/linear-algebra/ishermitian.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/ishermitian.m	Thu Nov 19 13:08:00 2020 -0800
@@ -52,7 +52,7 @@
 
 function retval = ishermitian (A, skewopt = "nonskew", tol = 0)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -133,8 +133,7 @@
 %! assert (! ishermitian (s));
 
 ## Test input validation
-%!error ishermitian ()
-%!error ishermitian (1,2,3,4)
+%!error <Invalid call> ishermitian ()
 %!error <second argument must be> ishermitian (1, {"skew"})
 %!error <SKEWOPT must be 'skew' or 'nonskew'> ishermitian (1, "foobar")
 %!error <SKEWOPT must be 'skew' or 'nonskew'> ishermitian (1, "foobar")
--- a/scripts/linear-algebra/issymmetric.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/issymmetric.m	Thu Nov 19 13:08:00 2020 -0800
@@ -51,7 +51,7 @@
 
 function retval = issymmetric (A, skewopt = "nonskew", tol = 0)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -66,9 +66,8 @@
   endif
 
   ## Validate inputs
-  retval = (isnumeric (A) || islogical (A)) && issquare (A);
-  if (! retval)
-    return;
+  if (! (isnumeric (A) || islogical (A) || ischar (A)))
+    error ("issymmetric: A must be a numeric, logical, or character matrix");
   endif
 
   if (! (strcmp (skewopt, "skew") || strcmp (skewopt, "nonskew")))
@@ -79,13 +78,18 @@
     error ("issymmetric: TOL must be a scalar >= 0");
   endif
 
+  if (! issquare (A))
+    retval = false;
+    return;
+  endif
+
   ## Calculate symmetry
   if (strcmp (skewopt, "nonskew"))
     if (tol == 0)
       ## check for exact symmetry
       retval = full (! any ((A != A.')(:)));
     else
-      if (islogical (A))
+      if (! isnumeric (A))
         ## Hack to allow norm to work.  Choose single to minimize memory.
         A = single (A);
       endif
@@ -97,7 +101,7 @@
     if (tol == 0)
       retval = full (! any ((A != -A.')(:)));
     else
-      if (islogical (A))
+      if (! isnumeric (A))
         ## Hack to allow norm to work.  Choose single to minimize memory.
         A = single (A);
       endif
@@ -116,26 +120,21 @@
 %!assert (issymmetric ([1, 2.1; 2, 1.1], 0.2))
 %!assert (issymmetric ([1, 2i; 2i, 1]))
 %!assert (issymmetric (speye (100)), true)  # Return full logical value.
-%!assert (issymmetric (logical (eye (2))))
-%!assert (! issymmetric (logical ([1 1; 0 1])))
-%!assert (issymmetric (logical ([1 1; 0 1]), 0.5))
+%!assert (! issymmetric ([0, 2; -2, 0], "nonskew"))
 %!assert (issymmetric ([0, 2; -2, 0], "skew"))
 %!assert (! issymmetric ([0, 2; -2, eps], "skew"))
 %!assert (issymmetric ([0, 2; -2, eps], "skew", eps))
-
-%!assert (! (issymmetric ("test")))
-%!assert (! (issymmetric ("t")))
-%!assert (! (issymmetric (["te"; "et"])))
-%!assert (! issymmetric ({1}))
-%!test
-%! s.a = 1;
-%! assert (! issymmetric (s));
+%!assert (issymmetric (logical (eye (2))))
+%!assert (! issymmetric (logical ([1 1; 0 1])))
+%!assert (issymmetric (logical ([1 1; 0 1]), 0.5))
+%!assert (! issymmetric ("test"))
+%!assert (issymmetric ("t"))
+%!assert (issymmetric (["te"; "et"]))
 
 ## Test input validation
-%!error issymmetric ()
-%!error issymmetric (1,2,3,4)
+%!error <Invalid call> issymmetric ()
 %!error <second argument must be> issymmetric (1, {"skew"})
-%!error <SKEWOPT must be 'skew' or 'nonskew'> issymmetric (1, "foobar")
+%!error <A must be a numeric,.* matrix> issymmetric ({1})
 %!error <SKEWOPT must be 'skew' or 'nonskew'> issymmetric (1, "foobar")
 %!error <TOL must be a scalar .= 0> issymmetric (1, "skew", {1})
 %!error <TOL must be a scalar .= 0> issymmetric (1, "skew", [1 1])
--- a/scripts/linear-algebra/istril.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/istril.m	Thu Nov 19 13:08:00 2020 -0800
@@ -34,7 +34,7 @@
 
 function retval = istril (A)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -61,5 +61,4 @@
 %!assert (! istril (randn (10)))
 
 ## Test input validation
-%!error istril ()
-%!error istril (1,2)
+%!error <Invalid call> istril ()
--- a/scripts/linear-algebra/istriu.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/istriu.m	Thu Nov 19 13:08:00 2020 -0800
@@ -34,7 +34,7 @@
 
 function retval = istriu (A)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -61,5 +61,4 @@
 %!assert (! istriu (randn (10)))
 
 ## Test input validation
-%!error istriu ()
-%!error istriu (1,2)
+%!error <Invalid call> istriu ()
--- a/scripts/linear-algebra/krylov.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/krylov.m	Thu Nov 19 13:08:00 2020 -0800
@@ -71,7 +71,7 @@
     defeps = 1e-12;
   endif
 
-  if (nargin < 3 || nargin > 5)
+  if (nargin < 3)
     print_usage ();
   elseif (nargin < 5)
     ## Default permutation flag.
@@ -187,7 +187,7 @@
     if ((columns (V) > na) && (length (alpha) == na))
       ## Trim to size.
       V = V(:,1:na);
-    elseif (columns(V) > na)
+    elseif (columns (V) > na)
       krylov_V = V;
       krylov_na = na;
       krylov_length_alpha = length (alpha);
@@ -198,7 +198,7 @@
       ## Construct next Q and multiply.
       Q = zeros (size (V));
       for kk = 1:columns (Q)
-        Q(pivot_vec(nu-columns(Q)+kk),kk) = 1;
+        Q(pivot_vec(nu-columns (Q)+kk),kk) = 1;
       endfor
 
       ## Apply Householder reflections.
@@ -218,7 +218,7 @@
       hv = U(:,i);
       av = alpha(i);
       V -= av*hv*(hv'*V);
-      H(i,nu-columns(V)+(1:columns(V))) = V(pivot_vec(i),:);
+      H(i,nu-columns (V)+(1:columns (V))) = V(pivot_vec(i),:);
     endfor
 
   endwhile
--- a/scripts/linear-algebra/linsolve.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/linsolve.m	Thu Nov 19 13:08:00 2020 -0800
@@ -77,7 +77,7 @@
 
 function [x, R] = linsolve (A, b, opts)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -141,8 +141,8 @@
 %! opts.TRANSA = true;
 %! assert (linsolve (A, b, opts), A' \ b);
 
-%!error linsolve ()
-%!error linsolve (1)
+%!error <Invalid call> linsolve ()
+%!error <Invalid call> linsolve (1)
 %!error linsolve (1,2,3)
 %!error <A and B must be numeric> linsolve ({1},2)
 %!error <A and B must be numeric> linsolve (1,{2})
--- a/scripts/linear-algebra/logm.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/logm.m	Thu Nov 19 13:08:00 2020 -0800
@@ -52,7 +52,7 @@
 
 function [s, iters] = logm (A, opt_iters = 100)
 
-  if (nargin == 0 || nargin > 2)
+  if (nargin == 0)
     print_usage ();
   endif
 
@@ -95,7 +95,7 @@
       j(2) = find (tau / 2 <= theta, 1);
       if (j(1) - j(2) <= 1 || p == 2)
         m = j(1);
-        break
+        break;
       endif
     endif
     k += 1;
@@ -182,6 +182,5 @@
 %!assert (logm (expm ([0 1i; -1i 0])), [0 1i; -1i 0], 10 * eps)
 
 ## Test input validation
-%!error logm ()
-%!error logm (1, 2, 3)
+%!error <Invalid call> logm ()
 %!error <logm: A must be a square matrix> logm ([1 0;0 1; 2 2])
--- a/scripts/linear-algebra/lscov.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/lscov.m	Thu Nov 19 13:08:00 2020 -0800
@@ -60,7 +60,7 @@
 
 function [x, stdx, mse, S] = lscov (A, b, V = [], alg)
 
-  if (nargin < 2 || nargin > 4)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -167,9 +167,9 @@
 %! y = Z(:,1); X = [ones(rows(Z),1), Z(:,2:end)];
 %! alpha = 0.05;
 %! [b, stdb, mse] = lscov (X, y);
-%! assert(b, V(:,1), 3e-6);
-%! assert(stdb, V(:,2), -1.e-5);
-%! assert(sqrt (mse), rsd, -1E-6);
+%! assert (b, V(:,1), 3e-6);
+%! assert (stdb, V(:,2), -1.e-5);
+%! assert (sqrt (mse), rsd, -1E-6);
 
 %!test
 %! ## Adapted from example in Matlab documentation
@@ -178,41 +178,41 @@
 %! X = [ones(size(x1)) x1 x2];
 %! y = [.17 .26 .28 .23 .27 .34]';
 %! [b, se_b, mse, S] = lscov(X, y);
-%! assert(b, [0.1203 0.3284 -0.1312]', 1E-4);
-%! assert(se_b, [0.0643 0.2267 0.1488]', 1E-4);
-%! assert(mse, 0.0015, 1E-4);
-%! assert(S, [0.0041 -0.0130 0.0075; -0.0130 0.0514 -0.0328; 0.0075 -0.0328 0.0221], 1E-4);
+%! assert (b, [0.1203 0.3284 -0.1312]', 1E-4);
+%! assert (se_b, [0.0643 0.2267 0.1488]', 1E-4);
+%! assert (mse, 0.0015, 1E-4);
+%! assert (S, [0.0041 -0.0130 0.0075; -0.0130 0.0514 -0.0328; 0.0075 -0.0328 0.0221], 1E-4);
 %! w = [1 1 1 1 1 .1]';
 %! [bw, sew_b, msew] = lscov (X, y, w);
-%! assert(bw, [0.1046 0.4614 -0.2621]', 1E-4);
-%! assert(sew_b, [0.0309 0.1152 0.0814]', 1E-4);
-%! assert(msew, 3.4741e-004, -1E-4);
-%! V = .2*ones(length(x1)) + .8*diag(ones(size(x1)));
+%! assert (bw, [0.1046 0.4614 -0.2621]', 1E-4);
+%! assert (sew_b, [0.0309 0.1152 0.0814]', 1E-4);
+%! assert (msew, 3.4741e-004, -1E-4);
+%! V = .2*ones (length (x1)) + .8*diag (ones (size (x1)));
 %! [bg, sew_b, mseg] = lscov (X, y, V);
-%! assert(bg, [0.1203 0.3284 -0.1312]', 1E-4);
-%! assert(sew_b, [0.0672 0.2267 0.1488]', 1E-4);
-%! assert(mseg, 0.0019, 1E-4);
+%! assert (bg, [0.1203 0.3284 -0.1312]', 1E-4);
+%! assert (sew_b, [0.0672 0.2267 0.1488]', 1E-4);
+%! assert (mseg, 0.0019, 1E-4);
 %! y2 = [y 2*y];
 %! [b2, se_b2, mse2, S2] = lscov (X, y2);
-%! assert(b2, [b 2*b], 2*eps);
-%! assert(se_b2, [se_b 2*se_b], 2*eps);
-%! assert(mse2, [mse 4*mse], eps);
-%! assert(S2(:, :, 1), S, eps);
-%! assert(S2(:, :, 2), 4*S, eps);
+%! assert (b2, [b 2*b], 2*eps);
+%! assert (se_b2, [se_b 2*se_b], 2*eps);
+%! assert (mse2, [mse 4*mse], eps);
+%! assert (S2(:, :, 1), S, eps);
+%! assert (S2(:, :, 2), 4*S, eps);
 
 %!test
 %! ## Artificial example with positive semi-definite weight matrix
 %! x = (0:0.2:2)';
-%! y = round(100*sin(x) + 200*cos(x));
+%! y = round (100*sin (x) + 200*cos (x));
 %! X = [ones(size(x)) sin(x) cos(x)];
-%! V = eye(numel(x));
+%! V = eye (numel (x));
 %! V(end, end-1) = V(end-1, end) = 1;
 %! [b, seb, mseb, S] = lscov (X, y, V);
-%! assert(b, [0 100 200]', 0.2);
+%! assert (b, [0 100 200]', 0.2);
 
-%!error lscov ()
-%!error lscov (1)
-%!error lscov (1,2,3,4,5)
+## Test input validation
+%!error <Invalid call> lscov ()
+%!error <Invalid call> lscov (1)
 %!error <A and B must have the same number of rows> lscov (ones (2,2),1)
 %!warning <algorithm selection input ALG is not yet implemented>
 %! lscov (1,1, [], "chol");
--- a/scripts/linear-algebra/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/bandwidth.m \
   %reldir%/commutation_matrix.m \
   %reldir%/cond.m \
--- a/scripts/linear-algebra/normest.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/normest.m	Thu Nov 19 13:08:00 2020 -0800
@@ -43,7 +43,7 @@
 
 function [nest, iter] = normest (A, tol = 1e-6)
 
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -96,8 +96,7 @@
 %! assert (normest (A), norm (A), 1e-6);
 
 ## Test input validation
-%!error normest ()
-%!error normest (1, 2, 3)
+%!error <Invalid call> normest ()
 %!error <A must be a numeric .* matrix> normest ([true true])
 %!error <A must be .* 2-D matrix> normest (ones (3,3,3))
 %!error <TOL must be a real scalar> normest (1, [1, 2])
--- a/scripts/linear-algebra/normest1.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/normest1.m	Thu Nov 19 13:08:00 2020 -0800
@@ -379,7 +379,7 @@
 %! assert (iscolumn (it));
 
 ## Test input validation
-%!error normest1 ()
+%!error <Invalid call> normest1 ()
 %!error <A must be a square matrix or a function handle> normest1 ({1})
 %!error <A must be a square matrix> normest1 ([1 2])
 %!error <X0 must have 2 columns> normest1 (magic (5), :, [1])
--- a/scripts/linear-algebra/null.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/null.m	Thu Nov 19 13:08:00 2020 -0800
@@ -40,7 +40,7 @@
 
 function retval = null (A, tol)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   elseif (nargin == 2 && strcmp (tol, "r"))
     error ("null: option for rational not yet implemented");
@@ -88,7 +88,7 @@
 %!test
 %! A = [1 0; 0 1];
 %! assert (null (A), zeros (2,0));
-%! assert (null (single (A)), zeros (2, 0, "single"))
+%! assert (null (single (A)), zeros (2, 0, "single"));
 
 %!test
 %! A = [1 0; 1 0];
@@ -96,8 +96,8 @@
 
 %!test
 %! A = [1 1; 0 0];
-%! assert (null (A), [-1/sqrt(2) 1/sqrt(2)]', eps)
-%! assert (null (single (A)), single ([-1/sqrt(2) 1/sqrt(2)]'), eps)
+%! assert (null (A), [-1/sqrt(2) 1/sqrt(2)]', eps);
+%! assert (null (single (A)), single ([-1/sqrt(2) 1/sqrt(2)]'), eps);
 
 %!test
 %! tol = 1e-4;
--- a/scripts/linear-algebra/ols.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/ols.m	Thu Nov 19 13:08:00 2020 -0800
@@ -183,9 +183,8 @@
 %! assert (b, [1.4, 2], 2*eps);
 
 ## Test input validation
-%!error ols ()
-%!error ols (1)
-%!error ols (1, 2, 3)
+%!error <Invalid call> ols ()
+%!error <Invalid call> ols (1)
 %!error ols ([true, true], [1, 2])
 %!error ols ([1, 2], [true, true])
 %!error ols (ones (2,2,2), ones (2,2))
--- a/scripts/linear-algebra/ordeig.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/ordeig.m	Thu Nov 19 13:08:00 2020 -0800
@@ -35,17 +35,17 @@
 ## appearance of the matrix @code{@var{A}-@var{lambda}*@var{B}}.  The pair
 ## @var{A}, @var{B} is usually the result of a QZ decomposition.
 ##
-## @seealso{ordschur, eig, schur, qz}
+## @seealso{ordschur, ordqz, eig, schur, qz}
 ## @end deftypefn
 
 function lambda = ordeig (A, B)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
   if (! isnumeric (A) || ! issquare (A))
-    error ("ordeig: A must be a square matrix")
+    error ("ordeig: A must be a square matrix");
   endif
 
   n = length (A);
@@ -53,7 +53,7 @@
   if (nargin == 1)
     B = eye (n);
     if (isreal (A))
-      if (! isquasitri (A))
+      if (! is_quasitri (A))
         error ("ordeig: A must be quasi-triangular (i.e., upper block triangular with 1x1 or 2x2 blocks on the diagonal)");
       endif
     else
@@ -68,7 +68,7 @@
       error ("ordeig: A and B must be the same size");
     endif
     if (isreal (A) && isreal (B))
-      if (! isquasitri (A) || ! isquasitri (B))
+      if (! is_quasitri (A) || ! is_quasitri (B))
         error ("ordeig: A and B must be quasi-triangular (i.e., upper block triangular with 1x1 or 2x2 blocks on the diagonal)");
       endif
     else
@@ -106,7 +106,7 @@
 endfunction
 
 ## Check whether a matrix is quasi-triangular
-function retval = isquasitri (A)
+function retval = is_quasitri (A)
   if (length (A) <= 2)
     retval = true;
   else
@@ -140,8 +140,7 @@
 %! assert (lambda, 3);
 
 ## Test input validation
-%!error ordeig ()
-%!error ordeig (1,2,3)
+%!error <Invalid call> ordeig ()
 %!error <A must be a square matrix> ordeig ('a')
 %!error <A must be a square matrix> ordeig ([1, 2, 3])
 %!error <A must be quasi-triangular> ordeig (magic (3))
--- a/scripts/linear-algebra/orth.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/orth.m	Thu Nov 19 13:08:00 2020 -0800
@@ -40,45 +40,41 @@
 
 function retval = orth (A, tol)
 
-  if (nargin == 1 || nargin == 2)
-
-    if (isempty (A))
-      retval = [];
-      return;
-    endif
-
-    [U, S, V] = svd (A);
+  if (nargin < 1)
+    print_usage ();
+  endif
 
-    [rows, cols] = size (A);
-
-    [S_nr, S_nc] = size (S);
+  if (isempty (A))
+    retval = [];
+    return;
+  endif
 
-    if (S_nr == 1 || S_nc == 1)
-      s = S(1);
-    else
-      s = diag (S);
-    endif
+  [U, S, V] = svd (A);
+
+  [rows, cols] = size (A);
+
+  [S_nr, S_nc] = size (S);
 
-    if (nargin == 1)
-      if (isa (A, "single"))
-        tol = max (size (A)) * s (1) * eps ("single");
-      else
-        tol = max (size (A)) * s (1) * eps;
-      endif
-    endif
-
-    rank = sum (s > tol);
+  if (S_nr == 1 || S_nc == 1)
+    s = S(1);
+  else
+    s = diag (S);
+  endif
 
-    if (rank > 0)
-      retval = -U(:, 1:rank);
+  if (nargin == 1)
+    if (isa (A, "single"))
+      tol = max (size (A)) * s (1) * eps ("single");
     else
-      retval = zeros (rows, 0);
+      tol = max (size (A)) * s (1) * eps;
     endif
+  endif
 
-  else
+  rank = sum (s > tol);
 
-    print_usage ();
-
+  if (rank > 0)
+    retval = -U(:, 1:rank);
+  else
+    retval = zeros (rows, 0);
   endif
 
 endfunction
--- a/scripts/linear-algebra/planerot.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/planerot.m	Thu Nov 19 13:08:00 2020 -0800
@@ -65,7 +65,7 @@
 
 function [G, y] = planerot (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   elseif (! (isvector (x) && numel (x) == 2))
     error ("planerot: X must be a 2-element vector");
@@ -83,7 +83,7 @@
 %! assert (g, [x(1) x(2); -x(2) x(1)] / sqrt (x(1)^2 + x(2)^2), 2e-8);
 %! assert (y(2), 0, 2e-8);
 
-%!error planerot ()
-%!error planerot (1,2)
+## Test input validation
+%!error <Invalid call> planerot ()
 %!error <X must be a 2-element vector> planerot (ones (2,2))
 %!error <X must be a 2-element vector> planerot ([0 0 0])
--- a/scripts/linear-algebra/qzhess.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/qzhess.m	Thu Nov 19 13:08:00 2020 -0800
@@ -153,5 +153,6 @@
 %! assert (q * b * z, bb, 2e-8);
 %! assert (bb .* mask, zeros (5), 2e-8);
 
-%!error qzhess ([0])
-%!error qzhess ()
+## Test input validation
+%!error <Invalid call> qzhess ()
+%!error <Invalid call> qzhess (1)
--- a/scripts/linear-algebra/rank.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/rank.m	Thu Nov 19 13:08:00 2020 -0800
@@ -81,6 +81,10 @@
 
 function retval = rank (A, tol)
 
+  if (nargin < 1)
+    print_usage ();
+  endif
+
   if (nargin == 1)
     sigma = svd (A);
     if (isempty (sigma))
@@ -92,11 +96,9 @@
         tolerance = max (size (A)) * sigma (1) * eps;
       endif
     endif
-  elseif (nargin == 2)
+  else
     sigma = svd (A);
     tolerance = tol;
-  else
-    print_usage ();
   endif
 
   retval = sum (sigma > tolerance);
--- a/scripts/linear-algebra/rref.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/rref.m	Thu Nov 19 13:08:00 2020 -0800
@@ -40,7 +40,7 @@
 
 function [A, k] = rref (A, tol)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -111,7 +111,7 @@
 %! a = [1 3; 4 5; 7 9];
 %! [r k] = rref (a);
 %! assert (rank (a), rank (r), 2e-8);
-%! assert (r, eye(3)(:,1:2), 2e-8);
+%! assert (r, eye (3)(:,1:2), 2e-8);
 %! assert (k, [1 2], 2e-8);
 
 %!test
@@ -130,4 +130,5 @@
 %! [r k] = rref (a, tol);
 %! assert (rank (a, tol), rank (r, tol), 2e-8);
 
-%!error rref ()
+## Test input validation
+%!error <Invalid call> rref ()
--- a/scripts/linear-algebra/trace.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/trace.m	Thu Nov 19 13:08:00 2020 -0800
@@ -34,7 +34,7 @@
 
 function y = trace (A)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -58,6 +58,5 @@
 %!assert (trace (rand (1,0)), 0)
 %!assert (trace ([3:10]), 3)
 
-%!error trace ()
-%!error trace (1, 2)
+%!error <Invalid call> trace ()
 %!error <only valid on 2-D objects> trace (reshape (1:9,[1,3,3]))
--- a/scripts/linear-algebra/vech.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/vech.m	Thu Nov 19 13:08:00 2020 -0800
@@ -41,7 +41,7 @@
 
 function v = vech (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -58,5 +58,4 @@
 
 %!assert (vech ([1, 2, 3; 4, 5, 6; 7, 8, 9]), [1; 4; 7; 5; 8; 9])
 
-%!error vech ()
-%!error vech (1, 2)
+%!error <Invalid call> vech ()
--- a/scripts/linear-algebra/vecnorm.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/linear-algebra/vecnorm.m	Thu Nov 19 13:08:00 2020 -0800
@@ -51,7 +51,7 @@
 
 function n = vecnorm (A, p = 2, dim)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -111,8 +111,7 @@
 %! assert (vecnorm (A), ret, 1e-4);
 
 ## Test input validation
-%!error vecnorm ()
-%!error vecnorm (1,2,3,4)
+%!error <Invalid call> vecnorm ()
 %!error <P must be positive real scalar> vecnorm (1, [1 2])
 %!error <P must be positive real scalar> vecnorm (1, i)
 %!error <P must be positive real scalar> vecnorm (1, -1)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/miscellaneous/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/miscellaneous/bunzip2.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/bunzip2.m	Thu Nov 19 13:08:00 2020 -0800
@@ -38,7 +38,7 @@
 
 function filelist = bunzip2 (bzfile, dir = [])
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/cast.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/cast.m	Thu Nov 19 13:08:00 2020 -0800
@@ -108,8 +108,7 @@
 %!assert (cast ([-2.5 1.1 2.5], "uint64"), uint64 ([0 1 3]))
 
 ## Test input validation
-%!error cast ()
-%!error cast (1)
-%!error cast (1,2,3)
+%!error <Invalid call> cast ()
+%!error <Invalid call> cast (1)
 %!error <TYPE 'foobar' is not a built-in type> cast (1, "foobar")
 %!error <TYPE must be a string> cast (1, {"foobar"})
--- a/scripts/miscellaneous/citation.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/citation.m	Thu Nov 19 13:08:00 2020 -0800
@@ -47,16 +47,13 @@
 
 function citation (package = "octave")
 
-  if (nargin > 1)
-    print_usage ();
-  else
-    display_info_file ("citation", package, "CITATION");
-  endif
+  ## function takes care of validating PACKAGE input
+  display_info_file ("citation", package, "CITATION");
 
 endfunction
 
 
 ## Test input validation
-%!error citation (1, 2)
 %!error <citation: PACKAGE must be a string> citation (1)
-%!error <citation: package .* is not installed> citation ("__NOT_A_VALID_PKG_NAME__")
+%!error <citation: package .* is not installed>
+%! citation ("__NOT_A_VALID_PKG_NAME__");
--- a/scripts/miscellaneous/compare_versions.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/compare_versions.m	Thu Nov 19 13:08:00 2020 -0800
@@ -223,10 +223,9 @@
 %!assert (compare_versions ("0.1", "0.1", "~="), false)
 
 ## Test input validation
-%!error compare_versions ()
-%!error compare_versions (1)
-%!error compare_versions (1,2)
-%!error compare_versions (1,2,3,4)
+%!error <Invalid call> compare_versions ()
+%!error <Invalid call> compare_versions (1)
+%!error <Invalid call> compare_versions (1,2)
 %!error <V1 and V2 must be strings> compare_versions (0.1, "0.1", "==")
 %!error <V1 and V2 must be strings> compare_versions ("0.1", 0.1, "==")
 %!error <V1 and V2 must be a single row> compare_versions (["0";".";"1"], "0.1", "==")
--- a/scripts/miscellaneous/computer.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/computer.m	Thu Nov 19 13:08:00 2020 -0800
@@ -25,9 +25,9 @@
 
 ## -*- texinfo -*-
 ## @deftypefn  {} {} computer ()
-## @deftypefnx {} {@var{c} =} computer ()
-## @deftypefnx {} {[@var{c}, @var{maxsize}] =} computer ()
-## @deftypefnx {} {[@var{c}, @var{maxsize}, @var{endian}] =} computer ()
+## @deftypefnx {} {@var{comp} =} computer ()
+## @deftypefnx {} {[@var{comp}, @var{maxsize}] =} computer ()
+## @deftypefnx {} {[@var{comp}, @var{maxsize}, @var{endian}] =} computer ()
 ## @deftypefnx {} {@var{arch} =} computer ("arch")
 ## Print or return a string of the form @var{cpu}-@var{vendor}-@var{os} that
 ## identifies the type of computer that Octave is running on.
@@ -55,36 +55,57 @@
 ##
 ## If the argument @qcode{"arch"} is specified, return a string indicating the
 ## architecture of the computer on which Octave is running.
+##
+## Results may be different if Octave was invoked with the --traditional
+## option.
 ## @seealso{isunix, ismac, ispc}
 ## @end deftypefn
 
-function [c, maxsize, endian] = computer (a)
+function [comp, maxsize, endian] = computer (arch)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1 && ! strcmpi (a, "arch"))
+  if (nargin == 1 && ! strcmpi (arch, "arch"))
     error ('computer: "arch" is only valid argument');
   endif
 
+  canonical_host_type = __octave_config_info__ ("canonical_host_type");
+  traditional = __traditional__ ();
+  enable_64 = __octave_config_info__ ("ENABLE_64");
+  host_parts = ostrsplit (canonical_host_type, "-");
+
   if (nargin == 0)
-    msg = __octave_config_info__ ("canonical_host_type");
 
-    if (strcmp (msg, "unknown"))
-      msg = "Hi Dave, I'm a HAL-9000";
+    host = "";
+    if (traditional && enable_64)
+      if (ismac ())
+        host = "MACI64";
+      elseif (ispc ())
+        host = "PCWIN64";
+      elseif (strcmp ([host_parts{3} "-" host_parts{1}], "linux-x86_64"))
+        host = "GLNXA64";
+      endif
+    endif
+    if (isempty (host))
+      host = canonical_host_type;
+    elseif (strcmp (host, "unknown"))
+      host = "Hi Dave, I'm a HAL-9000";
     endif
 
     if (nargout == 0)
-      disp (msg);
+      disp (host);
     else
-      c = msg;
-      if (isargout (2))
-        if (__octave_config_info__ ("ENABLE_64"))
-          maxsize = 2^63-1;
+      comp = host;
+      if (nargout > 1)
+        if (enable_64)
+          if (traditional)
+            maxsize = 2^48-1;
+          else
+            maxsize = 2^63-1;
+          endif
         else
           maxsize = 2^31-1;
         endif
       endif
-      if (isargout (3))
+      if (nargout > 2)
         if (__octave_config_info__ ("words_big_endian"))
           endian = "B";
         elseif (__octave_config_info__ ("words_little_endian"))
@@ -94,13 +115,25 @@
         endif
       endif
     endif
+
   else
-    ## "arch" argument asked for
-    tmp = ostrsplit (__octave_config_info__ ("canonical_host_type"), "-");
-    if (numel (tmp) == 4)
-      c = sprintf ("%s-%s-%s", tmp{4}, tmp{3}, tmp{1});
-    else
-      c = sprintf ("%s-%s", tmp{3}, tmp{1});
+
+    ## "arch" case.
+    comp = "";
+    if (traditional && enable_64)
+      if (ismac ())
+        comp = "maci64";
+      elseif (ispc ())
+        comp = "win64";
+      elseif (strcmp ([host_parts{3} "-" host_parts{1}], "linux-x86_64"))
+        comp = "glnxa64";
+      endif
+    endif
+    if (isempty (comp))
+      comp = [host_parts{3} "-" host_parts{1}];
+      if (numel (host_parts) == 4)
+        comp = [host_parts{4} "-" comp];
+      endif
     endif
 
   endif
--- a/scripts/miscellaneous/copyfile.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/copyfile.m	Thu Nov 19 13:08:00 2020 -0800
@@ -48,12 +48,12 @@
 
 function [status, msg, msgid] = copyfile (f1, f2, force)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
   max_cmd_line = 1024;
-  status = true;
+  sts = 1;
   msg = "";
   msgid = "";
 
@@ -87,13 +87,27 @@
   ## If f1 has more than 1 element then f2 must be a directory
   isdir = isfolder (f2);
   if (numel (f1) > 1 && ! isdir)
-    error ("copyfile: when copying multiple files, F2 must be a directory");
+    if (nargout == 0)
+      error ("copyfile: when copying multiple files, F2 must be a directory");
+    else
+      status = 0;
+      msg = "when copying multiple files, F2 must be a directory";
+      msgid = "copyfile";
+      return;
+    endif
   endif
 
   ## Protect the filename(s).
   f1 = glob (f1);
   if (isempty (f1))
-    error ("copyfile: no files to move");
+    if (nargout == 0)
+      error ("copyfile: no files to move");
+    else
+      status = 0;
+      msg = "no files to move";
+      msgid = "copyfile";
+      return;
+    endif
   endif
   p1 = sprintf ('"%s" ', f1{:});
   p2 = tilde_expand (f2);
@@ -118,7 +132,7 @@
       ## Copy the files.
       [err, msg] = system (sprintf ('%s %s"%s"', cmd, p1, p2));
       if (err != 0)
-        status = false;
+        sts = 0;
         msgid = "copyfile";
         break;
       endif
@@ -133,20 +147,28 @@
     ## Copy the files.
     [err, msg] = system (sprintf ('%s %s"%s"', cmd, p1, p2));
     if (err != 0)
-      status = false;
+      sts = 0;
       msgid = "copyfile";
     endif
   endif
 
+  if (nargout == 0)
+    if (sts == 0)
+      error ("copyfile: operation failed: %s", msg);
+    endif
+  else
+    status = sts;
+  endif
+
 endfunction
 
 
 %!test
 %! unwind_protect
-%!   f1 = tempname;
+%!   f1 = tempname ();
 %!   tmp_var = pi;
 %!   save (f1, "tmp_var");
-%!   f2 = tempname;
+%!   f2 = tempname ();
 %!   assert (copyfile (f1, f2));
 %!   assert (exist (f2, "file"));
 %!   fid = fopen (f1, "rb");
@@ -166,9 +188,9 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error copyfile ()
-%!error copyfile (1)
-%!error copyfile (1,2,3,4)
+%!error <Invalid call> copyfile ()
+%!error <Invalid call> copyfile (1)
 %!error <F1 must be a string> copyfile (1, "foobar")
 %!error <F2 must be a string> copyfile ("foobar", 1)
 %!error <F2 must be a directory> copyfile ({"a", "b"}, "%_NOT_A_DIR_%")
+%!error <no files to move> copyfile ("%_NOT_A_FILENAME1_%", "%_NOT_A_FILENAME2_%")
--- a/scripts/miscellaneous/delete.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/delete.m	Thu Nov 19 13:08:00 2020 -0800
@@ -49,13 +49,15 @@
     for arg = varargin
       files = glob (arg{1});
       if (isempty (files))
-        warning ("delete: no such file: %s", arg{1});
+        warning ("Octave:delete:no-such-file", ...
+                 "delete: no such file: %s", arg{1});
       endif
       for i = 1:length (files)
         file = files{i};
         [err, msg] = unlink (file);
         if (err)
-          warning ("delete: %s: %s", file, msg);
+          warning ("Octave:delete:unlink-error", ...
+                   "delete: %s: %s", file, msg);
         endif
       endfor
     endfor
@@ -65,7 +67,8 @@
     __go_delete__ (varargin{1});
 
   else
-    error ("delete: first argument must be a filename or graphics handle");
+    error ("Octave:delete:unsupported-object", ...
+           "delete: first argument must be a filename or graphics handle");
   endif
 
 endfunction
@@ -73,14 +76,14 @@
 
 %!test
 %! unwind_protect
-%!   file = tempname;
+%!   file = tempname ();
 %!   tmp_var = pi;
 %!   save (file, "tmp_var");
 %!   assert (exist (file, "file"));
 %!   delete (file);
 %!   assert (! exist (file, "file"));
 %! unwind_protect_cleanup
-%!   unlink (file);
+%!   sts = unlink (file);
 %! end_unwind_protect
 
 %!test
@@ -95,5 +98,5 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error delete ()
+%!error <Invalid call> delete ()
 %!error <first argument must be a filename> delete (struct ())
--- a/scripts/miscellaneous/dir.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/dir.m	Thu Nov 19 13:08:00 2020 -0800
@@ -75,13 +75,7 @@
 ## FIXME: This is quite slow for large directories.
 ##        Perhaps it should be converted to C++?
 
-function retval = dir (directory)
-
-  if (nargin == 0)
-    directory = ".";
-  elseif (nargin > 1)
-    print_usage ();
-  endif
+function retval = dir (directory = ".")
 
   if (! ischar (directory))
     error ("dir: DIRECTORY argument must be a string");
@@ -97,9 +91,11 @@
   if (strcmp (directory, "."))
     flst = {"."};
     nf = 1;
+    dir_has_wildcard = false;
   else
     flst = __wglob__ (directory);
     nf = numel (flst);
+    dir_has_wildcard = any (directory == '*');  # See Bug #58976.
   endif
 
   ## Determine the file list for the case where a single directory is specified.
@@ -109,7 +105,7 @@
     if (err < 0)
       warning ("dir: 'stat (%s)' failed: %s", fn, msg);
       nf = 0;
-    elseif (S_ISDIR (st.mode))
+    elseif (S_ISDIR (st.mode) && ! dir_has_wildcard)
       flst = readdir (flst{1});
       nf = numel (flst);
       flst = strcat ([fn filesep], flst);
@@ -224,7 +220,40 @@
 %!   chdir (orig_dir);
 %!   confirm_recursive_rmdir (false, "local");
 %!   if (exist (tmp_dir))
-%!     rmdir (tmp_dir, "s");
+%!     sts = rmdir (tmp_dir, "s");
+%!   endif
+%! end_unwind_protect
+
+%!test <*58976>
+%! orig_dir = pwd ();
+%! tmp_dir = tempname ();
+%! unwind_protect
+%!   assert (mkdir (tmp_dir));
+%!   assert (mkdir (fullfile (tmp_dir, "dir1")));
+%!   assert (mkdir (fullfile (tmp_dir, "dir2")));
+%!   chdir (fullfile (tmp_dir, "dir1"));
+%!   fclose (fopen ("f1", "w"));
+%!   chdir (tmp_dir);
+%!
+%!   ## Wildcard with multiple matches lists directories
+%!   list = dir (fullfile (tmp_dir, "dir*"));
+%!   assert (numel (list) == 2);
+%!   assert ({list.name}, {"dir1", "dir2"});
+%!
+%!   ## Wildcard with single match lists directories
+%!   assert (rmdir (fullfile (tmp_dir, "dir2")));
+%!   list = dir (fullfile (tmp_dir, "dir*"));
+%!   assert (numel (list) == 1);
+%!   assert ({list.name}, {"dir1"});
+%!
+%!   ## No wildcard returns listing of directory contents
+%!   list = dir (fullfile (tmp_dir, "dir1"));
+%!   assert (any (strcmp ({list.name}, "f1")));
+%! unwind_protect_cleanup
+%!   chdir (orig_dir);
+%!   confirm_recursive_rmdir (false, "local");
+%!   if (exist (tmp_dir))
+%!     sts = rmdir (tmp_dir, "s");
 %!   endif
 %! end_unwind_protect
 
@@ -238,7 +267,7 @@
 %!   assert (list(1).folder, canonicalize_file_name (tmp_dir));
 %! unwind_protect_cleanup
 %!   if (exist (tmp_dir))
-%!     rmdir (tmp_dir);
+%!     sts = rmdir (tmp_dir);
 %!   endif
 %! end_unwind_protect
 
--- a/scripts/miscellaneous/dos.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/dos.m	Thu Nov 19 13:08:00 2020 -0800
@@ -41,7 +41,7 @@
 
 function [status, text] = dos (command, echo_arg)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -73,5 +73,6 @@
 %!   assert (output, "");
 %! endif
 
-%!error dos ()
+## Test input validation
+%!error <Invalid call> dos ()
 %!error dos (1, 2, 3)
--- a/scripts/miscellaneous/edit.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/edit.m	Thu Nov 19 13:08:00 2020 -0800
@@ -109,7 +109,7 @@
 ## (editor is started in the background and Octave continues) or sync mode
 ## (Octave waits until the editor exits).  Set it to @qcode{"sync"} to start
 ## the editor in sync mode.  The default is @qcode{"async"}
-## (@pxref{XREFsystem,,system}).
+## (@pxref{XREFsystem,,@code{system}}).
 ##
 ## @item editinplace
 ## Determines whether files should be edited in place, without regard to
@@ -143,7 +143,7 @@
                                 "MODE", "async",
                                 "EDITINPLACE", true);
   ## Make sure the stateval variables survive "clear functions".
-  mlock;
+  mlock ();
 
   ## Get default editor every time in case the user has changed it
   FUNCTION.EDITOR = [EDITOR() " %s"];
@@ -219,7 +219,7 @@
     if (iscellstr (varargin))
       editfilelist = varargin;
     else
-      error ("edit: if supplying more than one input all inputs must be strings containing field names to open.");
+      error ("edit: if supplying more than one input all inputs must be strings containing field names to open");
     endif
   endif
 
--- a/scripts/miscellaneous/fieldnames.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/fieldnames.m	Thu Nov 19 13:08:00 2020 -0800
@@ -28,30 +28,35 @@
 ## @deftypefnx {} {@var{names} =} fieldnames (@var{obj})
 ## @deftypefnx {} {@var{names} =} fieldnames (@var{javaobj})
 ## @deftypefnx {} {@var{names} =} fieldnames ("@var{javaclassname}")
-## Return a cell array of strings with the names of the fields in the
-## specified input.
+## Return a cell array of strings with the names of the fields in the specified
+## input.
 ##
-## When the input is a structure @var{struct}, the names are the elements of
-## the structure.
+## When the input is a structure @var{struct}, the @var{names} are the elements
+## of the structure.
 ##
-## When the input is an Octave object @var{obj}, the names are the public
+## When the input is an Octave object @var{obj}, the @var{names} are the public
 ## properties of the object.
 ##
 ## When the input is a Java object @var{javaobj} or a string containing the
-## name of a Java class @var{javaclassname}, the names are the public fields
-## (data members) of the object or class.
-## @seealso{numfields, isfield, orderfields, struct, methods}
+## name of a Java class @var{javaclassname}, the @var{names} are the public
+## fields (data members) of the object or class.
+## @seealso{numfields, isfield, orderfields, struct, properties}
 ## @end deftypefn
 
 function names = fieldnames (obj)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
-  if (isstruct (obj) || isobject (obj))
-    ## Call internal C++ function for structs or Octave objects
+  if (isstruct (obj))
     names = __fieldnames__ (obj);
+  elseif (isobject (obj))
+    try
+      names = properties (obj);      # classdef object
+    catch
+      names = __fieldnames__ (obj);  # @class object
+    end_try_catch
   elseif (isjava (obj) || ischar (obj))
     ## FIXME: Function prototype that accepts java obj exists, but doesn't
     ##        work if obj is java.lang.String.  Convert obj to classname.
@@ -70,22 +75,34 @@
 endfunction
 
 
-## test preservation of fieldname order
+## Test preservation of fieldname order
 %!test
 %! x(3).d=1;  x(2).a=2;  x(1).b=3;  x(2).c=3;
 %! assert (fieldnames (x), {"d"; "a"; "b"; "c"});
 
-## test empty structure
+## Test empty structure
 %!test
 %! s = struct ();
 %! assert (fieldnames (s), cell (0, 1));
 
-## test Java classname by passing classname
+## Test classdef object
+%!test
+%! m = containers.Map ();
+%! f = fieldnames (m);
+%! assert (f, {"Count"; "KeyType"; "ValueType"; "map"; "numeric_keys"});
+
+## Test old-style @class object
+%!test
+%! obj = ftp ();
+%! f = fieldnames (obj);
+%! assert (f, {"host"; "username"; "password"; "curlhandle"});
+
+## Test Java classname by passing classname
 %!testif HAVE_JAVA; usejava ("jvm")
 %! names = fieldnames ("java.lang.Double");
 %! assert (any (strcmp (names, "MAX_VALUE")));
 
-## test Java classname by passing java object
+## Test Java classname by passing java object
 %!testif HAVE_JAVA; usejava ("jvm")
 %! names = fieldnames (javaObject ("java.lang.Double", 10));
 %! assert (any (strcmp (names, "MAX_VALUE")));
--- a/scripts/miscellaneous/fileattrib.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/fileattrib.m	Thu Nov 19 13:08:00 2020 -0800
@@ -24,13 +24,16 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn  {} {} fileattrib (@var{file})
-## @deftypefnx {} {} fileattrib ()
+## @deftypefn  {} {} fileattrib ()
+## @deftypefnx {} {} fileattrib (@var{file})
+## @deftypefnx {} {[@var{status}, @var{attrib}] =} fileattrib (@dots{})
 ## @deftypefnx {} {[@var{status}, @var{msg}, @var{msgid}] =} fileattrib (@dots{})
-## Return information about @var{file}.
+## Report attribute information about @var{file}.
 ##
-## If successful, @var{status} is 1 and @var{msg} is a structure with the
-## following fields:
+## If no file or directory is specified, report information about the present
+## working directory.
+##
+## If successful, the output is a structure with the following fields:
 ##
 ## @table @code
 ## @item Name
@@ -64,30 +67,29 @@
 ## True if the user (group; other users) has execute permission for @var{file}.
 ## @end table
 ##
-## If an attribute does not apply (i.e., archive on a Unix system) then the
+## If an attribute does not apply (e.g., archive on a Unix system) then the
 ## field is set to NaN.
 ##
-## If @code{attrib} fails, @var{msg} is a non-empty string containing an
-## error message and @var{msg_id} is the non-empty string @qcode{"fileattrib"}.
+## If @var{file} contains globbing characters, information about all matching
+## files is returned in a structure array.
 ##
-## With no input arguments, return information about the current directory.
-##
-## If @var{file} contains globbing characters, return information about all
-## the matching files.
-## @seealso{glob}
+## If outputs are requested, the first is @var{status} which takes the value 1
+## when the operation was successful, and 0 otherwise.  The second output
+## contains the structure described above (@var{attrib}) if the operation was
+## successful; otherwise, the second output is a system-dependent error message
+## (@var{msg}).  The third output is an empty string ("") when the operation
+## was successful, or a unique message identifier (@var{msgid}) in the case of
+## failure.
+## @seealso{stat, glob}
 ## @end deftypefn
 
 function [status, msg, msgid] = fileattrib (file = ".")
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   if (! ischar (file))
     error ("fileattrib: FILE must be a string");
   endif
 
-  status = true;
+  sts = 1;
   msg = "";
   msgid = "";
 
@@ -108,10 +110,9 @@
         r(i).hidden = NaN;
       else
         [~, attrib] = dos (sprintf ('attrib "%s"', r(i).Name));
-        ## dos never returns error status so have to check it indirectly
+        ## DOS never returns error status so have to check it indirectly
         if (! isempty (strfind (attrib, " -")))
-          status = false;
-          msgid = "fileattrib";
+          sts = 0;
           break;
         endif
         attrib = regexprep (attrib, '\S+:.*', "");
@@ -142,15 +143,23 @@
         r(i).OtherExecute = NaN;
       endif
     else
-      status = false;
-      msgid = "fileattrib";
+      sts = 0;
       break;
     endif
   endfor
 
-  if (status)
-    if (nargout == 0)
-      status = r;
+  if (nargout == 0)
+    if (! sts)
+      error ("fileattrib: operation failed");
+    endif
+    status = r;
+  else
+    status = sts;
+    if (! sts)
+      if (isempty (msg))
+        msg = "operation failed";
+      endif
+      msgid = "fileattrib";
     else
       msg = r;
     endif
--- a/scripts/miscellaneous/fileparts.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/fileparts.m	Thu Nov 19 13:08:00 2020 -0800
@@ -34,7 +34,7 @@
 
 function [dir, name, ext] = fileparts (filename)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -111,7 +111,6 @@
 %! assert (strcmp (d, "") && strcmp (n, "") && strcmp (e, ".ext"));
 
 ## Test input validation
-%!error fileparts ()
-%!error fileparts (1,2)
+%!error <Invalid call> fileparts ()
 %!error <FILENAME must be a single string> fileparts (1)
 %!error <FILENAME must be a single string> fileparts (["a"; "b"])
--- a/scripts/miscellaneous/fullfile.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/fullfile.m	Thu Nov 19 13:08:00 2020 -0800
@@ -24,17 +24,18 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn  {} {@var{filename} =} fullfile (@var{dir1}, @var{dir2}, @dots{}, @var{file})
-## @deftypefnx {} {@var{filenames} =} fullfile (@dots{}, @var{files})
+## @deftypefn {} {@var{filename} =} fullfile (@var{dir1}, @var{dir2}, @dots{}, @var{file})
 ## Build complete filename from separate parts.
 ##
-## Joins any number of path components intelligently.  The return value is
-## the concatenation of each component with exactly one file separator
-## between each non empty part and at most one leading and/or trailing file
+## The function joins any number of path components intelligently.  The return
+## value is the concatenation of each component with exactly one file separator
+## between each part of the path and at most one leading and/or trailing file
 ## separator.
 ##
-## If the last component part is a cell array, returns a cell array of
-## filepaths, one for each element in the last component, e.g.:
+## The input arguments might be strings or cell strings.  Any input arguments
+## that are cell strings must contain one single string or must be equal in
+## size.  In that case, the function returns a cell string of filepaths of the
+## same dimensions as the input cell strings, e.g.:
 ##
 ## @example
 ## @group
@@ -49,7 +50,7 @@
 ## @end example
 ##
 ## On Windows systems, while forward slash file separators do work, they are
-## replaced by backslashes; in addition drive letters are stripped of leading
+## replaced by backslashes.  In addition, drive letters are stripped of leading
 ## file separators to obtain a valid file path.
 ##
 ## Note: @code{fullfile} does not perform any validation of the resulting full
@@ -59,19 +60,58 @@
 
 function filename = fullfile (varargin)
 
-  if (nargin && iscell (varargin{end}))
-    filename = cellfun (@(x) fullfile (varargin{1:end-1}, x), varargin{end},
-                                       "UniformOutput", false);
-  else
-    non_empty = cellfun ("isempty", varargin);
-    unc = 0;
-    if (ispc && ! isempty (varargin))
-      varargin = strrep (varargin, '/', filesep);
-      unc = strncmp (varargin{1}, '\\', 2);
-      varargin(1) = regexprep (varargin{1}, '[\\/]*([a-zA-Z]:[\\/]*)', "$1");
-    endif
-    filename = strjoin (varargin(! non_empty), filesep);
-    filename(unc + strfind (filename(1+unc : end), [filesep filesep])) = "";
+  ## remove empty arguments
+  varargin(cellfun (@isempty, varargin)) = [];
+
+  if (isempty (varargin))
+    ## return early for all empty or no input
+    filename = "";
+    return;
+  endif
+
+  ## check input type
+  is_cellstr = cellfun (@iscellstr, varargin);
+  if (! all (is_cellstr | cellfun (@ischar, varargin)))
+    error ("fullfile: input must either be strings or cell strings");
+  endif
+
+  ## convert regular strings to cell strings
+  varargin(! is_cellstr) = num2cell (varargin(! is_cellstr));
+
+  ## check if input size matches
+  if (numel (varargin) > 1 && common_size (varargin{:}) != 0)
+    error ("fullfile: cell string input must be scalar or of the same size");
+  endif
+
+  fs = filesep ();
+
+  if (ispc ())
+    ## replace forward slashes with backslashes
+    varargin = cellfun (@(x) strrep (x, "/", fs), varargin,
+                        "UniformOutput", false);
+
+    ## Strip fileseps preceeding drive letters
+    varargin{1} = regexprep (varargin{1}, '\\*([a-zA-Z]:\\*)', "$1");
+
+    unc = strncmp (varargin{1}, '\\', 2);
+  endif
+
+  ## insert file separator between elements
+  varargin(2,:) = {fs};
+  varargin{end} = "";
+
+  filename = strcat (varargin{:});
+
+  ## remove multiplicate file separators
+  filename = regexprep (filename, [undo_string_escapes(fs), "*"], fs);
+
+  if (ispc ())
+    ## prepend removed file separator for UNC paths
+    filename(unc) = strcat (fs, filename(unc));
+  endif
+
+  if (! any (is_cellstr))
+    filename = filename{1};
   endif
 
 endfunction
@@ -79,13 +119,14 @@
 
 %!shared fs, fsx, xfs, fsxfs, xfsy, xfsyfs
 %! fs = filesep ();
-%! fsx = [fs "x"];
-%! xfs = ["x" fs];
-%! fsxfs = [fs "x" fs];
-%! xfsy = ["x" fs "y"];
-%! xfsyfs = ["x" fs "y" fs];
+%! fsx = [fs, "x"];
+%! xfs = ["x", fs];
+%! fsxfs = [fs, "x", fs];
+%! xfsy = ["x", fs, "y"];
+%! xfsyfs = ["x", fs, "y", fs];
 
 %!assert (fullfile (""), "")
+%!assert (fullfile ("", ""), "")
 %!assert (fullfile (fs), fs)
 %!assert (fullfile ("", fs), fs)
 %!assert (fullfile (fs, ""), fs)
@@ -105,32 +146,39 @@
 %!assert (fullfile (fs, "x", fs), fsxfs)
 
 %!assert (fullfile ("x/", "/", "/", "y", "/", "/"), xfsyfs)
-%!assert (fullfile ("/", "x/", "/", "/", "y", "/", "/"), [fs xfsyfs])
-%!assert (fullfile ("/x/", "/", "/", "y", "/", "/"), [fs xfsyfs])
+%!assert (fullfile ("/", "x/", "/", "/", "y", "/", "/"), [fs, xfsyfs])
+%!assert (fullfile ("/x/", "/", "/", "y", "/", "/"), [fs, xfsyfs])
 
 ## different on purpose so that "fullfile (c{:})" works for empty c
 %!assert (fullfile (), "")
 
-%!assert (fullfile ("x", "y", {"c", "d"}), {[xfsyfs "c"], [xfsyfs "d"]})
+%!assert (fullfile ("x", "y", {"c", "d"}), {[xfsyfs, "c"], [xfsyfs, "d"]})
+%!assert (fullfile ({"folder1", "folder2"}, "sub", {"f1.m", "f2.m"}), ...
+%!        {["folder1", fs, "sub", fs, "f1.m"], ...
+%!         ["folder2", fs, "sub", fs, "f2.m"]});
 
 ## Windows specific - drive letters and file sep type
-%!test
-%! if (ispc)
-%!   assert (fullfile ('\/\/\//A:/\/\', "x/", "/", "/", "y", "/", "/"), ...
-%!           ['A:\' xfsyfs]);
-%! endif
+%!testif ; ispc ()
+%! assert (fullfile ('\/\/\//A:/\/\', "x/", "/", "/", "y", "/", "/"), ...
+%!         ['A:\' xfsyfs]);
 
 ## *nix specific - double backslash
-%!test
-%! if (isunix || ismac)
-%!   assert (fullfile (fs, fs), fs);
-%! endif
+%!testif ; ! ispc ()
+%! assert (fullfile (fs, fs), fs);
+
+## Windows specific - UNC path
+%!testif ; ispc ()
+%! assert (fullfile ({'\/\//server1', 'C:', '\\server2\/'}, ...
+%!                   "x/", "/", "/", "y", "/", "/"), ...
+%!         {['\\server1\', xfsyfs], ['C:\', xfsyfs], ['\\server2\', xfsyfs]});
 
 ## Windows specific - drive letters and file sep type, cell array
-%!test
-%! if (ispc)
-%!  tmp = fullfile ({"\\\/B:\//", "A://c", "\\\C:/g/h/i/j\/"});
-%!  assert (tmp{1}, 'B:\');
-%!  assert (tmp{2}, 'A:\c');
-%!  assert (tmp{3}, 'C:\g\h\i\j\');
-%! endif
+%!testif ; ispc ()
+%! tmp = fullfile ({'\\\/B:\//', 'A://c', '\\\C:/g/h/i/j\/'});
+%! assert (tmp{1}, 'B:\');
+%! assert (tmp{2}, 'A:\c');
+%! assert (tmp{3}, 'C:\g\h\i\j\');
+
+%!error <strings or cell strings> fullfile (1)
+%!error <strings or cell strings> fullfile ({1})
+%!error <same size> fullfile ({"a", "b"}, {"a", "b", "c"})
--- a/scripts/miscellaneous/getfield.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/getfield.m	Thu Nov 19 13:08:00 2020 -0800
@@ -32,8 +32,8 @@
 ## If @var{s} is a structure array then @var{sidx} selects an element of the
 ## structure array, @var{field} specifies the field name of the selected
 ## element, and @var{fidx} selects which element of the field (in the case of
-## an array or cell array).  See @code{setfield} for a more complete
-## description of the syntax.
+## an array or cell array).  For a more complete description of the syntax,
+## @pxref{XREFsetfield,,@code{setfield}}.
 ##
 ## @seealso{setfield, rmfield, orderfields, isfield, fieldnames, isstruct, struct}
 ## @end deftypefn
@@ -65,6 +65,6 @@
 %! assert (getfield (ss,{1,2},"fd",{3},"b", {1,4}), 5);
 
 ## Test input validation
-%!error getfield ()
-%!error getfield (1)
+%!error <Invalid call> getfield ()
+%!error <Invalid call> getfield (1)
 %!error <invalid index> getfield (1,2)
--- a/scripts/miscellaneous/grabcode.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/grabcode.m	Thu Nov 19 13:08:00 2020 -0800
@@ -59,7 +59,7 @@
 
 function code_str = grabcode (url)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -100,5 +100,4 @@
 
 
 ## Test input validation
-%!error grabcode ()
-%!error grabcode (1,2)
+%!error <Invalid call> grabcode ()
--- a/scripts/miscellaneous/gunzip.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/gunzip.m	Thu Nov 19 13:08:00 2020 -0800
@@ -41,7 +41,7 @@
 
 function filelist = gunzip (gzfile, dir = [])
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/inputParser.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/inputParser.m	Thu Nov 19 13:08:00 2020 -0800
@@ -190,10 +190,11 @@
 
   properties (Access = protected, Constant = true)
     ## Default validator, always returns scalar true.
-    def_val = @() true;
+    def_val = @(~) true;
   endproperties
 
   methods
+
     function set.PartialMatching (this, val)
       if (val)
         error ("inputParser: PartialMatching is not yet implemented");
@@ -225,7 +226,7 @@
       ##
       ## @end deftypefn
 
-      if (nargin < 2 || nargin > 3)
+      if (nargin < 2)
         print_usage ();
       elseif (numel (this.Optional) || numfields (this.Parameter)
               || numfields (this.Switch))
@@ -264,7 +265,7 @@
       ##
       ## @end deftypefn
 
-      if (nargin < 3 || nargin > 4)
+      if (nargin < 3)
         print_usage ();
       elseif (numfields (this.Parameter) || numfields (this.Switch))
         error (["inputParser.Optional: can't have Optional arguments " ...
@@ -287,7 +288,7 @@
       ##
       ## @end deftypefn
 
-      if (nargin < 3 || nargin > 4)
+      if (nargin < 3)
         print_usage ();
       endif
       this.addParameter (name, def, val);
@@ -420,7 +421,7 @@
           ## keys.  See bug #50752.
           idx -= 1;
           vidx -= 1;
-          break
+          break;
         endif
         try
           valid_option = opt.val (in);
@@ -437,11 +438,11 @@
                               && isscalar (in)))
             idx -= 1;
             vidx -= 1;
-            break
+            break;
           else
             this.error (sprintf (["failed validation of %s\n", ...
                                   "Validation function: %s"],
-                                 toupper (opt.name), disp(opt.val)));
+                                 toupper (opt.name), disp (opt.val)));
           endif
         endif
         this.Results.(opt.name) = in;
@@ -514,9 +515,11 @@
       printf ("Defined parameters:\n\n   {%s}\n",
               strjoin (this.Parameters, ", "));
     endfunction
+
   endmethods
 
   methods (Access = private)
+
     function validate_name (this, type, name)
       if (! isvarname (name))
         error ("inputParser.add%s: NAME is an invalid identifier", method);
@@ -572,10 +575,12 @@
       endif
       error ("%s%s", where, msg);
     endfunction
+
   endmethods
 
 endclassdef
 
+
 %!function p = create_p ()
 %!  p = inputParser ();
 %!  p.CaseSensitive = true;
@@ -650,7 +655,7 @@
 
 ## check alternative method (obj, ...) API
 %!function p2 = create_p2 ();
-%!  p2 = inputParser;
+%!  p2 = inputParser ();
 %!  addRequired (p2, "req1", @(x) ischar (x));
 %!  addOptional (p2, "op1", "val", @(x) any (strcmp (x, {"val", "foo"})));
 %!  addOptional (p2, "op2", 78, @(x) x > 50);
@@ -677,13 +682,13 @@
 
 ## We must not perform validation of default values
 %!test <*45837>
-%! p = inputParser;
+%! p = inputParser ();
 %! p.addParameter ("Dir", [], @ischar);
 %! p.parse ();
 %! assert (p.Results.Dir, []);
 
 %!test
-%! p = inputParser;
+%! p = inputParser ();
 %! p.addParameter ("positive", -1, @(x) x > 5);
 %! p.parse ();
 %! assert (p.Results.positive, -1);
@@ -695,13 +700,12 @@
 %! p.addOptional ("err", "foo", @error);
 %! p.addParameter ("not_err", "bar", @ischar);
 %! p.parse ("not_err", "qux");
-%! assert (p.Results.err, "foo")
-%! assert (p.Results.not_err, "qux")
-
+%! assert (p.Results.err, "foo");
+%! assert (p.Results.not_err, "qux");
 
 ## With more Parameters to test StructExpand
 %!function p3 = create_p3 ();
-%!  p3 = inputParser;
+%!  p3 = inputParser ();
 %!  addOptional (p3, "op1", "val", @(x) any (strcmp (x, {"val", "foo"})));
 %!  addOptional (p3, "op2", 78, @(x) x > 50);
 %!  addSwitch (p3, "verbose");
@@ -721,43 +725,43 @@
 %!test
 %! p3 = create_p3 ();
 %! p3.parse (struct ("line", "circle", "color", "green"), "line", "tree");
-%! assert (p3.Results.line, "tree")
+%! assert (p3.Results.line, "tree");
 %! p3.parse ("line", "tree", struct ("line", "circle", "color", "green"));
-%! assert (p3.Results.line, "circle")
+%! assert (p3.Results.line, "circle");
 
 %!test # unmatched parameters with StructExpand
 %! p3 = create_p3 ();
 %! p3.KeepUnmatched = true;
 %! p3.parse (struct ("line", "circle", "color", "green", "bar", "baz"));
-%! assert (p3.Unmatched.bar, "baz")
+%! assert (p3.Unmatched.bar, "baz");
 
 ## The validation for the second optional argument throws an error with
 ## a struct so check that we can handle it.
 %!test
 %! p3 = create_p3 ();
 %! p3.parse ("foo", struct ("color", "green"), "line", "tree");
-%! assert (p3.Results.op1, "foo")
-%! assert (p3.Results.line, "tree")
-%! assert (p3.Results.color, "green")
-%! assert (p3.Results.verbose, false)
+%! assert (p3.Results.op1, "foo");
+%! assert (p3.Results.line, "tree");
+%! assert (p3.Results.color, "green");
+%! assert (p3.Results.verbose, false);
 
 
 ## Some simple tests for addParamValue since all the other ones use add
 ## addParameter but they use the same codepath.
 %!test
-%! p = inputParser;
+%! p = inputParser ();
 %! addParameter (p, "line", "tree", @(x) any (strcmp (x, {"tree", "circle"})));
 %! addParameter (p, "color", "red", @(x) any (strcmp (x, {"red", "green"})));
 %! p.parse ("line", "circle");
-%! assert ({p.Results.line, p.Results.color}, {"circle", "red"})
+%! assert ({p.Results.line, p.Results.color}, {"circle", "red"});
 
 %!test
-%! p = inputParser;
+%! p = inputParser ();
 %! p.addParameter ("foo", "bar", @ischar);
 %! p.parse ();
-%! assert (p.Results, struct ("foo", "bar"))
+%! assert (p.Results, struct ("foo", "bar"));
 %! p.parse ("foo", "qux");
-%! assert (p.Results, struct ("foo", "qux"))
+%! assert (p.Results, struct ("foo", "qux"));
 
 ## This behaviour means that a positional option can never be a string
 ## that is the name of a parameter key.  This is required for Matlab
@@ -767,16 +771,16 @@
 %! p.addOptional ("op1", "val");
 %! p.addParameter ("line", "tree");
 %! p.parse ("line", "circle");
-%! assert (p.Results, struct ("op1", "val", "line", "circle"))
+%! assert (p.Results, struct ("op1", "val", "line", "circle"));
 %!
 %! p = inputParser ();
 %! p.addOptional ("op1", "val1");
 %! p.addOptional ("op2", "val2");
 %! p.addParameter ("line", "tree");
 %! p.parse ("line", "circle");
-%! assert (p.Results.op1, "val1")
-%! assert (p.Results.op2, "val2")
-%! assert (p.Results.line, "circle")
+%! assert (p.Results.op1, "val1");
+%! assert (p.Results.op2, "val2");
+%! assert (p.Results.line, "circle");
 %!
 %! ## If there's enough arguments to fill the positional options and
 %! ## param/key, it still skips positional options.
@@ -809,18 +813,18 @@
 %! p.addOptional ("op1", "val1");
 %! p.addParameter ("line", "circle");
 %! p.parse ("line");
-%! assert (p.Results, struct ("op1", "line", "line", "circle"))
+%! assert (p.Results, struct ("op1", "line", "line", "circle"));
 
 %!test <*50752>
-%! p = inputParser;
+%! p = inputParser ();
 %! p.addOptional ("op1", "val1");
 %! p.addSwitch ("line");
 %! p.parse ("line");
-%! assert (p.Results.op1, "val1")
-%! assert (p.Results.line, true)
+%! assert (p.Results.op1, "val1");
+%! assert (p.Results.line, true);
 
 %!test
-%! p = inputParser;
+%! p = inputParser ();
 %! p.addParameter ("a", []);
 %! p.addParameter ("b", []);
 %! p.parse ("a", 1);
@@ -829,7 +833,7 @@
 %! assert (p.UsingDefaults, {"a"});
 
 %!test
-%! p = inputParser;
+%! p = inputParser ();
 %! p.addParameter ("b", []);
 %! p.KeepUnmatched = true;
 %! p.parse ("a", 1);
@@ -838,8 +842,8 @@
 %! assert (p.Unmatched, struct ());
 
 ## Test for patch #9241
-%!error<failed validation of A with ischar>
-%! p = inputParser;
+%!error <failed validation of A with ischar>
+%! p = inputParser ();
 %! p.addParameter ("a", [], @ischar);
 %! p.parse ("a", 1);
 
--- a/scripts/miscellaneous/inputname.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/inputname.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,76 +31,133 @@
 ## @deftypefnx {} {} inputname (@var{n}, @var{ids_only})
 ## Return the name of the @var{n}-th argument to the calling function.
 ##
-## If the argument is not a simple variable name, return an empty string.  As
-## an example, a reference to a field in a structure such as @code{s.field} is
-## not a simple name and will return @qcode{""}.
+## If the argument is not a simple variable name, return an empty string.
+## Examples which will return @qcode{""} are numbers (@code{5.1}),
+## expressions (@code{@var{y}/2}), and cell or structure indexing
+## (@code{@var{c}@{1@}} or @code{@var{s}.@var{field}}).
 ##
 ## @code{inputname} is only useful within a function.  When used at the command
-## line it always returns an empty string.
+## line or within a script it always returns an empty string.
+##
+## By default, return an empty string if the @var{n}-th argument is not a valid
+## variable name.  If the optional argument @var{ids_only} is false, return the
+## text of the argument even if it is not a valid variable name.  This is an
+## Octave extension that allows the programmer to view exactly how the function
+## was invoked even when the inputs are complex expressions.
+## @seealso{nargin, narginchk}
+## @end deftypefn
+
+## FIXME: Actually, it probably *isn't* worth fixing, but there are small
+## differences between Octave and Matlab.
+##
+## 1) When called from the top-level or a script, Matlab throws an error
+##
+##   inputname (1)   % at command prompt
+##   % Octave returns "", Matlab throws an error
 ##
-## By default, return an empty string if the @var{n}-th argument is not
-## a valid variable name.  If the optional argument @var{ids_only} is
-## false, return the text of the argument even if it is not a valid
-## variable name.
-## @seealso{nargin, nthargout}
-## @end deftypefn
+## 2) cell or struct indexing causes all further names to be returned as ""
+##
+##   c = {'a', 'b'}
+##   y = 1; z = 2;
+##   func (c, y, z)
+##   % inputname() would return 'c', 'y', 'z' for the inputs.
+##   func (c{1}, y, z)
+##   % inputname() would return '', '', '' for the inputs.
+##
+## 3) If inputname is not called from a function, Matlab walks up the stack
+##    until it finds some valid code and then works from there.  This could
+##    be relevant for mex files or anonymous functions.
+##
+##   f = @(x) inputname (x);
+##   a = 1:4;
+##   arrayfun (fn, a, 'uniformoutput', false)
+##   % output is {'fn', 'a', '', ''}
 
 function name = inputname (n, ids_only = true)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
-  name = "";
+  if (! isscalar (n) || ! isindex (n))
+    error ("inputname: N must be a scalar index");
+  endif
+
   try
-    name = evalin ("caller", sprintf ("__varval__ ('.argn.'){%d}", fix (n)));
+    name = evalin ("caller", sprintf ("__varval__ ('.argn.'){%d}", n));
   catch
+    name = "";
     return;
   end_try_catch
 
-  ## For compatibility with Matlab,
-  ## return empty string if argument name is not a valid identifier.
+  ## For compatibility with Matlab, return empty string if argument name is
+  ## not a valid identifier.
   if (ids_only && ! isvarname (name))
     name = "";
+  elseif (ids_only)
+    ## More complicated checking is required to verify name (bug #59103).
+    ## NAME may be text, like "Inf", which is an acceptable variable name
+    ## that passes isvarname(), but that does not mean it is an actual
+    ## variable name, rather than a function or IEEE number.
+    try
+      v = evalin ("caller",
+                  sprintf ("evalin ('caller', '__varval__ (\"%s\")')", name));
+    catch
+      name = "";
+    end_try_catch
   endif
 
 endfunction
 
 
-## Warning: heap big magic in the following tests!!!
-## The test function builds a private context for each test, with only the
-## specified values shared between them.  It does this using the following
-## template:
-##
-##     function [<shared>] = testfn (<shared>)
-##        <test>
-##     endfunction
-##
-## To test inputname, I need a function context invoked with known parameter
-## names.  So define a couple of shared parameters, et voila!, the test is
-## trivial.
+%!function name = __iname1__ (arg1, arg2, arg3)
+%!  name = inputname (1);
+%!endfunction
+
+%!function name = __iname1_ID__ (arg1, arg2, arg3)
+%!  name = inputname (1, false);
+%!endfunction
+
+%!function name = __iname2__ (arg1, arg2, arg3)
+%!  name = inputname (2);
+%!endfunction
 
-%!shared hello, worldly
-%!assert (inputname (1), "hello")
-%!assert (inputname (2), "worldly")
-%!assert (inputname (3), "")
+%!function names = __iname3__ (arg1, arg2, arg3)
+%!  names = cell (1, 3);
+%!  for i = 1:3
+%!    names{i} = inputname (i);
+%!  endfor
+%!endfunction
+
+%!test
+%! assert (__iname1__ ('xvar'), "");
+%! xvar = 1; 
+%! assert (__iname1__ (xvar), "xvar");
 
-## Clear parameter list so that testfn is created with zero inputs/outputs
-%!shared
-%!assert (inputname (-1), "")
-%!assert (inputname (1), "")
+%!test
+%! xvar = 1;  yvar = 2;
+%! assert (__iname2__ (xvar), "");
+%! assert (__iname2__ (xvar, yvar), "yvar");
+
+%!test
+%! xvar = 1;  yvar = 2;
+%! assert (__iname3__ (xvar), {"xvar", "", ""});
+%! assert (__iname3__ (xvar, yvar), {"xvar", "yvar", ""});
+%! assert (__iname3__ (xvar, 3, yvar), {"xvar", "", "yvar"});
 
-%!function r = __foo1__ (x, y)
-%!  r = inputname (2);
-%!endfunction
-%!assert (__foo1__ (pi, e), "e")
-%!assert (feval (@__foo1__, pi, e), "e")
+## Test numbers, expressions, indexing operations
+%!test
+%! assert (__iname1__ (1.0), "");
+%! x = 1;
+%! assert (__iname1__ (x / 2), "");
+%! assert (__iname1__ (Inf), "");
 
-%!function r = __foo2__ (x, y)
-%!  r = inputname (2, false);
-%!endfunction
-%!assert (__foo2__ (pi+1, 2+2), "2 + 2")
-%!assert (feval (@__foo2__, pi, pi/2), "pi / 2")
+%!test
+%! assert (__iname1_ID__ (1.0), "1.0");
+%! x = 1;
+%! assert (__iname1_ID__ (x / 2), "x / 2");
+%! assert (__iname1_ID__ (Inf), "Inf");
 
-%!error inputname ()
-%!error inputname (1,2,3)
+%!error <Invalid call> inputname ()
+%!error <N must be a scalar> inputname (ones (2,2))
+%!error <N must be a scalar index> inputname (-1)
--- a/scripts/miscellaneous/isfile.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/isfile.m	Thu Nov 19 13:08:00 2020 -0800
@@ -34,7 +34,7 @@
 
 function retval = isfile (f)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -75,6 +75,6 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error isfile ()
+%!error <Invalid call> isfile ()
 %!error isfile ("a", "b")
 %!error <F must be a string> isfile (1.0)
--- a/scripts/miscellaneous/isfolder.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/isfolder.m	Thu Nov 19 13:08:00 2020 -0800
@@ -35,7 +35,7 @@
 
 function retval = isfolder (f)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -70,11 +70,11 @@
 %!   addpath (d);
 %!   assert (! isfolder (n));
 %! unwind_protect_cleanup
-%!   try, rmdir (tmp); end_try_catch
-%!   try, rmpath (d); end_try_catch
+%!   sts = rmdir (tmp);
+%!   rmpath (d);
 %! end_unwind_protect
 
 ## Test input validation
-%!error isfolder ()
+%!error <Invalid call> isfolder ()
 %!error isfolder ("a", "b")
 %!error <F must be a string> isfolder (1.0)
--- a/scripts/miscellaneous/ismac.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/ismac.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,15 +31,9 @@
 
 function retval = ismac ()
 
-  if (nargin == 0)
-    retval = __octave_config_info__ ("mac");
-  else
-    print_usage ();
-  endif
+  retval = __octave_config_info__ ("mac");
 
 endfunction
 
 
 %!assert (islogical (ismac ()))
-
-%!error ismac (1)
--- a/scripts/miscellaneous/ismethod.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/ismethod.m	Thu Nov 19 13:08:00 2020 -0800
@@ -42,7 +42,7 @@
   endif
 
   if (! ischar (method))
-    error ("ismethod: second argument must be a method name");
+    error ("ismethod: METHOD must be a string");
   endif
 
   method_list = methods (obj);
@@ -51,6 +51,7 @@
 
 endfunction
 
+
 %!testif HAVE_JAVA; usejava ("jvm")
 %! assert (ismethod (javaObject ("java.lang.String", "Yo"), "hashCode"));
 
--- a/scripts/miscellaneous/ispc.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/ispc.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,15 +31,9 @@
 
 function retval = ispc ()
 
-  if (nargin == 0)
-    retval = __octave_config_info__ ("windows");
-  else
-    print_usage ();
-  endif
+  retval = __octave_config_info__ ("windows");
 
 endfunction
 
 
 %!assert (islogical (ispc ()))
-
-%!error ispc (1)
--- a/scripts/miscellaneous/isunix.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/isunix.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,15 +31,9 @@
 
 function retval = isunix ()
 
-  if (nargin == 0)
-    retval = __octave_config_info__ ("unix");
-  else
-    print_usage ();
-  endif
+  retval = __octave_config_info__ ("unix");
 
 endfunction
 
 
 %!assert (islogical (isunix ()))
-
-%!error isunix (1)
--- a/scripts/miscellaneous/license.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/license.m	Thu Nov 19 13:08:00 2020 -0800
@@ -68,12 +68,8 @@
 
 function [retval, errmsg] = license (cmd, feature, toggle)
 
-  if (nargin > 3)
-    print_usage ();
-  endif
-
-  ## Then only give information about Octave core
   if (nargin == 0)
+    ## then only give information about Octave core
     retval = "GNU General Public License";
     return;
   endif
@@ -82,10 +78,6 @@
 
   switch (tolower (cmd))
     case "inuse"
-      if (nargin > 2)
-        print_usage ();
-      endif
-
       features = features(loaded);
 
       if (nargin > 1)
--- a/scripts/miscellaneous/list_primes.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/list_primes.m	Thu Nov 19 13:08:00 2020 -0800
@@ -34,9 +34,7 @@
 
 function retval = list_primes (n = 25)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (! isreal (n) || ! isscalar (n))
+  if (! isreal (n) || ! isscalar (n))
     error ("list_primes: N must be a real scalar");
   endif
 
@@ -69,6 +67,5 @@
 %!assert (list_primes (1), [2])
 
 ## Test input validation
-%!error list_primes (1, 2)
 %!error <N must be a real scalar> list_primes (i)
 %!error <N must be a real scalar> list_primes ([1 2])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/miscellaneous/memory.m	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,273 @@
+########################################################################
+##
+## Copyright (C) 2020 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn  {} {} memory ()
+## @deftypefnx {} {[@var{userdata}, @var{systemdata}] =} memory ()
+## Display or return information about the memory usage of Octave.
+##
+## If the function is called without output arguments, a table with an overview
+## of the current memory consumption is displayed.
+##
+## The output argument @var{userdata} is a structure with the following fields
+## containing data for the Octave process:
+##
+## @table @code
+## @item @var{MaxPossibleArrayBytes}
+## Maximum size for an array to be allocated.  Be aware that this includes
+## @emph{all} physical memory and swap space.  Allocating that amount of memory
+## might result in system instability, data corruption, and/or file system
+## corruption.  Note that depending on the platform (32-bit systems), the
+## largest contiguous memory block might further limit the maximum possible
+## allocatable array.  This check is not currently implemented.
+##
+## @item @var{MemAvailableAllArrays}
+## The total size of available memory in bytes.
+##
+## @item @var{ram_available_all_arrays}
+## The maximum size for an array that can be allocated in physical memory
+## (excluding swap space).  Note that depending on the platform (32-bit
+## systems), the largest contiguous memory block might further limit the
+## maximum possible allocatable array.  This check is not currently
+## implemented.
+##
+## @item  @var{MemUsedMATLAB}
+## @itemx @var{mem_used_octave}
+## The memory (including swap space) currently used by Octave in bytes.
+##
+## @item @var{ram_used_octave}
+## The physical memory (excluding swap space) currently used by Octave in
+## bytes.
+##
+## @end table
+##
+## The output argument @var{systemdata} is a nested structure with the
+## following fields containing information about the system's memory:
+##
+## @table @code
+## @item @var{PhysicalMemory.Available}
+## The currently available physical memory in bytes.
+##
+## @item @var{PhysicalMemory.Total}
+## The total physical memory in bytes.
+##
+## @item @var{SystemMemory.Available}
+## The currently available memory (including swap space) in bytes.
+##
+## @item @var{SystemMemory.Total}
+## The total memory (including swap space) in bytes.
+##
+## @item @var{VirtualAddressSpace.Available}
+## The currently available virtual address space in bytes.
+##
+## @item @var{VirtualAddressSpace.Total}
+## The total virtual address space in bytes.
+##
+## @end table
+##
+## @example
+## @group
+## memory ()
+##    @result{} System    RAM: 3934008 KiB,  swap: 4087804 KiB
+##       Octave    RAM:  170596 KiB,  virt: 1347944 KiB
+##       Free      RAM: 1954940 KiB,  swap: 4087804 KiB
+##       Available RAM: 2451948 KiB, total: 6042744 KiB
+## @end group
+##
+## @group
+## [userdata, systemdata] = memory ()
+##    @result{} userdata =
+##      scalar structure containing the fields:
+##      MaxPossibleArrayBytes = 6.1622e+09
+##      MemAvailableAllArrays = 6.1622e+09
+##      ram_available_all_arrays = 2.4883e+09
+##      MemUsedMATLAB = 1.3825e+09
+##      mem_used_octave = 1.3825e+09
+##      ram_used_octave = 1.7824e+08
+##
+##    systemdata =
+##      scalar structure containing the fields:
+##      PhysicalMemory =
+##        scalar structure containing the fields:
+##          Available = 2.4954e+09
+##          Total = 4.0284e+09
+##      SystemMemory =
+##        scalar structure containing the fields:
+##          Available = 6.6813e+09
+##          Total = 8.2143e+09
+##      VirtualAddressSpace =
+##        scalar structure containing the fields:
+##          Available = 2.8147e+14
+##          Total = 2.8147e+14
+## @end group
+## @end example
+##
+## This function is implemented for Linux and Windows only.
+##
+## @seealso{computer, getpid, getrusage, nproc, uname}
+## @end deftypefn
+
+function [userdata, systemdata] = memory ()
+
+  if (! isunix () && ! ispc ())
+    if (nargout > 0)
+      error ("memory: function not yet implemented for this architecture");
+    else
+      warning ("memory: function not yet implemented for this architecture");
+    endif
+    return;
+  endif
+
+  kiB = 1024;
+  [architecture, bits] = computer ();
+
+  if (isunix ())
+    ## Read values from pseudofiles
+    [status, meminfo] = lmemory ();
+
+    ## FIXME: Query the actual size of the user address space,
+    ##        e.g., with getrlimit (RLIMIT_AS, rlp)
+    if (log2 (bits) > 32)
+      ## 64-bit platform
+      address_space = 2^48;  # 256 TiB
+    else
+      ## 32-bit platform
+      address_space = 3 * 2^30;  # 3 GiB
+    endif
+
+    total_ram = meminfo.MemTotal * kiB;
+    total_swap = meminfo.SwapTotal * kiB;
+    free_ram = meminfo.MemFree * kiB;
+    if (isfield (meminfo, "MemAvailable"))
+      available_ram = meminfo.MemAvailable * kiB;
+    else
+      ## On kernels from before 2014 MemAvailable is not present.
+      ## This is a rough estimate that can be used instead.
+      available_ram = (meminfo.MemFree + meminfo.Cached) * kiB;
+    endif
+    free_swap = meminfo.SwapFree * kiB;
+    used_ram = status.VmRSS * kiB;
+    used_virtual = status.VmSize * kiB;
+    avail_virtual = address_space - used_virtual;
+
+  elseif (ispc ())
+    [proc, sys] = __wmemory__ ();
+
+    total_ram = sys.TotalPhys;
+    total_swap = sys.TotalPageFile;
+    available_ram = sys.AvailPhys;
+    free_swap = sys.AvailPageFile;
+    used_ram = proc.WorkingSetSize;
+    used_virtual = proc.WorkingSetSize + proc.PagefileUsage;
+    avail_virtual = sys.AvailVirtual;
+    address_space = sys.TotalVirtual;
+
+  endif
+
+  available = min (available_ram + free_swap, avail_virtual);
+  ram_available = min (available_ram, avail_virtual);
+
+  ## FIXME: On 32-bit systems, the largest possible array is limited by the
+  ##        largest contiguous block in memory.
+  user.MaxPossibleArrayBytes = available;
+  user.MemAvailableAllArrays = available;
+  user.ram_available_all_arrays = ram_available;
+  user.MemUsedMATLAB = used_virtual;  # For compatibility
+  user.mem_used_octave = used_virtual;
+  user.ram_used_octave = used_ram;
+
+  syst.PhysicalMemory.Available = available_ram;
+  syst.PhysicalMemory.Total = total_ram;
+  syst.SystemMemory.Available = available_ram + free_swap;
+  syst.SystemMemory.Total = total_ram + total_swap;
+  syst.VirtualAddressSpace.Available = avail_virtual;
+  syst.VirtualAddressSpace.Total = address_space;
+
+  if (nargout)
+    userdata = user;
+    systemdata = syst;
+  else
+    unitsize = kiB;
+    unitname = 'kiB';
+    disp (sprintf ("Octave is running on %s", architecture))
+    disp (sprintf ("System    RAM: %9.0f %s,  swap: %9.0f %s",
+                   round (syst.PhysicalMemory.Total / unitsize), unitname,
+                   round (total_swap / unitsize), unitname ))
+    disp (sprintf ("Octave    RAM: %9.0f %s,  virt: %9.0f %s",
+                   round (user.ram_used_octave / unitsize), unitname,
+                   round (user.mem_used_octave / unitsize), unitname))
+    if (isunix ())
+      ## The concept of free vs. available RAM doesn't seem to exist on Windows
+      disp (sprintf ("Free      RAM: %9.0f %s,  swap: %9.0f %s",
+                     round (free_ram / unitsize), unitname,
+                     round (free_swap / unitsize), unitname))
+    endif
+    disp (sprintf ("Available RAM: %9.0f %s, total: %9.0f %s",
+                   round (user.ram_available_all_arrays / unitsize), unitname,
+                   round (user.MemAvailableAllArrays / unitsize), unitname))
+  endif
+
+endfunction
+
+function [status, meminfo] = lmemory ()
+  ## Read pseudo files to gather memory information on Linux
+
+  ## Read the proc/self/status pseudofile.
+  ## See https://linuxwiki.de/proc/pid#A.2Fproc.2Fpid.2Fstatus.
+  ## It contains a variable number of lines with name-value pairs.
+
+  f = fopen ("/proc/self/status");
+  buffer = textscan (f, "%s %s", "delimiter", ':\n');
+  fclose (f);
+  for i = 1:rows (buffer{1})
+    status.(buffer{1}{i}) = textscan (buffer{2}{i}){1};
+  endfor
+
+  ## Read the /proc/meminfo pseudofile
+  ## see https://linuxwiki.de/proc/meminfo
+  ## It contains a variable number of lines with name-value pairs.
+
+  f = fopen ("/proc/meminfo");
+  buffer = textscan (f, "%s %s", "delimiter", ':\n');
+  fclose (f);
+  for i = 1:rows (buffer{1})
+    meminfo.(buffer{1}{i}) = textscan (buffer{2}{i}){1};
+  endfor
+
+endfunction
+
+
+%!testif ; isunix () || ispc ()
+%! [user, syst] = memory ();
+%! assert (user.mem_used_octave > 0);
+%! assert (user.ram_used_octave <= user.mem_used_octave);
+%! assert (user.mem_used_octave < syst.SystemMemory.Total);
+%! assert (user.MemAvailableAllArrays <= syst.SystemMemory.Available);
+
+%!testif ; ! isunix () && ! ispc ()
+%! fail ("[user] = memory ()",
+%!       "function not yet implemented for this architecture");
+%! fail ("memory ()", "warning",
+%!       "function not yet implemented for this architecture");
--- a/scripts/miscellaneous/menu.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/menu.m	Thu Nov 19 13:08:00 2020 -0800
@@ -100,8 +100,9 @@
 endfunction
 
 
-%!error menu ()
-%!error menu ("title")
+## Test input validation
+%!error <Invalid call> menu ()
+%!error <Invalid call> menu ("title")
 %!error <TITLE must be a string> menu (1, "opt1")
 %!error <All OPTIONS must be strings> menu ("title", "opt1", 1)
 %!error <OPTIONS must be string or cell array of strings> menu ("title", 1)
--- a/scripts/miscellaneous/methods.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/methods.m	Thu Nov 19 13:08:00 2020 -0800
@@ -46,7 +46,7 @@
 
 function mtds = methods (obj, opt)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -145,7 +145,7 @@
 %!         "validate_name"});
 
 ## Test input validation
-%!error methods ()
+%!error <Invalid call> methods ()
 %!error methods ("a", "b", "c")
 %!error <invalid option> methods ("ftp", "option1")
 %!error <invalid input argument> methods (1)
--- a/scripts/miscellaneous/mkdir.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/mkdir.m	Thu Nov 19 13:08:00 2020 -0800
@@ -50,7 +50,7 @@
 
 function [status, msg, msgid] = mkdir (parent, dirname)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -112,7 +112,7 @@
 %!   assert (isfolder (dir));
 %! unwind_protect_cleanup
 %!   confirm_recursive_rmdir (false, "local");
-%!   rmdir (dir1, "s");
+%!   sts = rmdir (dir1, "s");
 %! end_unwind_protect
 
 %!test <*53031>
@@ -125,8 +125,8 @@
 %!   assert (status);
 %!   assert (isfolder (fullfile (tmp_dir, "subdir")));
 %! unwind_protect_cleanup
-%!   rmdir (fullfile (tmp_dir, "subdir"));
-%!   rmdir (tmp_dir);
+%!   sts = rmdir (fullfile (tmp_dir, "subdir"));
+%!   sts = rmdir (tmp_dir);
 %!   if (isempty (HOME))
 %!     unsetenv ("HOME");
 %!   else
@@ -138,5 +138,4 @@
 %! fail ('mkdir ("__%hello%__", "world")', "invalid PARENT");
 
 ## Test input validation
-%!error mkdir ()
-%!error mkdir ("a", "b", "c")
+%!error <Invalid call> mkdir ()
--- a/scripts/miscellaneous/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -10,6 +10,7 @@
   %reldir%/private/tar_is_bsd.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/bug_report.m \
   %reldir%/bunzip2.m \
   %reldir%/cast.m \
@@ -44,6 +45,7 @@
   %reldir%/loadobj.m \
   %reldir%/ls.m \
   %reldir%/ls_command.m \
+  %reldir%/memory.m \
   %reldir%/menu.m \
   %reldir%/methods.m \
   %reldir%/mex.m \
--- a/scripts/miscellaneous/movefile.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/movefile.m	Thu Nov 19 13:08:00 2020 -0800
@@ -54,12 +54,12 @@
 
 function [status, msg, msgid] = movefile (f1, f2, force)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
   max_cmd_line = 1024;
-  status = true;
+  sts = 1;
   msg = "";
   msgid = "";
 
@@ -96,13 +96,27 @@
   ## If f1 has more than 1 element f2 must be a directory
   isdir = isfolder (f2);
   if (numel (f1) > 1 && ! isdir)
-    error ("movefile: when moving multiple files, F2 must be a directory");
+    if (nargout == 0)
+      error ("movefile: when copying multiple files, F2 must be a directory");
+    else
+      status = 0;
+      msg = "when copying multiple files, F2 must be a directory";
+      msgid = "movefile";
+      return;
+    endif
   endif
 
   ## Protect the filename(s).
   f1 = glob (f1);
   if (isempty (f1))
-    error ("movefile: no files to move");
+    if (nargout == 0)
+      error ("movefile: no files to move");
+    else
+      status = 0;
+      msg = "no files to move";
+      msgid = "movefile";
+      return;
+    endif
   endif
   p1 = sprintf ('"%s" ', f1{:});
   p2 = tilde_expand (f2);
@@ -129,11 +143,11 @@
       ## Move the file(s).
       [err, msg] = system (sprintf ('%s %s "%s"', cmd, p1, p2));
       if (err != 0)
-        status = false;
+        sts = 0;
         msgid = "movefile";
       endif
       ## Load new file(s) in editor
-      __event_manager_file_renamed__ (status);
+      __event_manager_file_renamed__ (sts);
     endwhile
   else
     if (ispc () && ! isunix ()
@@ -147,11 +161,19 @@
     ## Move the file(s).
     [err, msg] = system (sprintf ('%s %s "%s"', cmd, p1, p2));
     if (err != 0)
-      status = false;
+      sts = 0;
       msgid = "movefile";
     endif
     ## Load new file(s) in editor
-    __event_manager_file_renamed__ (status);
+    __event_manager_file_renamed__ (sts);
+  endif
+
+  if (nargout == 0)
+    if (sts == 0)
+      error ("movefile: operation failed: %s", msg);
+    endif
+  else
+    status = sts;
   endif
 
 endfunction
@@ -159,14 +181,14 @@
 
 %!test
 %! unwind_protect
-%!   f1 = tempname;
+%!   f1 = tempname ();
 %!   tmp_var = pi;
 %!   save (f1, "tmp_var");
 %!   fid = fopen (f1, "rb");
 %!   assert (fid >= 0);
 %!   orig_data = fread (fid);
 %!   fclose (fid);
-%!   f2 = tempname;
+%!   f2 = tempname ();
 %!   assert (movefile (f1, f2));
 %!   assert (! exist (f1, "file"));
 %!   assert (exist (f2, "file"));
@@ -182,8 +204,8 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error movefile ()
-%!error movefile (1,2,3,4)
+%!error <Invalid call> movefile ()
 %!error <F1 must be a string> movefile (1, "foobar")
 %!error <F2 must be a string> movefile ("foobar", 1)
 %!error <F2 must be a directory> movefile ({"a", "b"}, "%_NOT_A_DIR_%")
+%!error <no files to move> movefile ("%_NOT_A_FILENAME1_%", "%_NOT_A_FILENAME2_%")
--- a/scripts/miscellaneous/mustBeFinite.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/mustBeFinite.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,7 +36,7 @@
 
 function mustBeFinite (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/mustBeGreaterThan.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/mustBeGreaterThan.m	Thu Nov 19 13:08:00 2020 -0800
@@ -67,7 +67,7 @@
 
 %!error <Invalid call> mustBeGreaterThan ()
 %!error <Invalid call> mustBeGreaterThan (1)
-%!error <Invalid call> mustBeGreaterThan (1,2,3)
+%!error <called with too many inputs> mustBeGreaterThan (1, 2, 3)
 %!error <input must be greater than 42> mustBeGreaterThan (42, 42)
 %!error <found 1 elements that were not> mustBeGreaterThan (Inf, Inf)
 %!error <must be greater than 0> mustBeGreaterThan (NaN, 0)
--- a/scripts/miscellaneous/mustBeGreaterThanOrEqual.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/mustBeGreaterThanOrEqual.m	Thu Nov 19 13:08:00 2020 -0800
@@ -69,6 +69,6 @@
 
 %!error <Invalid call> mustBeGreaterThanOrEqual ()
 %!error <Invalid call> mustBeGreaterThanOrEqual (1)
-%!error <Invalid call> mustBeGreaterThanOrEqual (1,2,3)
+%!error <called with too many inputs> mustBeGreaterThanOrEqual (1, 2, 3)
 %!error <must be greater than or equal to 2> mustBeGreaterThanOrEqual (1, 2)
 %!error <must be greater than or equal to 0> mustBeGreaterThanOrEqual (NaN, 0)
--- a/scripts/miscellaneous/mustBeInteger.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/mustBeInteger.m	Thu Nov 19 13:08:00 2020 -0800
@@ -37,7 +37,7 @@
 
 function mustBeInteger (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -54,7 +54,7 @@
     but = "there were non-finite values";
   elseif (any (x != fix (x)))
     but = "it had fractional values in some elements";
-  end
+  endif
 
   if (! isempty (but))
     label = inputname (1);
--- a/scripts/miscellaneous/mustBeLessThan.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/mustBeLessThan.m	Thu Nov 19 13:08:00 2020 -0800
@@ -69,7 +69,7 @@
 
 %!error <Invalid call> mustBeLessThan ()
 %!error <Invalid call> mustBeLessThan (1)
-%!error <Invalid call> mustBeLessThan (1,2,3)
+%!error <called with too many inputs> mustBeLessThan (1, 2, 3)
 %!error <must be less than 0> mustBeLessThan (1, 0)
 %!error <must be less than 1> mustBeLessThan (1, 1)
 %!error <must be less than Inf> mustBeLessThan (Inf, Inf)
--- a/scripts/miscellaneous/mustBeLessThanOrEqual.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/mustBeLessThanOrEqual.m	Thu Nov 19 13:08:00 2020 -0800
@@ -72,5 +72,5 @@
 
 %!error <Invalid call> mustBeLessThanOrEqual ()
 %!error <Invalid call> mustBeLessThanOrEqual (1)
-%!error <Invalid call> mustBeLessThanOrEqual (1,2,3)
+%!error <called with too many inputs> mustBeLessThanOrEqual (1, 2, 3)
 %!error <must be less than or equal to 0> mustBeLessThanOrEqual (1, 0)
--- a/scripts/miscellaneous/mustBeMember.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/mustBeMember.m	Thu Nov 19 13:08:00 2020 -0800
@@ -53,8 +53,8 @@
       label = "input";
     endif
     n_bad = numel (find (tf));
-    # FIXME: Fancy inclusion of bad_val & valid values in the error message.
-    #        Probably use mat2str() in a try/catch for that.
+    ## FIXME: Fancy inclusion of bad_val & valid values in the error message.
+    ##        Probably use mat2str() in a try/catch for that.
     error ("%s must be one of the specified valid values; found %d elements that were not", ...
            label, n_bad);
   endif
@@ -70,6 +70,6 @@
 
 %!error <Invalid call> mustBeMember ()
 %!error <Invalid call> mustBeMember (1)
-%!error <Invalid call> mustBeMember (1,2,3)
+%!error <called with too many inputs> mustBeMember (1, 2, 3)
 %!error <found 1 elements> mustBeMember ([1, 42], 1:5)
 %!error <found 1 elements> mustBeMember ("nope", {"foo", "bar", "baz"})
--- a/scripts/miscellaneous/mustBeNegative.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/mustBeNegative.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,7 +36,7 @@
 
 function mustBeNegative (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/mustBeNonNan.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/mustBeNonNan.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,7 +36,7 @@
 
 function mustBeNonNan (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/mustBeNonempty.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/mustBeNonempty.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,7 +36,7 @@
 
 function mustBeNonempty (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/mustBeNonnegative.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/mustBeNonnegative.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,7 +36,7 @@
 
 function mustBeNonnegative (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/mustBeNonpositive.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/mustBeNonpositive.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,7 +36,7 @@
 
 function mustBeNonpositive (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/mustBeNonsparse.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/mustBeNonsparse.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,7 +36,7 @@
 
 function mustBeNonsparse (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/mustBeNonzero.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/mustBeNonzero.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,7 +36,7 @@
 
 function mustBeNonzero (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/mustBeNumeric.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/mustBeNumeric.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,7 +36,7 @@
 
 function mustBeNumeric (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/mustBeNumericOrLogical.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/mustBeNumericOrLogical.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,7 +36,7 @@
 
 function mustBeNumericOrLogical (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/mustBePositive.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/mustBePositive.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,7 +36,7 @@
 
 function mustBePositive (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/mustBeReal.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/mustBeReal.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,7 +36,7 @@
 
 function mustBeReal (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/namedargs2cell.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/namedargs2cell.m	Thu Nov 19 13:08:00 2020 -0800
@@ -46,10 +46,9 @@
 
 function c = namedargs2cell (s)
 
-  if (nargin != 1 || nargout > 1)
+  if (nargin < 1)
     print_usage ();
-  endif
-  if (! isstruct (s) || ! isscalar (s))
+  elseif (! isstruct (s) || ! isscalar (s))
     error ("namedargs2cell: S must be a scalar structure");
   endif
 
@@ -66,6 +65,6 @@
 
 ## Test input validation
 %!error <Invalid call> namedargs2cell ()
-%!error <Invalid call> namedargs2cell (1, 2)
+%!error <called with too many inputs> namedargs2cell (1, 2)
 %!error <S must be a scalar structure> namedargs2cell (true)
 %!error <S must be a scalar structure> namedargs2cell (struct ("name", {1, 2}))
--- a/scripts/miscellaneous/nargchk.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/nargchk.m	Thu Nov 19 13:08:00 2020 -0800
@@ -40,7 +40,7 @@
 
 function msg = nargchk (minargs, maxargs, nargs, outtype = "string")
 
-  if (nargin < 3 || nargin > 4)
+  if (nargin < 3)
     print_usage ();
   elseif (minargs > maxargs)
     error ("nargchk: MINARGS must be <= MAXARGS");
--- a/scripts/miscellaneous/narginchk.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/narginchk.m	Thu Nov 19 13:08:00 2020 -0800
@@ -43,7 +43,7 @@
 function narginchk (minargs, maxargs)
 
   if (nargin != 2)
-    print_usage;
+    print_usage ();
   elseif (! isnumeric (minargs) || ! isscalar (minargs))
     error ("narginchk: MINARGS must be a numeric scalar");
   elseif (! isnumeric (maxargs) || ! isscalar (maxargs))
--- a/scripts/miscellaneous/nargoutchk.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/nargoutchk.m	Thu Nov 19 13:08:00 2020 -0800
@@ -97,13 +97,13 @@
     args = evalin ("caller", "nargout;");
 
     if (args < minargs)
-      error ("nargoutchk: Not enough output arguments.");
+      error ("nargoutchk: Not enough output arguments");
     elseif (args > maxargs)
-      error ("nargoutchk: Too many output arguments.");
+      error ("nargoutchk: Too many output arguments");
     endif
 
   else
-    print_usage;
+    print_usage ();
   endif
 
 endfunction
--- a/scripts/miscellaneous/news.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/news.m	Thu Nov 19 13:08:00 2020 -0800
@@ -37,15 +37,11 @@
 
 function news (package = "octave")
 
-  if (nargin > 1)
-    print_usage ();
-  else
-    display_info_file ("news", package, "NEWS");
-  endif
+  ## function takes care of validating PACKAGE input
+  display_info_file ("news", package, "NEWS");
 
 endfunction
 
 
-%!error news (1, 2)
 %!error <news: PACKAGE must be a string> news (1)
 %!error <news: package .* is not installed> news ("__NOT_A_VALID_PKG_NAME__")
--- a/scripts/miscellaneous/open.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/open.m	Thu Nov 19 13:08:00 2020 -0800
@@ -73,7 +73,7 @@
 
 function output = open (file)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -131,6 +131,6 @@
 
 
 ## Test input validation
-%!error open ()
+%!error <Invalid call> open ()
 %!error open ("abc", "def")
 %!error <FILE must be a string> open (1)
--- a/scripts/miscellaneous/orderfields.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/orderfields.m	Thu Nov 19 13:08:00 2020 -0800
@@ -104,7 +104,7 @@
 
 function [sout, p] = orderfields (s1, s2)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -213,8 +213,7 @@
 %! assert (size_equal (s, s2));
 
 ## Test input validation
-%!error orderfields ()
-%!error orderfields (1,2,3)
+%!error <Invalid call> orderfields ()
 %!error <S1 must be a struct> orderfields (1)
 %!error <S1 and S2 do not have the same fields>
 %! s1.a = 1;
--- a/scripts/miscellaneous/private/display_info_file.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/private/display_info_file.m	Thu Nov 19 13:08:00 2020 -0800
@@ -40,7 +40,7 @@
     names     = cellfun (@(x) x.name, installed, "UniformOutput", false);
     pos       = strcmpi (names, package);
     if (! any (pos))
-      error ("%s: package '%s' is not installed.", func, package);
+      error ("%s: package '%s' is not installed", func, package);
     endif
     filepath = fullfile (installed{pos}.dir, "packinfo", file);
   endif
--- a/scripts/miscellaneous/private/tar_is_bsd.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/private/tar_is_bsd.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,9 +36,10 @@
 ## @end deftypefn
 
 function out = tar_is_bsd ()
+
   ## BSD tar needs to be handled differently from GNU tar
   persistent cache
-  if isempty (cache)
+  if (isempty (cache))
     [status, tar_ver_str] = system ("tar --version");
     if (status)
       error ("tar: Failed executing tar --version (status = %d)", status);
@@ -46,4 +47,5 @@
     cache = ! isempty (regexp (tar_ver_str, "bsdtar"));
   endif
   out = cache;
+
 endfunction
--- a/scripts/miscellaneous/publish.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/publish.m	Thu Nov 19 13:08:00 2020 -0800
@@ -209,7 +209,7 @@
   ## Check file to be in Octave's load path
   [file_path, file_name, file_ext] = fileparts (file);
   if (isempty (file_path))
-    file_path = pwd;
+    file_path = pwd ();
   endif
   if (exist ([file_name, file_ext]) != 2)
     error (["publish: " file " is not in the load path"]);
@@ -611,7 +611,7 @@
   ## Extract <html> and <latex> blocks recursively.
   content_str = strjoin (content, "\n");
   tags = {"html", "latex"};
-  for i = 1:length(tags)
+  for i = 1:length (tags)
     tok = regexp (content_str, ...
       ['(.*?)(^|\n\n)(<', tags{i}, '>)\n(.*?)\n(<\/', ...
         tags{i}, '>)($|\n\n)(.*)'], "tokens", "once");
@@ -709,6 +709,7 @@
     p_content{end+1}.type = "text";
     p_content{end}.content = strjoin (block, "\n");
   endfor
+
 endfunction
 
 
@@ -722,6 +723,7 @@
   until (! ischar (m_source{i}))
   fclose (fid);
   m_source = m_source(1:end-1);  # No EOL
+
 endfunction
 
 
@@ -770,6 +772,7 @@
       endfor
     endif
   endif
+
 endfunction
 
 
@@ -783,6 +786,7 @@
       toc_cstr{end+1} = format_text (cstr{i}.content, formatter);
     endif
   endfor
+
 endfunction
 
 
@@ -1067,6 +1071,7 @@
   ## Split string by lines and preserve blank lines.
   cstr = strsplit (strrep (cstr, "\n\n", "\n \n"), "\n");
   eval_context ("save");
+
 endfunction
 
 
@@ -1088,7 +1093,7 @@
       for i = 1:length (var_names)
         if (! any (strcmp (var_names{i}, forbidden_var_names)))
           ctext(var_names{i}) = evalin ("caller", var_names{i});
-        end
+        endif
       endfor
 
     case "load"
@@ -1107,13 +1112,14 @@
       ## Do nothing
 
   endswitch
+
 endfunction
 
 
 ## Note: Functional BIST tests are located in the 'test/publish' directory.
 
 ## Test input validation
-%!error publish ()
+%!error <Invalid call> publish ()
 %!error publish (1)
 %!error <FILE does not exist> publish ("%%_non_existent_file_%%.m")
 %!error <only script files can be published> publish ("publish.m")
--- a/scripts/miscellaneous/recycle.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/recycle.m	Thu Nov 19 13:08:00 2020 -0800
@@ -42,10 +42,6 @@
 
   persistent current_state = "off";
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   if (nargin == 0 || nargout > 0)
     val = current_state;
   endif
--- a/scripts/miscellaneous/run.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/run.m	Thu Nov 19 13:08:00 2020 -0800
@@ -47,7 +47,7 @@
 
 function run (script)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -114,7 +114,7 @@
 %!   assert (_5yVNhWVJWJn47RKnzxPsyb_, 1337);
 %! unwind_protect_cleanup
 %!   unlink (test_script);
-%!   rmdir (tmp_dir);
+%!   sts = rmdir (tmp_dir);
 %! end_unwind_protect
 
 ## Test function file execution
@@ -140,11 +140,11 @@
 %!   assert (tstval2, true);
 %! unwind_protect_cleanup
 %!   unlink (test_function);
-%!   rmdir (tmp_dir);
+%!   sts = rmdir (tmp_dir);
 %!   path (path_orig);
 %! end_unwind_protect
 
 ## Test input validation
-%!error run ()
+%!error <Invalid call> run ()
 %!error run ("a", "b")
 %!error <SCRIPT must exist> run ("__A_very_#unlikely#_file_name__")
--- a/scripts/miscellaneous/setfield.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/setfield.m	Thu Nov 19 13:08:00 2020 -0800
@@ -52,7 +52,7 @@
 ## the space character.  Using arbitrary strings for field names is
 ## incompatible with @sc{matlab}, and this usage will emit a warning if the
 ## warning ID @code{Octave:language-extension} is enabled.
-## @xref{XREFwarning_ids,,warning_ids}.
+## @xref{XREFwarning_ids,,@code{warning_ids}}.
 ##
 ## With the second calling form, set a field of a structure array.  The
 ## input @var{sidx} selects an element of the structure array, @var{field}
@@ -146,7 +146,7 @@
 %! assert (oo(1,2).fd(3).b(1,4), 6);
 
 ## Test input validation
-%!error setfield ()
-%!error setfield (1)
-%!error setfield (1,2)
+%!error <Invalid call> setfield ()
+%!error <Invalid call> setfield (1)
+%!error <Invalid call> setfield (1,2)
 %!error <invalid index> setfield (1,2,3)
--- a/scripts/miscellaneous/substruct.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/substruct.m	Thu Nov 19 13:08:00 2020 -0800
@@ -69,7 +69,7 @@
       error ("substruct: for TYPE == ., SUBS must be a character string");
     endif
   else
-    error ('substruct: TYPE must be one of "()", "{}", or "."');
+    error ('substruct: TYPE must be one of "()", "{}", or ""');
   endif
 
   retval = struct ("type", typ, "subs", sub);
@@ -87,8 +87,10 @@
 %! y = substruct ("()", {1,2,3}, "{}", {":"}, ".", "foo");
 %! assert (x,y);
 
-%!error substruct ()
-%!error substruct (1, 2, 3)
+## Test input validation
+%!error <Invalid call> substruct ()
+%!error <Invalid call> substruct (1)
+%!error <Invalid call> substruct (1, 2, 3)
 %!error substruct ("x", 1)
 %!error substruct ("()", [1,2,3])
 %!error substruct (".", {1,2,3})
--- a/scripts/miscellaneous/swapbytes.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/swapbytes.m	Thu Nov 19 13:08:00 2020 -0800
@@ -42,7 +42,7 @@
 
 function y = swapbytes (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -74,6 +74,5 @@
 %! assert (swapbytes (swapbytes (single (pi))), single (pi));
 
 ## Test input validation
-%!error swapbytes ()
-%!error swapbytes (1, 2)
+%!error <Invalid call> swapbytes ()
 %!error <invalid object of class 'cell'> swapbytes ({1})
--- a/scripts/miscellaneous/symvar.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/symvar.m	Thu Nov 19 13:08:00 2020 -0800
@@ -48,6 +48,7 @@
 
 function vars = symvar (str)
 
+  warning ("off", "Octave:legacy-function", "local");  # using inline below.
   vars = argnames (inline (str));
   ## Correct for auto-generated 'x' variable when no symvar was found.
   if (numel (vars) == 1 && strcmp (vars{1}, "x") && ! any (str == "x"))
@@ -58,5 +59,5 @@
 
 
 %!assert (symvar ("3*x + 4*y + 5*cos (z)"), {"x"; "y"; "z"})
-%!assert (symvar ("sin()^2 + cos()^2 == 1"), {})
+%!assert (symvar ("sin ()^2 + cos ()^2 == 1"), {})
 %!assert (symvar ("1./x"), {"x"})
--- a/scripts/miscellaneous/tar.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/tar.m	Thu Nov 19 13:08:00 2020 -0800
@@ -44,7 +44,7 @@
 
 function filelist = tar (tarfile, files, rootdir = ".")
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -72,7 +72,7 @@
   else
     cmd = sprintf ("tar cvf %s -C %s %s",
                             tarfile, rootdir, sprintf (" %s", files{:}));
-  end
+  endif
 
   ## Save and restore the TAR_OPTIONS environment variable used by GNU tar.
   tar_options_env = getenv ("TAR_OPTIONS");
@@ -133,7 +133,7 @@
 %!   if (! exist (tarname, "file"))
 %!     error ("tar archive file cannot be found!");
 %!   endif
-%!   outdir = tempname;
+%!   outdir = tempname ();
 %!   untar (tarname, outdir);
 %!   fid = fopen (fullfile (outdir, fname1), "rt");
 %!   assert (fid >= 0);
@@ -149,17 +149,12 @@
 %!   chdir (orig_dir);
 %!   unlink (tarname);
 %!   confirm_recursive_rmdir (false, "local");
-%!   if (exist (dirname))
-%!     rmdir (dirname, "s");
-%!   endif
-%!   if (exist (outdir))
-%!     rmdir (outdir, "s");
-%!   endif
+%!   sts = rmdir (dirname, "s");
+%!   sts = rmdir (outdir, "s");
 %! end_unwind_protect
 
 ## Test input validation
-%!error tar ()
-%!error tar (1)
-%!error tar (1,2,3,4)
+%!error <Invalid call> tar ()
+%!error <Invalid call> tar (1)
 %!error <TARFILE must be a string> tar (1, "foobar")
 %!error <FILES must be a character array or cellstr> tar ("foobar", 1)
--- a/scripts/miscellaneous/tempdir.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/tempdir.m	Thu Nov 19 13:08:00 2020 -0800
@@ -37,7 +37,7 @@
 
   dirname = getenv ("TMPDIR");
   if (isempty (dirname))
-    dirname = P_tmpdir;
+    dirname = P_tmpdir ();
   endif
 
   if (! strcmp (dirname(end), filesep))
--- a/scripts/miscellaneous/unix.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/unix.m	Thu Nov 19 13:08:00 2020 -0800
@@ -41,7 +41,7 @@
 
 function [status, text] = unix (command, echo_arg)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -71,5 +71,5 @@
 %!   assert (output, "");
 %! endif
 
-%!error unix ()
-%!error unix (1, 2, 3)
+## Test input validation
+%!error <Invalid call> unix ()
--- a/scripts/miscellaneous/unpack.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/unpack.m	Thu Nov 19 13:08:00 2020 -0800
@@ -78,7 +78,7 @@
 
 function filelist = unpack (file, dir = [], filetype = "")
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -372,7 +372,7 @@
 %!     unlink (filename);
 %!     unlink ([filename ".orig"]);
 %!     confirm_recursive_rmdir (false, "local");
-%!     rmdir (dirname, "s");
+%!     sts = rmdir (dirname, "s");
 %!   end_unwind_protect
 %! unwind_protect_cleanup
 %!   ## Restore environment variables TMPDIR, TMP
@@ -386,8 +386,7 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error unpack ()
-%!error unpack (1,2,3,4)
+%!error <Invalid call> unpack ()
 %!error <FILE must be a string or cell array of strings> unpack (1)
 %!error <FILE "_%NOT_A_FILENAME%_" not found> unpack ("_%NOT_A_FILENAME%_")
 %!error <FILE "_%NOT_A_FILENAME%_" not found> unpack ({"_%NOT_A_FILENAME%_"})
--- a/scripts/miscellaneous/untar.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/untar.m	Thu Nov 19 13:08:00 2020 -0800
@@ -38,7 +38,7 @@
 
 function filelist = untar (tarfile, dir = [])
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/unzip.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/unzip.m	Thu Nov 19 13:08:00 2020 -0800
@@ -38,7 +38,7 @@
 
 function filelist = unzip (zipfile, dir = [])
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/validateattributes.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/validateattributes.m	Thu Nov 19 13:08:00 2020 -0800
@@ -424,7 +424,7 @@
   num_pos = strcmpi (cls, name);
   if (any (num_pos))
     cls(num_pos) = [];
-    cls(end+1:end+numel(group)) = group;
+    cls(end+1:end+numel (group)) = group;
   endif
 endfunction
 
--- a/scripts/miscellaneous/ver.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/ver.m	Thu Nov 19 13:08:00 2020 -0800
@@ -58,10 +58,6 @@
 
 function retval = ver (package = "")
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   if (nargout == 0)
     hg_id = __octave_config_info__ ("hg_id");
 
--- a/scripts/miscellaneous/verLessThan.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/verLessThan.m	Thu Nov 19 13:08:00 2020 -0800
@@ -83,7 +83,7 @@
 %!assert (verLessThan ("Octave", "99.9.9"))
 
 ## Test input validation
-%!error verLessThan ()
+%!error <Invalid call> verLessThan ()
 %!error verLessThan ("a")
 %!error verLessThan ("a", "1", "b")
 %!error <package "no-such-package" is not installed>
--- a/scripts/miscellaneous/version.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/version.m	Thu Nov 19 13:08:00 2020 -0800
@@ -72,7 +72,7 @@
 
 function [v, d] = version (feature)
 
-  if (nargin > 1 || ((nargin != 0) && ((nargout > 1) || ! ischar (feature))))
+  if (nargin == 1 && (nargout > 1 || ! ischar (feature)))
     print_usage ();
   endif
 
@@ -81,7 +81,7 @@
 
     if (nargout > 1)
       d = __octave_config_info__ ("release_date");
-    end
+    endif
   else
     switch (lower (feature))
       case "-date"
--- a/scripts/miscellaneous/what.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/what.m	Thu Nov 19 13:08:00 2020 -0800
@@ -73,10 +73,6 @@
 
 function retval = what (dir)
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   if (nargin == 0)
     dir = { pwd() };
   else
@@ -109,7 +105,7 @@
    if (numel (dir) == 0)
      w = __what__ ("");
      w = resize (w, [0, 1]);  # Matlab compatibility, return 0x1 empty array
-   end
+   endif
 
   if (nargout == 0)
     for i = 1 : numel (w)
--- a/scripts/miscellaneous/zip.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/miscellaneous/zip.m	Thu Nov 19 13:08:00 2020 -0800
@@ -44,7 +44,7 @@
 
 function filelist = zip (zipfile, files, rootdir = ".")
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -126,16 +126,15 @@
 %!     error ("unzipped file not equal to original file!");
 %!   endif
 %! unwind_protect_cleanup
-%!   unlink (filename);
-%!   unlink ([dirname, filesep, basename, ext]);
-%!   unlink (zipfile);
-%!   unlink ([zipfile ".zip"]);
-%!   rmdir (dirname);
+%!   sts = unlink (filename);
+%!   sts = unlink ([dirname, filesep, basename, ext]);
+%!   sts = unlink (zipfile);
+%!   sts = unlink ([zipfile ".zip"]);
+%!   sts = rmdir (dirname);
 %! end_unwind_protect
 
 ## Test input validation
-%!error zip ()
-%!error zip (1)
-%!error zip (1,2,3,4)
+%!error <Invalid call> zip ()
+%!error <Invalid call> zip (1)
 %!error <ZIPFILE must be a string> zip (1, "foobar")
 %!error <FILES must be a character array or cellstr> zip ("foobar", 1)
--- a/scripts/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -6,6 +6,7 @@
 
 include %reldir%/+containers/module.mk
 include %reldir%/+matlab/+lang/module.mk
+include %reldir%/+matlab/+net/module.mk
 include %reldir%/audio/module.mk
 include %reldir%/deprecated/module.mk
 include %reldir%/elfun/module.mk
@@ -49,6 +50,9 @@
 ######################## include %reldir%/@ftp/module.mk ########################
 FCN_FILE_DIRS += %reldir%/@ftp
 
+%canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config
+
 %canon_reldir%_@ftp_FCN_FILES = \
   %reldir%/@ftp/ascii.m \
   %reldir%/@ftp/binary.m  \
@@ -70,7 +74,9 @@
 
 %canon_reldir%_@ftp_DATA = $(%canon_reldir%_@ftp_FCN_FILES)
 
-FCN_FILES += $(%canon_reldir%_@ftp_FCN_FILES)
+FCN_FILES += \
+  $(%canon_reldir%_FCN_FILES) \
+  $(%canon_reldir%_@ftp_FCN_FILES)
 
 PKG_ADD_FILES += %reldir%/@ftp/PKG_ADD
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/ode/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/ode/decic.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/ode/decic.m	Thu Nov 19 13:08:00 2020 -0800
@@ -97,7 +97,7 @@
                                              y0, fixed_y0, yp0, fixed_yp0,
                                              options)
 
-  if (nargin < 6 || nargin > 7)
+  if (nargin < 6)
     print_usage ();
   endif
 
@@ -215,13 +215,12 @@
 %! assert ([ynew(1:end), ypnew(1:end)], [ref1(1:end), ref2(1:end)], 1e-5);
 
 ## Test input validation
-%!error decic ()
-%!error decic (1)
-%!error decic (1,2)
-%!error decic (1,2,3)
-%!error decic (1,2,3,4)
-%!error decic (1,2,3,4,5)
-%!error decic (1,2,3,4,5,6,7,8)
+%!error <Invalid call> decic ()
+%!error <Invalid call> decic (1)
+%!error <Invalid call> decic (1,2)
+%!error <Invalid call> decic (1,2,3)
+%!error <Invalid call> decic (1,2,3,4)
+%!error <Invalid call> decic (1,2,3,4,5)
 %!error <FUN must be a valid function handle>
 %! decic (1, 0, [1; 0; 0], [1; 1; 0], [-1e-4; 1; 0], [0; 0; 0]);
 %!error <T0 must be a numeric scalar>
--- a/scripts/ode/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/ode/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -17,6 +17,7 @@
   %reldir%/private/starting_stepsize.m
 
 %canon_reldir%_FCN_FILES =  \
+  %reldir%/.oct-config \
   %reldir%/decic.m \
   %reldir%/ode15i.m \
   %reldir%/ode15s.m \
--- a/scripts/ode/ode15i.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/ode/ode15i.m	Thu Nov 19 13:08:00 2020 -0800
@@ -261,13 +261,13 @@
     varargout{1} = t;
     varargout{2} = y;
   elseif (nargout == 1)
-    varargout{1}.x = t;  # Time stamps are saved in field x
-    varargout{1}.y = y;  # Results are saved in field y
+    varargout{1}.x = t.';  # Time stamps saved in field x (row vector)
+    varargout{1}.y = y.';  # Results are saved in field y (row vector)
     varargout{1}.solver = solver;
     if (options.haveeventfunction)
-      varargout{1}.xe = te;  # Time info when an event occurred
-      varargout{1}.ye = ye;  # Results when an event occurred
-      varargout{1}.ie = ie;  # Index info which event occurred
+      varargout{1}.xe = te.';  # Time info when an event occurred
+      varargout{1}.ye = ye.';  # Results when an event occurred
+      varargout{1}.ie = ie.';  # Index info which event occurred
     endif
   elseif (nargout > 2)
     varargout = cell (1,5);
@@ -388,11 +388,11 @@
 
 ## With empty options
 %!testif HAVE_SUNDIALS
-%! opt = odeset();
+%! opt = odeset ();
 %! [t, y] = ode15i (@rob, [0, 1e6, 2e6, 3e6, 4e6], [1; 0; 0],
 %!                  [-1e-4; 1e-4; 0], opt);
 %! assert ([t(end), y(end,:)], fref2, 1e-3);
-%! opt = odeset();
+%! opt = odeset ();
 
 ## Without options
 %!testif HAVE_SUNDIALS
@@ -504,7 +504,7 @@
 %! opt = odeset ("Events", @ff);
 %! sol = ode15i (@rob, [0, 100], [1; 0; 0], [-1e-4; 1e-4; 0], opt);
 %! assert (isfield (sol, "ie"));
-%! assert (sol.ie, [0;1]);
+%! assert (sol.ie, [1, 2]);
 %! assert (isfield (sol, "xe"));
 %! assert (isfield (sol, "ye"));
 %! assert (sol.x(end), 10, 1);
@@ -514,20 +514,22 @@
 %! opt = odeset ("Events", @ff);
 %! [t, y, te, ye, ie] = ode15i (@rob, [0, 100], [1; 0; 0],
 %!                              [-1e-4; 1e-4; 0], opt);
-%! assert ([t(end), te', ie'], [10, 10, 10, 0, 1], [1, 0.2, 0.2, 0, 0]);
+%! assert (t(end), 10, 1);
+%! assert (te, [10; 10], 0.2);
+%! assert (ie, [1; 2]);
 
 ## Initial solutions as row vectors
 %!testif HAVE_SUNDIALS
 %! A = eye (2);
 %! [tout, yout] = ode15i (@(t, y, yp) A * y - A * yp, ...
 %! [0, 1], [1, 1], [1, 1]);
-%! assert (size (yout), [20, 2])
+%! assert (size (yout), [20, 2]);
 
 %!testif HAVE_SUNDIALS
 %! A = eye (2);
 %! [tout, yout] = ode15i (@(t, y, yp) A * y - A * yp, ...
 %! [0, 1], [1, 1], [1; 1]);
-%! assert (size (yout), [20, 2])
+%! assert (size (yout), [20, 2]);
 
 ## Jacobian fun wrong dimension
 %!testif HAVE_SUNDIALS
--- a/scripts/ode/ode15s.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/ode/ode15s.m	Thu Nov 19 13:08:00 2020 -0800
@@ -270,7 +270,7 @@
                                                   options.havetimedep,
                                                   options.havejacfun);
       options.havejacfun = true;
-    else   ## All matrices are constant
+    else   # All matrices are constant
       options.Jacobian = {[- options.Jacobian], [options.Mass]};
 
     endif
@@ -322,13 +322,13 @@
     varargout{1} = t;
     varargout{2} = y;
   elseif (nargout == 1)
-    varargout{1}.x = t;  # Time stamps are saved in field x
-    varargout{1}.y = y;  # Results are saved in field y
+    varargout{1}.x = t.';  # Time stamps saved in field x (row vector)
+    varargout{1}.y = y.';  # Results are saved in field y (row vector)
     varargout{1}.solver = solver;
     if (options.haveeventfunction)
-      varargout{1}.xe = te;  # Time info when an event occurred
-      varargout{1}.ye = ye;  # Results when an event occurred
-      varargout{1}.ie = ie;  # Index info which event occurred
+      varargout{1}.xe = te.';  # Time info when an event occurred
+      varargout{1}.ye = ye.';  # Results when an event occurred
+      varargout{1}.ie = ie.';  # Index info which event occurred
     endif
   elseif (nargout > 2)
     varargout = cell (1,5);
@@ -433,7 +433,7 @@
 %!  refrob = [100, 0.617234887614937, 0.000006153591397, 0.382758958793666];
 %!endfunction
 %!
-%!function [val, isterminal, direction] = feve (t, y)
+%!function [val, isterminal, direction] = feve (t, y, ~)
 %!  isterminal = [0, 1];
 %!  if (t < 1e1)
 %!    val = [-1, -2];
@@ -467,9 +467,9 @@
 %!endfunction
 %!
 %!function jac = jacfunsparse (t, y)
-%!  jac = sparse([-0.04,           1e4*y(3),  1e4*y(2);
-%!                 0.04, -1e4*y(3)-6e7*y(2), -1e4*y(2);
-%!                    1,                  1,         1]);
+%!  jac = sparse ([-0.04,           1e4*y(3),  1e4*y(2);
+%!                  0.04, -1e4*y(3)-6e7*y(2), -1e4*y(2);
+%!                     1,                  1,         1]);
 %!endfunction
 
 %!testif HAVE_SUNDIALS
@@ -619,77 +619,77 @@
 
 ## Solve in backward direction starting at t=0
 %!testif HAVE_SUNDIALS
-%! ref = [-1.205364552835178, 0.951542399860817];
+%! ref = [-1.205364552835178; 0.951542399860817];
 %! sol = ode15s (@fpol, [0 -2], [2, 0]);
-%! assert ([sol.x(end), sol.y(end,:)], [-2, ref], 5e-3);
+%! assert ([sol.x(end); sol.y(:,end)], [-2; ref], 5e-3);
 
 ## Solve in backward direction starting at t=2
 %!testif HAVE_SUNDIALS
-%! ref = [-1.205364552835178, 0.951542399860817];
+%! ref = [-1.205364552835178; 0.951542399860817];
 %! sol = ode15s (@fpol, [2, 0 -2], fref);
-%! assert ([sol.x(end), sol.y(end,:)], [-2, ref], 3e-2);
+%! assert ([sol.x(end); sol.y(:,end)], [-2; ref], 3e-2);
 
 ## Solve another anonymous function in backward direction
 %!testif HAVE_SUNDIALS
-%! ref = [-1, 0.367879437558975];
+%! ref = [-1; 0.367879437558975];
 %! sol = ode15s (@(t,y) y, [0 -1], 1);
-%! assert ([sol.x(end), sol.y(end,:)], ref, 1e-2);
+%! assert ([sol.x(end); sol.y(:,end)], ref, 1e-2);
 
 ## Solve another anonymous function below zero
 %!testif HAVE_SUNDIALS
-%! ref = [0, 14.77810590694212];
+%! ref = [0; 14.77810590694212];
 %! sol = ode15s (@(t,y) y, [-2, 0], 2);
-%! assert ([sol.x(end), sol.y(end,:)], ref, 5e-2);
+%! assert ([sol.x(end); sol.y(:,end)], ref, 5e-2);
 
 ## Solve in backward direction starting at t=0 with MaxStep option
 %!testif HAVE_SUNDIALS
-%! ref = [-1.205364552835178, 0.951542399860817];
+%! ref = [-1.205364552835178; 0.951542399860817];
 %! opt = odeset ("MaxStep", 1e-3);
 %! sol = ode15s (@fpol, [0 -2], [2, 0], opt);
 %! assert (abs (sol.x(8)-sol.x(7)), 1e-3, 1e-3);
-%! assert ([sol.x(end), sol.y(end,:)], [-2, ref], 1e-3);
+%! assert ([sol.x(end); sol.y(:,end)], [-2; ref], 1e-3);
 
 ## AbsTol option
 %!testif HAVE_SUNDIALS
 %! opt = odeset ("AbsTol", 1e-5);
 %! sol = ode15s (@fpol, [0, 2], [2, 0], opt);
-%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 4e-3);
+%! assert ([sol.x(end); sol.y(:,end)], [2, fref].', 4e-3);
 
 ## AbsTol and RelTol option
 %!testif HAVE_SUNDIALS
 %! opt = odeset ("AbsTol", 1e-8, "RelTol", 1e-8);
 %! sol = ode15s (@fpol, [0, 2], [2, 0], opt);
-%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 1e-3);
+%! assert ([sol.x(end); sol.y(:,end)], [2, fref].', 1e-3);
 
 ## RelTol option -- higher accuracy
 %!testif HAVE_SUNDIALS
 %! opt = odeset ("RelTol", 1e-8);
 %! sol = ode15s (@fpol, [0, 2], [2, 0], opt);
-%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 1e-4);
+%! assert ([sol.x(end); sol.y(:,end)], [2, fref].', 1e-4);
 
 ## Mass option as function
 %!testif HAVE_SUNDIALS
 %! opt = odeset ("Mass", @fmas, "MStateDependence", "none");
 %! sol = ode15s (@fpol, [0, 2], [2, 0], opt);
-%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 3e-3);
+%! assert ([sol.x(end); sol.y(:,end)], [2, fref].', 3e-3);
 
 ## Mass option as matrix
 %!testif HAVE_SUNDIALS
 %! opt = odeset ("Mass", eye (2,2), "MStateDependence", "none");
 %! sol = ode15s (@fpol, [0, 2], [2, 0], opt);
-%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 3e-3);
+%! assert ([sol.x(end); sol.y(:,end)], [2, fref].', 3e-3);
 
 ## Mass option as sparse matrix
 %!testif HAVE_SUNDIALS
 %! opt = odeset ("Mass", speye (2), "MStateDependence", "none");
 %! sol = ode15s (@fpol, [0, 2], [2, 0], opt);
-%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 3e-3);
+%! assert ([sol.x(end); sol.y(:,end)], [2, fref].', 3e-3);
 
 ## Mass option as function and sparse matrix
 %!testif HAVE_SUNDIALS
 %! opt = odeset ("Mass", "fmsa", "MStateDependence", "none");
 %! sol = ode15s (@fpol, [0, 2], [2, 0], opt);
-%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 3e-3);
+%! assert ([sol.x(end); sol.y(:,end)], [2, fref].', 3e-3);
 
 ## Refine
 %!testif HAVE_SUNDIALS
@@ -715,7 +715,7 @@
 %!               "MStateDependence", "none");
 %! sol = ode15s (@rob, [0, 100], [1; 0; 0], opt);
 %! assert (isfield (sol, "ie"));
-%! assert (sol.ie, [0;1]);
+%! assert (sol.ie, [1, 2]);
 %! assert (isfield (sol, "xe"));
 %! assert (isfield (sol, "ye"));
 %! assert (sol.x(end), 10, 1);
@@ -725,13 +725,15 @@
 %! opt = odeset ("Events", @feve, "Mass", @massdensefunstate,
 %!               "MStateDependence", "none");
 %! [t, y, te, ye, ie] = ode15s (@rob, [0, 100], [1; 0; 0], opt);
-%! assert ([t(end), te', ie'], [10, 10, 10, 0, 1], [1, 0.5, 0.5, 0, 0]);
+%! assert (t(end), 10, 1);
+%! assert (te, [10; 10], 0.5);
+%! assert (ie, [1; 2]);
 
 ## Initial solution as row vector
 %!testif HAVE_SUNDIALS
 %! A = zeros (2);
 %! [tout, yout] = ode15s (@(t, y) A * y, [0, 1], [1, 1]);
-%! assert (yout, ones (18, 2))
+%! assert (yout, ones (18, 2));
 
 %!testif HAVE_SUNDIALS
 %! A = zeros (2);
--- a/scripts/ode/ode23.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/ode/ode23.m	Thu Nov 19 13:08:00 2020 -0800
@@ -326,19 +326,19 @@
 
 ## We are using the Van der Pol equation for all tests.
 ## Further tests also define a reference solution (computed at high accuracy)
-%!function ydot = fpol (t, y)  # The Van der Pol ODE
+%!function ydot = fpol (t, y, varargin)  # The Van der Pol ODE
 %!  ydot = [y(2); (1 - y(1)^2) * y(2) - y(1)];
 %!endfunction
 %!function ref = fref ()       # The computed reference sol
 %!  ref = [0.32331666704577, -1.83297456798624];
 %!endfunction
 %!function [val, trm, dir] = feve (t, y, varargin)
-%!  val = fpol (t, y, varargin);  # We use the derivatives
+%!  val = fpol (t, y, varargin{:});  # We use the derivatives
 %!  trm = zeros (2,1);            # that's why component 2
 %!  dir = ones (2,1);             # does not seem to be exact
 %!endfunction
 %!function [val, trm, dir] = fevn (t, y, varargin)
-%!  val = fpol (t, y, varargin);  # We use the derivatives
+%!  val = fpol (t, y, varargin{:});  # We use the derivatives
 %!  trm = ones (2,1);             # that's why component 2
 %!  dir = ones (2,1);             # does not seem to be exact
 %!endfunction
@@ -378,7 +378,7 @@
 %! [t, y] = ode23 (@fpol, [0 2], [2 0], 12, 13, "KL");
 %! assert ([t(end), y(end,:)], [2, fref], 1e-3);
 %!test  # empty OdePkg structure *but* extra input arguments
-%! opt = odeset;
+%! opt = odeset ();
 %! [t, y] = ode23 (@fpol, [0 2], [2 0], opt, 12, 13, "KL");
 %! assert ([t(end), y(end,:)], [2, fref], 1e-2);
 %!test  # Solve another anonymous function below zero
@@ -426,7 +426,7 @@
 %!test # hermite_cubic_interpolation
 %! opt = odeset ("RelTol", 1e-8, "NormControl", "on");
 %! [t,sol] = ode23(@(t,x)[x(2);x(1)],linspace(0,1),[1;0],opt);
-%! assert(max(abs(sol(:,1)-cosh(t))),0,1e-6)
+%! assert (max (abs (sol(:,1)-cosh (t))),0,1e-6);
 %!test  # RelTol and NormControl option -- higher accuracy
 %! opt = odeset ("RelTol", 1e-8, "NormControl", "on");
 %! sol = ode23 (@fpol, [0 2], [2 0], opt);
@@ -497,14 +497,14 @@
 
 %!test # Check that imaginary part of solution does not get inverted
 %! sol = ode23 (@(x,y) 1, [0 1], 1i);
-%! assert (imag (sol.y), ones (size (sol.y)))
+%! assert (imag (sol.y), ones (size (sol.y)));
 %! [x, y] = ode23 (@(x,y) 1, [0 1], 1i);
-%! assert (imag (y), ones (size (y)))
+%! assert (imag (y), ones (size (y)));
 
 ## Test input validation
-%!error ode23 ()
-%!error ode23 (1)
-%!error ode23 (1,2)
+%!error <Invalid call> ode23 ()
+%!error <Invalid call> ode23 (1)
+%!error <Invalid call> ode23 (1,2)
 %!error <TRANGE must be a numeric> ode23 (@fpol, {[0 25]}, [3 15 1])
 %!error <TRANGE must be a .* vector> ode23 (@fpol, [0 25; 25 0], [3 15 1])
 %!error <TRANGE must contain at least 2 elements> ode23 (@fpol, [1], [3 15 1])
--- a/scripts/ode/ode23s.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/ode/ode23s.m	Thu Nov 19 13:08:00 2020 -0800
@@ -283,7 +283,7 @@
 %! [vt, vy] = ode23s (fun, [0 20], [2 0]);
 %! toc ()
 %! ## Plotting the result
-%! plot(vt,vy(:,1),'-o');
+%! plot (vt,vy(:,1),'-o');
 
 %!demo
 %! ## Demo function: stiff Van Der Pol equation
@@ -295,7 +295,7 @@
 %! [vt, vy] = ode23s (fun, [0 20], [2 0], odeopts);
 %! toc ()
 %! ## Plotting the result
-%! plot(vt,vy(:,1),'-o');
+%! plot (vt,vy(:,1),'-o');
 
 %!demo
 %! ## Demo function: stiff Van Der Pol equation
@@ -306,7 +306,7 @@
 %! [vt, vy] = ode23s (fun, [0 200], [2 0]);
 %! toc ()
 %! ## Plotting the result
-%! plot(vt,vy(:,1),'-o');
+%! plot (vt,vy(:,1),'-o');
 
 %!demo
 %! ## Demo function: stiff Van Der Pol equation
@@ -318,7 +318,7 @@
 %! [vt, vy] = ode23s (fun, [0 200], [2 0], odeopts);
 %! toc ()
 %! ## Plotting the result
-%! plot(vt,vy(:,1),'-o');
+%! plot (vt,vy(:,1),'-o');
 
 %!demo
 %! ## Demonstrate convergence order for ode23s
@@ -357,7 +357,7 @@
 ## We are using the "Van der Pol" implementation for all tests that are done
 ## for this function.  For further tests we also define a reference solution
 ## (computed at high accuracy).
-%!function ydot = fpol (t, y)  # The Van der Pol ODE
+%!function ydot = fpol (t, y, varargin)  # The Van der Pol ODE
 %!  ydot = [y(2); 10 * (1 - y(1)^2) * y(2) - y(1)];
 %!endfunction
 %!function ydot = jac (t, y)   # The Van der Pol ODE
@@ -367,12 +367,12 @@
 %!  ref = [1.8610687248524305  -0.0753216319179125];
 %!endfunction
 %!function [val, trm, dir] = feve (t, y, varargin)
-%!  val = fpol (t, y, varargin);  # We use the derivatives
+%!  val = fpol (t, y, varargin{:});  # We use the derivatives
 %!  trm = zeros (2,1);            # that's why component 2
 %!  dir = ones (2,1);             # does not seem to be exact
 %!endfunction
 %!function [val, trm, dir] = fevn (t, y, varargin)
-%!  val = fpol (t, y, varargin);  # We use the derivatives
+%!  val = fpol (t, y, varargin{:});  # We use the derivatives
 %!  trm = ones (2,1);             # that's why component 2
 %!  dir = ones (2,1);             # does not seem to be exact
 %!endfunction
@@ -412,7 +412,7 @@
 %! [t, y] = ode23s (@fpol, [0 2], [2 0], 12, 13, "KL");
 %! assert ([t(end), y(end,:)], [2, fref], 1e-3);
 %!test  # empty OdePkg structure *but* extra input arguments
-%! opt = odeset;
+%! opt = odeset ();
 %! [t, y] = ode23s (@fpol, [0 2], [2 0], opt, 12, 13, "KL");
 %! assert ([t(end), y(end,:)], [2, fref], 1e-2);
 %!test  # InitialStep option
@@ -495,14 +495,14 @@
 
 %!test # Check that imaginary part of solution does not get inverted
 %! sol = ode23s (@(x,y) 1, [0 1], 1i);
-%! assert (imag (sol.y), ones (size (sol.y)))
+%! assert (imag (sol.y), ones (size (sol.y)));
 %! [x, y] = ode23s (@(x,y) 1, [0 1], 1i);
-%! assert (imag (y), ones (size (y)))
+%! assert (imag (y), ones (size (y)));
 
 ## Test input validation
-%!error ode23s ()
-%!error ode23s (1)
-%!error ode23s (1,2)
+%!error <Invalid call> ode23s ()
+%!error <Invalid call> ode23s (1)
+%!error <Invalid call> ode23s (1,2)
 %!error <TRANGE must be a numeric> ode23s (@fpol, {[0 25]}, [3 15 1])
 %!error <TRANGE must be a .* vector> ode23s (@fpol, [0 25; 25 0], [3 15 1])
 %!error <TRANGE must contain at least 2 elements> ode23s (@fpol, [1], [3 15 1])
--- a/scripts/ode/ode45.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/ode/ode45.m	Thu Nov 19 13:08:00 2020 -0800
@@ -326,19 +326,19 @@
 
 ## We are using the Van der Pol equation for all tests.
 ## Further tests also define a reference solution (computed at high accuracy)
-%!function ydot = fpol (t, y)  # The Van der Pol ODE
+%!function ydot = fpol (t, y, varargin)  # The Van der Pol ODE
 %!  ydot = [y(2); (1 - y(1)^2) * y(2) - y(1)];
 %!endfunction
 %!function ref = fref ()       # The computed reference solution
 %!  ref = [0.32331666704577, -1.83297456798624];
 %!endfunction
 %!function [val, trm, dir] = feve (t, y, varargin)
-%!  val = fpol (t, y, varargin);  # We use the derivatives
+%!  val = fpol (t, y, varargin{:});  # We use the derivatives
 %!  trm = zeros (2,1);            # that's why component 2
 %!  dir = ones (2,1);             # does not seem to be exact
 %!endfunction
 %!function [val, trm, dir] = fevn (t, y, varargin)
-%!  val = fpol (t, y, varargin);  # We use the derivatives
+%!  val = fpol (t, y, varargin{:});  # We use the derivatives
 %!  trm = ones (2,1);             # that's why component 2
 %!  dir = ones (2,1);             # does not seem to be exact
 %!endfunction
@@ -401,7 +401,7 @@
 %! assert ([sol.x(5)-sol.x(4)], [1e-3], 1e-3);
 %!test  # Solve with intermediate step
 %! [t, y] = ode45 (@fpol, [0 1 2], [2 0]);
-%! assert (any((t-1) == 0));
+%! assert (any ((t-1) == 0));
 %! assert ([t(end), y(end,:)], [2, fref], 1e-3);
 %!test  # Solve in backward direction starting at t=0
 %! vref = [-1.205364552835178, 0.951542399860817];
@@ -414,7 +414,7 @@
 %!test  # Solve in backward direction starting at t=2, with intermediate step
 %! vref = [-1.205364552835178, 0.951542399860817];
 %! [t, y] = ode45 (@fpol, [2 0 -2], fref);
-%! idx = find(y < 0, 1, "first") - 1;
+%! idx = find (y < 0, 1, "first") - 1;
 %! assert ([t(idx), y(idx,:)], [0,2,0], 1e-2);
 %! assert ([t(end), y(end,:)], [-2, vref], 1e-2);
 %!test  # Solve another anonymous function in backward direction
@@ -510,13 +510,13 @@
 
 %!test # Check that imaginary part of solution does not get inverted
 %! sol = ode45 (@(x,y) 1, [0 1], 1i);
-%! assert (imag (sol.y), ones (size (sol.y)))
+%! assert (imag (sol.y), ones (size (sol.y)));
 %! [x, y] = ode45 (@(x,y) 1, [0 1], 1i);
-%! assert (imag (y), ones (size (y)))
+%! assert (imag (y), ones (size (y)));
 
-%!error ode45 ()
-%!error ode45 (1)
-%!error ode45 (1,2)
+%!error <Invalid call> ode45 ()
+%!error <Invalid call> ode45 (1)
+%!error <Invalid call> ode45 (1,2)
 %!error <TRANGE must be a numeric> ode45 (@fpol, {[0 25]}, [3 15 1])
 %!error <TRANGE must be a .* vector> ode45 (@fpol, [0 25; 25 0], [3 15 1])
 %!error <TRANGE must contain at least 2 elements> ode45 (@fpol, [1], [3 15 1])
--- a/scripts/ode/odeget.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/ode/odeget.m	Thu Nov 19 13:08:00 2020 -0800
@@ -43,6 +43,10 @@
 
 function val = odeget (ode_opt, field, default = [])
 
+  if (nargin < 2)
+    print_usage ();
+  endif
+
   validateattributes (ode_opt, {"struct"}, {"nonempty"});
   validateattributes (field, {"char"}, {"nonempty"});
 
@@ -79,9 +83,9 @@
 %! warning ("off", "Octave:invalid-input-arg", "local");
 %! assert (odeget (odeset ("foo", 42), "foo"), 42);
 
-%!error odeget ()
-%!error odeget (1)
-%!error odeget (1,2,3,4,5)
+## Test input validation
+%!error <Invalid call> odeget ()
+%!error <Invalid call> odeget (1)
 %!error odeget (1, "opt1")
 %!error odeget (struct ("opt1", 1), 1)
 %!error odeget (struct ("opt1", 1), "foo")
--- a/scripts/ode/odeplot.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/ode/odeplot.m	Thu Nov 19 13:08:00 2020 -0800
@@ -91,7 +91,7 @@
     for i = 1:num_lines
       set (hlines(i), "xdata", told, "ydata", yold(i,:));
     endfor
-    drawnow;
+    drawnow ();
 
     retval = false;
 
--- a/scripts/ode/odeset.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/ode/odeset.m	Thu Nov 19 13:08:00 2020 -0800
@@ -119,7 +119,7 @@
 ##
 ## @item @code{OutputFcn}: function_handle
 ## Function to monitor the state during the simulation.  For the form of
-## the function to use see @code{odeplot}.
+## the function to use @pxref{XREFodeplot,,@code{odeplot}}.
 ##
 ## @item @code{OutputSel}: scalar | vector
 ## Indices of elements of the state vector to be passed to the output
--- a/scripts/ode/private/check_default_input.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/ode/private/check_default_input.m	Thu Nov 19 13:08:00 2020 -0800
@@ -23,7 +23,11 @@
 ##
 ########################################################################
 
-function [fun] = check_default_input (fun, trange, solver, varargin);
+function fun = check_default_input (fun, trange, solver, y0, yp0);
+
+  if (nargin < 4)
+    print_usage ();
+  endif
 
   ## Check fun
   validateattributes (fun, {"function_handle", "char"}, {}, solver, "fun");
@@ -57,7 +61,6 @@
   endif
 
   ## Check y0 and yp0
-  y0 = varargin{1};
   if (! isnumeric (y0) || ! isvector (y0))
     error ("Octave:invalid-input-arg",
            [solver ": Y0 must be a numeric vector"]);
@@ -65,7 +68,6 @@
   y0 = y0(:);
 
   if (nargin == 5)
-    yp0 = varargin{2};
     if (! isnumeric (yp0) || ! isvector (yp0))
       error ("Octave:invalid-input-arg",
              [solver ": YP0 must be a numeric vector"]);
--- a/scripts/ode/private/odemergeopts.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/ode/private/odemergeopts.m	Thu Nov 19 13:08:00 2020 -0800
@@ -23,8 +23,12 @@
 ##
 ########################################################################
 
+## FIXME: there are some calls to odemergeopts with a "solver" argument
+## but we don't use that here.  Should the calls be fixed or should we
+## do something with the solver argument here?
+
 function options = odemergeopts (caller, useroptions, options, classes,
-                                 attributes);
+                                 attributes, solver);
 
   for [value, key] = options
 
--- a/scripts/ode/private/runge_kutta_23s.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/ode/private/runge_kutta_23s.m	Thu Nov 19 13:08:00 2020 -0800
@@ -128,7 +128,7 @@
   endif
   W = M - dt*d*J;
 
-  if issparse (W)
+  if (issparse (W))
     [Lw, Uw, Pw, Qw, Rw] = lu  (W);
   else
     [Lw, Uw, Pw] = lu (W);
@@ -136,13 +136,13 @@
 
   ## compute the slopes
   F(:,1) = feval (fun, t, x, args{:});
-  if issparse (W)
+  if (issparse (W))
     k(:,1) = Qw * (Uw \ (Lw \ (Pw * (Rw \ (F(:,1) + dt*d*T)))));
   else
     k(:,1) = Uw \ (Lw \ (Pw * (F(:,1) + dt*d*T)));
   endif
   F(:,2) = feval (fun, t+a*dt, x+a*dt*k(:,1), args{:});
-  if issparse (W)
+  if (issparse (W))
     k(:,2) = Uw * (Uw \ (Lw \ (Pw * (Rw \ (F(:,2) - M*k(:,1)))))) + k(:,1);
   else
     k(:,2) = Uw \ (Lw \ (Pw * (F(:,2) - M*k(:,1)))) + k(:,1);
@@ -154,7 +154,7 @@
   if (nargout >= 3)
     ## 3rd order, needed in error formula
     F(:,3) = feval (fun, t+dt, x_next, args{:});
-    if issparse (W)
+    if (issparse (W))
       k(:,3) = Qw * (Uw \ (Lw \ (Pw * (Rw \ (F(:,3) - e32 * (M*k(:,2) - F(:,2)) - 2 * (M*k(:,1) - F(:,1)) + dt*d*T)))));
     else
       k(:,3) = Uw \ (Lw \ (Pw * (F(:,3) - e32 * (M*k(:,2) - F(:,2)) - 2 * (M*k(:,1) - F(:,1)) + dt*d*T)));
--- a/scripts/ode/private/runge_kutta_interpolate.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/ode/private/runge_kutta_interpolate.m	Thu Nov 19 13:08:00 2020 -0800
@@ -60,12 +60,12 @@
 ## at the time t_out using 2nd order Hermite interpolation.
 function x_out = quadratic_interpolation (t, x, der, t_out)
 
-  # coefficients of the parabola
+  ## coefficients of the parabola
   a = -(x(:,1) - x(:,2) - der(:).*(t(1)-t(2))) / (t(1) - t(2))^2;
   b = der(:) - 2*t(1).*a;
   c = x(:,1) - a*t(1)^2 - b*t(1);
 
-  # evaluate in t_out
+  ## evaluate in t_out
   x_out = a*t_out.^2 + b*t_out + c;
 
 endfunction
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/optimization/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/optimization/fminbnd.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/optimization/fminbnd.m	Thu Nov 19 13:08:00 2020 -0800
@@ -97,7 +97,7 @@
     return;
   endif
 
-  if (nargin < 2 || nargin > 4)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -288,15 +288,15 @@
 function print_formatted_table (table)
   printf ("\n Func-count     x          f(x)         Procedure\n");
   for row=table
-    printf("%5.5s        %7.7s    %8.8s\t%s\n",
-           int2str (row.funccount), num2str (row.x,"%.5f"),
-           num2str (row.fx,"%.6f"), row.procedure);
+    printf ("%5.5s        %7.7s    %8.8s\t%s\n",
+            int2str (row.funccount), num2str (row.x,"%.5f"),
+            num2str (row.fx,"%.6f"), row.procedure);
   endfor
   printf ("\n");
 endfunction
 
 ## Print either a success termination message or bad news
-function print_exit_msg (info, opt=struct())
+function print_exit_msg (info, opt=struct ())
   printf ("");
   switch (info)
     case 1
--- a/scripts/optimization/fminsearch.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/optimization/fminsearch.m	Thu Nov 19 13:08:00 2020 -0800
@@ -55,8 +55,9 @@
 ## @code{200 * number_of_variables}, i.e., @code{200 * length (@var{x0})}.
 ## The value must be a positive integer.
 ##
-## For a description of the other options, see @code{optimset}.  To initialize
-## an options structure with default values for @code{fminsearch} use
+## For a description of the other options,
+## @pxref{XREFoptimset,,@code{optimset}}.  To initialize an options structure
+## with default values for @code{fminsearch} use
 ## @code{options = optimset ("fminsearch")}.
 ##
 ## @code{fminsearch} may also be called with a single structure argument
@@ -311,7 +312,7 @@
     endfor
   else
     ## Right-angled simplex based on co-ordinate axes.
-    alpha = scale * ones(n+1,1);
+    alpha = scale * ones (n+1,1);
     for j = 2:n+1
       V(:,j) = x0 + alpha(j)*V(:,j);
       x(:) = V(:,j);
@@ -362,7 +363,7 @@
       printf ("Iter. %2.0f,", k);
       printf ("  how = %-11s", [how ","]);
       printf ("nf = %3.0f,  f = %9.4e  (%2.1f%%)\n", nf, dirn * fmax, ...
-              100*(fmax-fmax_old)/(abs(fmax_old)+eps));
+              100*(fmax-fmax_old)/(abs (fmax_old)+eps));
     endif
     fmax_old = fmax;
 
@@ -578,5 +579,5 @@
 %! fminsearch (@(x) (Inf), 0, optimset ("FunValCheck", "on"));
 
 ## Test input validation
-%!error fminsearch ()
+%!error <Invalid call> fminsearch ()
 %!error fminsearch (1)
--- a/scripts/optimization/fminunc.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/optimization/fminunc.m	Thu Nov 19 13:08:00 2020 -0800
@@ -70,7 +70,8 @@
 ## @var{x}, while @qcode{"TolFun"} is a tolerance for the objective function
 ## value @var{fval}.  The default is @code{1e-6} for both options.
 ##
-## For a description of the other options, see @code{optimset}.
+## For a description of the other options,
+## @pxref{XREFoptimset,,@code{optimset}}.
 ##
 ## On return, @var{x} is the location of the minimum and @var{fval} contains
 ## the value of the objective function at @var{x}.
@@ -128,7 +129,7 @@
     return;
   endif
 
-  if (nargin < 2 || nargin > 3 || ! isnumeric (x0))
+  if (nargin < 2 || ! isnumeric (x0))
     print_usage ();
   endif
 
--- a/scripts/optimization/fsolve.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/optimization/fsolve.m	Thu Nov 19 13:08:00 2020 -0800
@@ -78,8 +78,9 @@
 ## while @qcode{"TolFun"} is a tolerance for equations.  Default is @code{1e-6}
 ## for both @qcode{"TolX"} and @qcode{"TolFun"}.
 ##
-## For a description of the other options, see @code{optimset}.  To initialize
-## an options structure with default values for @code{fsolve} use
+## For a description of the other options,
+## @pxref{XREFoptimset,,@code{optimset}}.  To initialize an options structure
+## with default values for @code{fsolve} use
 ## @code{options = optimset ("fsolve")}.
 ##
 ## The first output @var{x} is the solution while the second output @var{fval}
@@ -186,7 +187,7 @@
     return;
   endif
 
-  if (nargin < 2 || nargin > 3 || ! isnumeric (x0))
+  if (nargin < 2 || ! isnumeric (x0))
     print_usage ();
   endif
 
--- a/scripts/optimization/fzero.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/optimization/fzero.m	Thu Nov 19 13:08:00 2020 -0800
@@ -134,7 +134,7 @@
     return;
   endif
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
--- a/scripts/optimization/glpk.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/optimization/glpk.m	Thu Nov 19 13:08:00 2020 -0800
@@ -485,7 +485,7 @@
 function [xopt, fmin, errnum, extra] = glpk (c, A, b, lb, ub, ctype, vartype, sense, param)
 
   ## If there is no input output the version and syntax
-  if (nargin < 3 || nargin > 9)
+  if (nargin < 3)
     print_usage ();
   endif
 
@@ -667,9 +667,9 @@
 %! assert (fmin, c' * xmin);
 %! assert (A * xmin, b);
 
-%!error<C .* finite values> glpk(NaN, 2, 3)
-%!error<A must be finite> glpk(1, NaN, 3)
-%!error<B must be finite> glpk(1, 2, NaN)
-%!error<LB must be a real-valued> glpk(1, 2, 3, NaN)
-%!error<UB must be a real-valued> glpk(1, 2, 3, 4, NaN)
-%!error<SENSE must be .* integer> glpk(1, 2, 3, 4, 5, "F", "C", NaN)
+%!error <C .* finite values> glpk (NaN, 2, 3)
+%!error <A must be finite> glpk (1, NaN, 3)
+%!error <B must be finite> glpk (1, 2, NaN)
+%!error <LB must be a real-valued> glpk (1, 2, 3, NaN)
+%!error <UB must be a real-valued> glpk (1, 2, 3, 4, NaN)
+%!error <SENSE must be .* integer> glpk (1, 2, 3, 4, 5, "F", "C", NaN)
--- a/scripts/optimization/humps.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/optimization/humps.m	Thu Nov 19 13:08:00 2020 -0800
@@ -63,10 +63,6 @@
 
 function [x, y] = humps (x = [0:0.05:1])
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   y = - 4*( 300*x.^4 - 720*x.^3 + 509*x.^2 - 87*x - 22) ./ ...
           ((10*x.^2 - 6*x + 1).*(20*x.^2 - 36*x + 17));
 
--- a/scripts/optimization/lsqnonneg.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/optimization/lsqnonneg.m	Thu Nov 19 13:08:00 2020 -0800
@@ -41,8 +41,8 @@
 ## @var{x0} is an optional initial guess for the solution @var{x}.
 ##
 ## @var{options} is an options structure to change the behavior of the
-## algorithm (@pxref{XREFoptimset,,optimset}).  @code{lsqnonneg} recognizes
-## these options: @qcode{"MaxIter"}, @qcode{"TolX"}.
+## algorithm (@pxref{XREFoptimset,,@code{optimset}}).  @code{lsqnonneg}
+## recognizes these options: @qcode{"MaxIter"}, @qcode{"TolX"}.
 ##
 ## Outputs:
 ##
@@ -91,7 +91,7 @@
     return;
   endif
 
-  if (nargin < 2 || nargin > 4)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -237,10 +237,9 @@
 %! xnew = [0;0.6929];
 %! assert (lsqnonneg (C, d), xnew, 0.0001);
 
-# Test input validation
-%!error lsqnonneg ()
-%!error lsqnonneg (1)
-%!error lsqnonneg (1,2,3,4,5)
+## Test input validation
+%!error <Invalid call> lsqnonneg ()
+%!error <Invalid call> lsqnonneg (1)
 %!error <C .* must be numeric matrices> lsqnonneg ({1},2)
 %!error <C .* must be numeric matrices> lsqnonneg (ones (2,2,2),2)
 %!error <D must be numeric matrices> lsqnonneg (1,{2})
--- a/scripts/optimization/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/optimization/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -6,6 +6,7 @@
   %reldir%/private/__fdjac__.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/__all_opts__.m \
   %reldir%/fminbnd.m \
   %reldir%/fminsearch.m \
--- a/scripts/optimization/optimget.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/optimization/optimget.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,7 +36,7 @@
 
 function retval = optimget (options, parname, default)
 
-  if (nargin < 2 || nargin > 4 || ! isstruct (options) || ! ischar (parname))
+  if (nargin < 2 || ! isstruct (options) || ! ischar (parname))
     print_usage ();
   endif
 
@@ -75,9 +75,8 @@
 %!assert (optimget (opts, "TolFun", 1e-3), 1e-3)
 
 ## Test input validation
-%!error optimget ()
-%!error optimget (1)
-%!error optimget (1,2,3,4,5)
+%!error <Invalid call> optimget ()
+%!error <Invalid call> optimget (1)
 %!error optimget (1, "name")
 %!error optimget (struct (), 2)
 %!warning <unrecognized option: foobar> (optimget (opts, "foobar"));
--- a/scripts/optimization/optimset.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/optimization/optimset.m	Thu Nov 19 13:08:00 2020 -0800
@@ -199,6 +199,7 @@
 
 endfunction
 
+
 %!assert (isfield (optimset (), "TolFun"))
 %!assert (isfield (optimset ("tolFun", 1e-3), "TolFun"))
 %!assert (optimget (optimset ("tolx", 1e-2), "tOLx"), 1e-2)
--- a/scripts/optimization/pqpnonneg.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/optimization/pqpnonneg.m	Thu Nov 19 13:08:00 2020 -0800
@@ -41,8 +41,8 @@
 ## @var{x0} is an optional initial guess for the solution @var{x}.
 ##
 ## @var{options} is an options structure to change the behavior of the
-## algorithm (@pxref{XREFoptimset,,optimset}).  @code{pqpnonneg} recognizes
-## one option: @qcode{"MaxIter"}.
+## algorithm (@pxref{XREFoptimset,,@code{optimset}}).  @code{pqpnonneg}
+## recognizes one option: @qcode{"MaxIter"}.
 ##
 ## Outputs:
 ##
@@ -93,7 +93,7 @@
     return;
   endif
 
-  if (nargin < 2 || nargin > 4)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -239,10 +239,9 @@
 %! d = rand (20, 1);
 %! assert (pqpnonneg (C'*C, -C'*d), lsqnonneg (C, d), 100*eps);
 
-# Test input validation
-%!error pqpnonneg ()
-%!error pqpnonneg (1)
-%!error pqpnonneg (1,2,3,4,5)
+## Test input validation
+%!error <Invalid call> pqpnonneg ()
+%!error <Invalid call> pqpnonneg (1)
 %!error <C .* must be numeric matrices> pqpnonneg ({1},2)
 %!error <C .* must be numeric matrices> pqpnonneg (ones (2,2,2),2)
 %!error <D must be numeric matrices> pqpnonneg (1,{2})
--- a/scripts/optimization/qp.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/optimization/qp.m	Thu Nov 19 13:08:00 2020 -0800
@@ -273,8 +273,8 @@
   endif
 
   ## Validate inequality constraints.
-  if (nargs > 7 && isempty (A_in) && ! (isempty(A_lb) || isempty(A_ub)))
-    warning("qp: empty inequality constraint matrix but non-empty bound vectors");
+  if (nargs > 7 && isempty (A_in) && ! (isempty (A_lb) || isempty (A_ub)))
+    warning ("qp: empty inequality constraint matrix but non-empty bound vectors");
   endif
 
   if (nargs > 7 && ! isempty (A_in))
--- a/scripts/optimization/sqp.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/optimization/sqp.m	Thu Nov 19 13:08:00 2020 -0800
@@ -29,7 +29,7 @@
 ## @deftypefnx {} {[@dots{}] =} sqp (@var{x0}, @var{phi}, @var{g}, @var{h})
 ## @deftypefnx {} {[@dots{}] =} sqp (@var{x0}, @var{phi}, @var{g}, @var{h}, @var{lb}, @var{ub})
 ## @deftypefnx {} {[@dots{}] =} sqp (@var{x0}, @var{phi}, @var{g}, @var{h}, @var{lb}, @var{ub}, @var{maxiter})
-## @deftypefnx {} {[@dots{}] =} sqp (@var{x0}, @var{phi}, @var{g}, @var{h}, @var{lb}, @var{ub}, @var{maxiter}, @var{tol})
+## @deftypefnx {} {[@dots{}] =} sqp (@var{x0}, @var{phi}, @var{g}, @var{h}, @var{lb}, @var{ub}, @var{maxiter}, @var{tolerance})
 ## Minimize an objective function using sequential quadratic programming (SQP).
 ##
 ## Solve the nonlinear program
@@ -127,7 +127,7 @@
 ## The seventh argument @var{maxiter} specifies the maximum number of
 ## iterations.  The default value is 100.
 ##
-## The eighth argument @var{tol} specifies the tolerance for the stopping
+## The eighth argument @var{tolerance} specifies the tolerance for the stopping
 ## criteria.  The default value is @code{sqrt (eps)}.
 ##
 ## The value returned in @var{info} may be one of the following:
@@ -197,7 +197,7 @@
 
   globals = struct (); # data and handles, needed and changed by subfunctions
 
-  if (nargin < 2 || nargin > 8 || nargin == 5)
+  if (nargin < 2 || nargin == 5)
     print_usage ();
   endif
 
@@ -297,7 +297,7 @@
         if (isa (x0, "single"))
           globals.lb = tmp_lb = -realmax ("single");
         else
-          globals.lb = tmp_lb = -realmax;
+          globals.lb = tmp_lb = -realmax ();
         endif
       else
         error ("sqp: invalid lower bound");
@@ -312,7 +312,7 @@
         if (isa (x0, "single"))
           globals.ub = tmp_ub = realmax ("single");
         else
-          globals.ub = tmp_ub = realmax;
+          globals.ub = tmp_ub = realmax ();
         endif
       else
         error ("sqp: invalid upper bound");
@@ -390,8 +390,8 @@
 
   info = 0;
   iter = 0;
-  # report ();  # Called with no arguments to initialize reporting
-  # report (iter, qp_iter, alpha, __sqp_nfun__, obj);
+  ## report ();  # Called with no arguments to initialize reporting
+  ## report (iter, qp_iter, alpha, __sqp_nfun__, obj);
 
   while (++iter < iter_max)
 
@@ -533,7 +533,7 @@
 
     A = A_new;
 
-    # report (iter, qp_iter, alpha, __sqp_nfun__, obj);
+    ## report (iter, qp_iter, alpha, __sqp_nfun__, obj);
 
   endwhile
 
@@ -776,10 +776,9 @@
 %! assert (obj, obj_opt, sqrt (eps));
 
 ## Test input validation
-%!error sqp ()
-%!error sqp (1)
-%!error sqp (1,2,3,4,5,6,7,8,9)
-%!error sqp (1,2,3,4,5)
+%!error <Invalid call> sqp ()
+%!error <Invalid call> sqp (1)
+%!error <Invalid call> sqp (1,2,3,4,5)
 %!error sqp (ones (2,2))
 %!error sqp (1, cell (4,1))
 %!error sqp (1, cell (3,1), cell (3,1))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/path/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/path/import.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/path/import.m	Thu Nov 19 13:08:00 2020 -0800
@@ -65,4 +65,4 @@
 endfunction
 
 
-%!error <not yet implemented> import ("foobar");
+%!error <not yet implemented> import ("foobar")
--- a/scripts/path/matlabroot.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/path/matlabroot.m	Thu Nov 19 13:08:00 2020 -0800
@@ -34,7 +34,7 @@
 
 function retval = matlabroot ()
 
-  retval = OCTAVE_HOME;
+  retval = OCTAVE_HOME ();
 
 endfunction
 
--- a/scripts/path/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/path/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -6,6 +6,7 @@
   %reldir%/private/getsavepath.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/import.m \
   %reldir%/matlabroot.m \
   %reldir%/pathdef.m \
--- a/scripts/path/pathdef.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/path/pathdef.m	Thu Nov 19 13:08:00 2020 -0800
@@ -44,10 +44,6 @@
 
 function val = pathdef ()
 
-  if (nargin > 0)
-    print_usage ();
-  endif
-
   ## Locate any project-specific .octaverc file.
   proj_octaverc = fullfile (pwd, ".octaverc");
   if (exist (proj_octaverc, "file"))
@@ -112,10 +108,10 @@
 %!   addpath (tmp_dir);
 %!   p1 = path ();
 %!   p2 = pathdef ();
-%!   assert (! isempty (strfind (p1, tmp_dir)))
-%!   assert (isempty (strfind (p2, tmp_dir)))
+%!   assert (! isempty (strfind (p1, tmp_dir)));
+%!   assert (isempty (strfind (p2, tmp_dir)));
 %! unwind_protect_cleanup
-%!   rmdir (tmp_dir);
+%!   sts = rmdir (tmp_dir);
 %!   path (path_orig);
 %! end_unwind_protect
 
@@ -130,9 +126,9 @@
 %!   path_1 = path ();
 %!   p = pathdef ();
 %!   path_2 = path ();
-%!   assert (path_1, path_2)
+%!   assert (path_1, path_2);
 %! unwind_protect_cleanup
-%!   rmdir (tmp_dir);
+%!   sts = rmdir (tmp_dir);
 %!   path (path_orig);
 %! end_unwind_protect
 
--- a/scripts/path/savepath.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/path/savepath.m	Thu Nov 19 13:08:00 2020 -0800
@@ -201,7 +201,7 @@
 %!   endif
 %!   status = savepath (fname);
 %!   assert (status == 0);
-%!   old_dir = pwd;
+%!   old_dir = pwd ();
 %!   unwind_protect
 %!     cd (test_dir);
 %!     if (exist (fullfile (pwd, ".octaverc")))
@@ -230,6 +230,6 @@
 %!   end_unwind_protect
 %! unwind_protect_cleanup
 %!   confirm_recursive_rmdir (false, "local");
-%!   rmdir (test_dir, "s");
+%!   sts = rmdir (test_dir, "s");
 %!   unlink (fname);
 %! end_unwind_protect
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/pkg/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/pkg/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/pkg/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -28,7 +28,9 @@
   %reldir%/private/uninstall.m \
   %reldir%/private/unload_packages.m
 
-%canon_reldir%_FCN_FILES = %reldir%/pkg.m
+%canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
+  %reldir%/pkg.m
 
 %canon_reldir%dir = $(fcnfiledir)/pkg
 
--- a/scripts/pkg/pkg.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/pkg/pkg.m	Thu Nov 19 13:08:00 2020 -0800
@@ -406,7 +406,7 @@
 
   confirm_recursive_rmdir (false, "local");
 
-  # valid actions in alphabetical order
+  ## valid actions in alphabetical order
   available_actions = {"build", "describe", "global_list",  "install", ...
                        "list", "load", "local_list", "prefix", "rebuild", ...
                        "test", "uninstall", "unload", "update"};
@@ -569,9 +569,9 @@
                  global_list, global_install);
 
       unwind_protect_cleanup
-        cellfun ("unlink", local_files);
+        [~] = cellfun ("unlink", local_files);
         if (exist (tmp_dir, "file"))
-          rmdir (tmp_dir, "s");
+          [~] = rmdir (tmp_dir, "s");
         endif
       end_unwind_protect
 
--- a/scripts/pkg/private/build.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/pkg/private/build.m	Thu Nov 19 13:08:00 2020 -0800
@@ -91,11 +91,11 @@
 
     tar (tar_path, package_root, builddir);
     gzip (tar_path, builddir);
-    rmdir (build_root, "s");
+    [~] = rmdir (build_root, "s");
 
     ## Currently does nothing because gzip() removes the original tar
     ## file but that should change in the future (bug #43431).
-    unlink (tar_path);
+    [~] = unlink (tar_path);
   endfor
 
 endfunction
--- a/scripts/pkg/private/configure_make.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/pkg/private/configure_make.m	Thu Nov 19 13:08:00 2020 -0800
@@ -88,9 +88,9 @@
       cmd = ["cd '" src "'; " scenv " ./configure " flags];
       [status, output] = shell (cmd, verbose);
       if (status != 0)
-        rmdir (desc.dir, "s");
+        sts = rmdir (desc.dir, "s");
         disp (output);
-        error ("pkg: error running the configure script for %s.", desc.name);
+        error ("pkg: error running the configure script for %s", desc.name);
       endif
     endif
 
@@ -105,9 +105,9 @@
       [status, output] = shell (sprintf ("%s make --jobs %i --directory '%s'",
                                          scenv, jobs, src), verbose);
       if (status != 0)
-        rmdir (desc.dir, "s");
+        sts = rmdir (desc.dir, "s");
         disp (output);
-        error ("pkg: error running 'make' for the %s package.", desc.name);
+        error ("pkg: error running 'make' for the %s package", desc.name);
       endif
     endif
 
@@ -169,7 +169,7 @@
     if (have_sh)
       cmd = ['sh.exe -c "' cmd '"'];
     else
-      error ("pkg: unable to find the command shell.");
+      error ("pkg: unable to find the command shell");
     endif
   endif
   ## if verbose, we want to display the output in real time.  To do this, we
--- a/scripts/pkg/private/default_prefix.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/pkg/private/default_prefix.m	Thu Nov 19 13:08:00 2020 -0800
@@ -24,10 +24,11 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn {} {[@var{prefix}, @var{archprefix} =} default_prefix (@var{global_install})
+## @deftypefn {} {[@var{prefix}, @var{archprefix} =} default_prefix (@var{global_install}, @var{desc})
 ## Undocumented internal function.
 ## @end deftypefn
 
+## FIXME: second input "desc" does not appear to be used.
 function [prefix, archprefix] = default_prefix (global_install, desc)
 
   if (global_install)
--- a/scripts/pkg/private/expand_rel_paths.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/pkg/private/expand_rel_paths.m	Thu Nov 19 13:08:00 2020 -0800
@@ -5,18 +5,23 @@
 ## See the file COPYRIGHT.md in the top-level directory of this
 ## distribution or <https://octave.org/copyright/>.
 ##
-## This program is free software: you can redistribute it and/or modify
-## it under the terms of the GNU General Public License as published by
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
 ## the Free Software Foundation, either version 3 of the License, or
 ## (at your option) any later version.
 ##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ## GNU General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
-## along with this program.  If not, see <https://www.gnu.org/licenses/>.
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
 
 ## -*- texinfo -*-
 ## @deftypefn {} {@var{pkg_list} =} expand_rel_paths (@var{pkg_list})
@@ -26,7 +31,7 @@
 function pkg_list = expand_rel_paths (pkg_list)
 
   ## Prepend location of OCTAVE_HOME to install directories
-  loc = OCTAVE_HOME;
+  loc = OCTAVE_HOME ();
   for i = 1:numel (pkg_list)
     ## Be sure to only prepend OCTAVE_HOME to pertinent package paths
     if (strncmpi (pkg_list{i}.dir, "__OH__", 6))
--- a/scripts/pkg/private/get_forge_pkg.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/pkg/private/get_forge_pkg.m	Thu Nov 19 13:08:00 2020 -0800
@@ -47,7 +47,7 @@
                                    name));
   if (succ)
     ## Remove blanks for simpler matching.
-    html(isspace(html)) = [];
+    html(isspace (html)) = [];
     ## Good.  Let's grep for the version.
     pat = "<tdclass=""package_table"">PackageVersion:</td><td>([\\d.]*)</td>";
     t = regexp (html, pat, "tokens");
--- a/scripts/pkg/private/install.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/pkg/private/install.m	Thu Nov 19 13:08:00 2020 -0800
@@ -145,7 +145,7 @@
   catch
     ## Something went wrong, delete tmpdirs.
     for i = 1:length (tmpdirs)
-      rmdir (tmpdirs{i}, "s");
+      sts = rmdir (tmpdirs{i}, "s");
     endfor
     rethrow (lasterror ());
   end_try_catch
@@ -199,7 +199,7 @@
   catch
     ## Something went wrong, delete tmpdirs.
     for i = 1:length (tmpdirs)
-      rmdir (tmpdirs{i}, "s");
+      sts = rmdir (tmpdirs{i}, "s");
     endfor
     rethrow (lasterror ());
   end_try_catch
@@ -218,7 +218,7 @@
   catch
     ## Something went wrong, delete tmpdirs.
     for i = 1:length (tmpdirs)
-      rmdir (tmpdirs{i}, "s");
+      sts = rmdir (tmpdirs{i}, "s");
     endfor
     rethrow (lasterror ());
   end_try_catch
@@ -237,11 +237,11 @@
   catch
     ## Something went wrong, delete tmpdirs.
     for i = 1:length (tmpdirs)
-      rmdir (tmpdirs{i}, "s");
+      sts = rmdir (tmpdirs{i}, "s");
     endfor
     for i = 1:length (descriptions)
-      rmdir (descriptions{i}.dir, "s");
-      rmdir (getarchdir (descriptions{i}), "s");
+      sts = rmdir (descriptions{i}.dir, "s");
+      sts = rmdir (getarchdir (descriptions{i}), "s");
     endfor
     rethrow (lasterror ());
   end_try_catch
@@ -252,8 +252,8 @@
     if (dirempty (descriptions{i}.dir, {"packinfo", "doc"})
         && dirempty (getarchdir (descriptions{i})))
       warning ("package %s is empty\n", descriptions{i}.name);
-      rmdir (descriptions{i}.dir, "s");
-      rmdir (getarchdir (descriptions{i}), "s");
+      sts = rmdir (descriptions{i}.dir, "s");
+      sts = rmdir (getarchdir (descriptions{i}), "s");
       descriptions(i) = [];
     endif
   endfor
@@ -282,10 +282,10 @@
   catch
     ## Something went wrong, delete tmpdirs.
     for i = 1:length (tmpdirs)
-      rmdir (tmpdirs{i}, "s");
+      sts = rmdir (tmpdirs{i}, "s");
     endfor
     for i = 1:length (descriptions)
-      rmdir (descriptions{i}.dir, "s");
+      sts = rmdir (descriptions{i}.dir, "s");
     endfor
     if (global_install)
       printf ("error: couldn't append to %s\n", global_list);
@@ -376,7 +376,7 @@
   if (! isfolder (inst_dir))
     [status, msg] = mkdir (inst_dir);
     if (status != 1)
-      rmdir (desc.dir, "s");
+      sts = rmdir (desc.dir, "s");
       error ("the 'inst' directory did not exist and could not be created: %s",
              msg);
     endif
@@ -389,7 +389,7 @@
 
   src = fullfile (packdir, "src");
   if (! isfolder (src))
-    return
+    return;
   endif
 
   ## Copy files to "inst" and "inst/arch" (this is instead of 'make install').
@@ -451,7 +451,7 @@
         endif
         [status, output] = copyfile (archindependent, instdir);
         if (status != 1)
-          rmdir (desc.dir, "s");
+          sts = rmdir (desc.dir, "s");
           error ("Couldn't copy files from 'src' to 'inst': %s", output);
         endif
       endif
@@ -466,7 +466,7 @@
         endif
         [status, output] = copyfile (archdependent, archdir);
         if (status != 1)
-          rmdir (desc.dir, "s");
+          sts = rmdir (desc.dir, "s");
           error ("Couldn't copy files from 'src' to 'inst': %s", output);
         endif
       endif
@@ -509,7 +509,7 @@
     [status, output] = mkdir (desc.dir);
     if (status != 1)
       error ("couldn't create installation directory %s : %s",
-      desc.dir, output);
+             desc.dir, output);
     endif
   endif
 
@@ -520,7 +520,7 @@
   if (! dirempty (instdir))
     [status, output] = copyfile (fullfile (instdir, "*"), desc.dir);
     if (status != 1)
-      rmdir (desc.dir, "s");
+      sts = rmdir (desc.dir, "s");
       error ("couldn't copy files to the installation directory");
     endif
     if (isfolder (fullfile (desc.dir, getarch ()))
@@ -535,39 +535,39 @@
             if (! isfolder (octm3))
               [status, output] = mkdir (octm3);
               if (status != 1)
-                rmdir (desc.dir, "s");
+                sts = rmdir (desc.dir, "s");
                 error ("couldn't create installation directory %s : %s",
                        octm3, output);
               endif
             endif
             [status, output] = mkdir (octm2);
             if (status != 1)
-              rmdir (desc.dir, "s");
+              sts = rmdir (desc.dir, "s");
               error ("couldn't create installation directory %s : %s",
                      octm2, output);
             endif
           endif
           [status, output] = mkdir (octm1);
           if (status != 1)
-            rmdir (desc.dir, "s");
+            sts = rmdir (desc.dir, "s");
             error ("couldn't create installation directory %s : %s",
                    octm1, output);
           endif
         endif
         [status, output] = mkdir (octfiledir);
         if (status != 1)
-          rmdir (desc.dir, "s");
+          sts = rmdir (desc.dir, "s");
           error ("couldn't create installation directory %s : %s",
-          octfiledir, output);
+                 octfiledir, output);
         endif
       endif
       [status, output] = movefile (fullfile (desc.dir, getarch (), "*"),
                                    octfiledir);
-      rmdir (fullfile (desc.dir, getarch ()), "s");
+      sts = rmdir (fullfile (desc.dir, getarch ()), "s");
 
       if (status != 1)
-        rmdir (desc.dir, "s");
-        rmdir (octfiledir, "s");
+        sts = rmdir (desc.dir, "s");
+        sts = rmdir (octfiledir, "s");
         error ("couldn't copy files to the installation directory");
       endif
     endif
@@ -578,8 +578,8 @@
   packinfo = fullfile (desc.dir, "packinfo");
   [status, msg] = mkdir (packinfo);
   if (status != 1)
-    rmdir (desc.dir, "s");
-    rmdir (octfiledir, "s");
+    sts = rmdir (desc.dir, "s");
+    sts = rmdir (octfiledir, "s");
     error ("couldn't create packinfo directory: %s", msg);
   endif
 
@@ -599,8 +599,8 @@
       write_index (desc, fullfile (packdir, "inst"),
                    fullfile (packinfo, "INDEX"), global_install);
     catch
-      rmdir (desc.dir, "s");
-      rmdir (octfiledir, "s");
+      sts = rmdir (desc.dir, "s");
+      sts = rmdir (octfiledir, "s");
       rethrow (lasterror ());
     end_try_catch
   endif
@@ -632,8 +632,8 @@
   else
     [status, output] = copyfile (filepath, packinfo);
     if (status != 1)
-      rmdir (desc.dir, "s");
-      rmdir (octfiledir, "s");
+      sts = rmdir (desc.dir, "s");
+      sts = rmdir (octfiledir, "s");
       error ("Couldn't copy %s file: %s", filename, output);
     endif
   endif
@@ -721,8 +721,8 @@
   ## part in the main directory.
   archdir = fullfile (getarchprefix (desc, global_install),
                       [desc.name "-" desc.version], getarch ());
-  if (isfolder (getarchdir (desc, global_install)))
-    archpkg = fullfile (getarchdir (desc, global_install), nm);
+  if (isfolder (getarchdir (desc)))
+    archpkg = fullfile (getarchdir (desc), nm);
     archfid = fopen (archpkg, "at");
   else
     archpkg = instpkg;
@@ -804,8 +804,8 @@
       cd (wd);
     catch
       cd (wd);
-      rmdir (desc.dir, "s");
-      rmdir (getarchdir (desc), "s");
+      sts = rmdir (desc.dir, "s");
+      sts = rmdir (getarchdir (desc), "s");
       rethrow (lasterror ());
     end_try_catch
   endif
--- a/scripts/pkg/private/installed_packages.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/pkg/private/installed_packages.m	Thu Nov 19 13:08:00 2020 -0800
@@ -134,8 +134,8 @@
     header = sprintf ("%s | %s | %s\n", h1, h2, h3);
     printf (header);
     tmp = sprintf (repmat ("-", 1, length (header) - 1));
-    tmp(length(h1)+2) = "+";
-    tmp(length(h1)+length(h2)+5) = "+";
+    tmp(length (h1)+2) = "+";
+    tmp(length (h1)+length (h2)+5) = "+";
     printf ("%s\n", tmp);
 
     ## Print the packages.
--- a/scripts/pkg/private/load_packages_and_dependencies.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/pkg/private/load_packages_and_dependencies.m	Thu Nov 19 13:08:00 2020 -0800
@@ -61,6 +61,11 @@
     EXEC_PATH (execpath);
   endif
 
+  ## Update lexer for autocompletion if necessary
+  if (isguirunning && (length (idx) > 0))
+    __event_manager_update_gui_lexer__;
+  endif
+
 endfunction
 
 
--- a/scripts/pkg/private/uninstall.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/pkg/private/uninstall.m	Thu Nov 19 13:08:00 2020 -0800
@@ -32,8 +32,8 @@
                     global_list, global_install)
 
   ## Get the list of installed packages.
-  [local_packages, global_packages] = installed_packages(local_list,
-                                                         global_list);
+  [local_packages, global_packages] = installed_packages (local_list,
+                                                          global_list);
   if (global_install)
     installed_pkgs_lst = {local_packages{:}, global_packages{:}};
   else
@@ -122,6 +122,11 @@
         endif
       endif
       if (isfolder (desc.dir))
+        ## FIXME: If first call to rmdir fails, then error() will
+        ##        stop further processing of getarchdir & archprefix.
+        ##        If this is, in fact, correct, then calls should
+        ##        just be shortened to rmdir (...) and let rmdir()
+        ##        report failure and reason for failure.
         [status, msg] = rmdir (desc.dir, "s");
         if (status != 1 && isfolder (desc.dir))
           error ("couldn't delete directory %s: %s", desc.dir, msg);
@@ -131,7 +136,7 @@
           error ("couldn't delete directory %s: %s", getarchdir (desc), msg);
         endif
         if (dirempty (desc.archprefix))
-          rmdir (desc.archprefix, "s");
+          sts = rmdir (desc.archprefix, "s");
         endif
       else
         warning ("directory %s previously lost", desc.dir);
@@ -140,8 +145,8 @@
 
     ## Write a new ~/.octave_packages.
     if (global_install)
-      if (length (remaining_packages) == 0)
-        unlink (global_list);
+      if (numel (remaining_packages) == 0)
+        [~] = unlink (global_list);
       else
         global_packages = save_order (remaining_packages);
         if (ispc)
@@ -152,8 +157,8 @@
         save (global_list, "global_packages");
       endif
     else
-      if (length (remaining_packages) == 0)
-        unlink (local_list);
+      if (numel (remaining_packages) == 0)
+        [~] = unlink (local_list);
       else
         local_packages = save_order (remaining_packages);
         if (ispc)
--- a/scripts/pkg/private/unload_packages.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/pkg/private/unload_packages.m	Thu Nov 19 13:08:00 2020 -0800
@@ -100,6 +100,9 @@
     if (any (idx))
       rmpath (d);
       ## FIXME: We should also check if we need to remove items from EXEC_PATH.
+      if (isguirunning)
+        __event_manager_update_gui_lexer__;
+      endif
     endif
   endfor
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/appearance/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/plot/appearance/annotation.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/annotation.m	Thu Nov 19 13:08:00 2020 -0800
@@ -217,9 +217,8 @@
 
   ## options
   opts = varargin;
-  nopts = numel (opts);
   if (! isempty (opts))
-    if (fix (nopts/2) != nopts/2 || ! all (cellfun (@ischar, opts(1:2:end))))
+    if (mod (numel (opts), 2) != 0 || ! all (cellfun (@ischar, opts(1:2:end))))
       warning ("annotation: couldn't parse PROP/VAL pairs, skipping");
       opts = {};
     endif
@@ -277,7 +276,7 @@
   listener = {@update_figsize_points, hax};
   addlistener (hf, "position", listener);
 
-  delfcn = @() dellistener (hf, "position", listener);
+  delfcn = @(~, ~) dellistener (hf, "position", listener);
   set (hax, "deletefcn", delfcn);
 
 endfunction
@@ -329,7 +328,7 @@
 
   addlistener (hax, "figsize_points", listener);
 
-  delfcn = @() dellistener (hax, "figsize_points", listener);
+  delfcn = @(~, ~) dellistener (hax, "figsize_points", listener);
   set (h, "deletefcn", delfcn);
 
   addlistener (h, "units", {@update_position, h});
@@ -832,7 +831,10 @@
            proptable(1:3:end), proptable(2:3:end), proptable(3:3:end));
 endfunction
 
-function addbasemenu (hm, hpar, pname, vals, mainlabel = "")
+## FIXME: there are some calls to addbasemenu with option-like arguments
+## but we don't do anything with varargin here.  What is the right thing
+## to do?
+function addbasemenu (hm, hpar, pname, vals, mainlabel = "", varargin)
 
   if (isempty (mainlabel))
     mainlabel = pname;
@@ -1131,7 +1133,7 @@
 
 function XY = textcoordinates (hte, pos)
   ## Get the "tight" extent of the text object in points units
-  textpos = get(hte, "position");
+  textpos = get (hte, "position");
   rot = get (hte, "rotation");
   units = get (hte, "units");
 
@@ -1451,8 +1453,8 @@
 %! xl = xlim ();
 %! yl = [-1.2 1.5];
 %! ylim (yl);
-%! x0 = (x0 - xl(1)) / diff(xl);
-%! y0 = (y0 - yl(1)) / diff(yl);
+%! x0 = (x0 - xl(1)) / diff (xl);
+%! y0 = (y0 - yl(1)) / diff (yl);
 %!
 %! pos = get (gca (), "position");
 %! x0 = x0*pos(3) + pos(1);
@@ -1575,7 +1577,7 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error annotation ()
+%!error <Invalid call> annotation ()
 %!error <Invalid call to annotation> annotation ({"line"}, 1:2, 1:2)
 %!error <X and Y must be 2-element vectors> annotation ("line", {1:2}, 1:2)
 %!error <X and Y must be 2-element vectors> annotation ("line", 1:2, {1:2})
--- a/scripts/plot/appearance/axis.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/axis.m	Thu Nov 19 13:08:00 2020 -0800
@@ -54,14 +54,20 @@
 ## The following options control the aspect ratio of the axes.
 ##
 ## @table @asis
+## @item @qcode{"equal"}
+## Force x-axis unit distance to equal y-axis (and z-axis) unit distance.
+##
 ## @item @qcode{"square"}
 ## Force a square axis aspect ratio.
 ##
-## @item @qcode{"equal"}
-## Force x-axis unit distance to equal y-axis (and z-axis) unit distance.
+## @item @nospell{@qcode{"vis3d"}}
+## Set aspect ratio modes (@qcode{"DataAspectRatio"},
+## @qcode{"PlotBoxAspectRatio"}) to @qcode{"manual"} for rotation without
+## stretching.
 ##
-## @item @qcode{"normal"}
-## Restore default aspect ratio.
+## @item  @qcode{"normal"}
+## @itemx @qcode{"fill"}
+## Restore default automatically computed aspect ratios.
 ## @end table
 ##
 ## @noindent
@@ -83,8 +89,6 @@
 ## @item @qcode{"image"}
 ## Equivalent to @qcode{"tight"} and @qcode{"equal"}.
 ##
-## @item @nospell{@qcode{"vis3d"}}
-## Set aspect ratio modes to @qcode{"manual"} for rotation without stretching.
 ## @end table
 ##
 ## @noindent
@@ -250,7 +254,7 @@
         ## Fix aspect ratio modes for rotation without stretching.
         set (ca, "dataaspectratiomode", "manual",
                  "plotboxaspectratiomode", "manual");
-      elseif (strcmpi (opt, "normal"))
+      elseif (strcmpi (opt, "normal") || strcmpi (opt, "fill"))
         ## Set plotboxaspectratio to something obtuse so that switching
         ## back to "auto" will force a re-calculation.
         set (ca, "plotboxaspectratio", [3 2 1]);
@@ -369,6 +373,7 @@
     endif
 
   endfor
+
 endfunction
 
 ## Find the limits for axis ("tight").
@@ -583,14 +588,14 @@
 %!  axis ("autoy");
 %!
 %! subplot (326);
-%!  plot (t, sin(t), t, -2*sin(t/2));
+%!  plot (t, sin (t), t, -2*sin (t/2));
 %!  axis ("tight");
 %!  title ("tight");
 
 %!demo
 %! clf;
 %! x = 0:0.1:10;
-%! plot (x, sin(x));
+%! plot (x, sin (x));
 %! axis image;
 %! title ({"image", 'equivalent to "tight" & "equal"'});
 
--- a/scripts/plot/appearance/camlookat.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/camlookat.m	Thu Nov 19 13:08:00 2020 -0800
@@ -35,18 +35,18 @@
 ## the bounding box approximately fills the field of view.
 ##
 ## This command fixes the camera's viewing direction
-## (@code{camtarget() - campos()}), camera up vector (@pxref{XREFcamup,,camup})
-## and viewing angle (@pxref{XREFcamva,,camva}).  The camera target
-## (@pxref{XREFcamtarget,,camtarget}) and camera position
-## (@pxref{XREFcampos,,campos}) are changed.
-##
+## (@code{camtarget() - campos()}), camera up vector
+## (@pxref{XREFcamup,,@code{camup}}) and viewing angle
+## (@pxref{XREFcamva,,@code{camva}}).  The camera target
+## (@pxref{XREFcamtarget,,@code{camtarget}}) and camera position
+## (@pxref{XREFcampos,,@code{campos}}) are changed.
 ##
 ## If the argument is a list @var{handle_list}, then a single bounding box for
 ## all the objects is computed and the camera is then adjusted as above.
 ##
 ## If the argument is an axis object @var{hax}, then the children of the axis
 ## are used as @var{handle_list}.  When called with no inputs, it uses the
-## current axis (@pxref{XREFgca,,gca}).
+## current axis (@pxref{XREFgca,,@code{gca}}).
 ##
 ## @seealso{camorbit, camzoom, camroll}
 ## @end deftypefn
@@ -54,10 +54,6 @@
 
 function camlookat (hh)
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   if (nargin == 0)
     hax = gca ();
     hh = get (hax, "children");
@@ -67,26 +63,26 @@
       hh = get (hax, "children");
     elseif (all (ishghandle (hh)))
       hax = ancestor (hh, "axes");
-      if numel (hax) > 1
+      if (numel (hax) > 1)
         hax = unique ([hax{:}]);
       endif
       if (numel (hax) > 1)
-        error ("camlookat: HANDLE_LIST must be children of the same axes.");
+        error ("camlookat: HANDLE_LIST must be children of the same axes");
       endif
     endif
   endif
 
   if (isempty (hh))
-    return
-  end
+    return;
+  endif
 
   x0 = x1 = y0 = y1 = z0 = z1 = [];
   for i = 1:numel (hh)
     h = hh(i);
 
     if (! ishghandle (h))
-      error ("camlookat: Inputs must be handles.");
-    end
+      error ("camlookat: Inputs must be handles");
+    endif
 
     x0_ = min (get (h, "xdata")(:));
     x1_ = max (get (h, "xdata")(:));
@@ -206,7 +202,7 @@
 %!   camlookat (h2);
 %!   dir2 = camtarget () - campos ();
 %!   dir2 /= norm (dir2);
-%!   assert (dir, dir2, -2*eps)
+%!   assert (dir, dir2, -2*eps);
 %!   camlookat ([h1 h2]);
 %!   dir2 = camtarget () - campos ();
 %!   dir2 /= norm (dir2);
@@ -313,7 +309,7 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error <Invalid call> camlookat (1, 2)
+%!error <called with too many inputs> camlookat (1, 2)
 %!error <must be handle> camlookat ("a")
 %!error <children of the same axes>
 %! hf = figure ("visible", "off");
--- a/scripts/plot/appearance/camorbit.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/camorbit.m	Thu Nov 19 13:08:00 2020 -0800
@@ -49,11 +49,11 @@
 ## @end example
 ##
 ## These rotations are centered around the camera target
-## (@pxref{XREFcamtarget,,camtarget}).
+## (@pxref{XREFcamtarget,,@code{camtarget}}).
 ## First the camera position is pitched up or down by rotating it @var{phi}
 ## degrees around an axis orthogonal to both the viewing direction
 ## (specifically @code{camtarget() - campos()}) and the camera ``up vector''
-## (@pxref{XREFcamup,,camup}).
+## (@pxref{XREFcamup,,@code{camup}}).
 ## Example:
 ##
 ## @example
@@ -81,7 +81,7 @@
 ##
 ## When @var{coorsys} is set to @qcode{"camera"}, the camera is moved left or
 ## right by rotating it around an axis parallel to the camera up vector
-## (@pxref{XREFcamup,,camup}).
+## (@pxref{XREFcamup,,@code{camup}}).
 ## The input @var{dir} should not be specified in this case.
 ## Example:
 ##
@@ -116,7 +116,7 @@
   phi = varargin{2};
   if (! (isnumeric (theta) && isscalar (theta)
          && isnumeric (phi) && isscalar (phi)))
-    error ("camorbit: THETA and PHI must be numeric scalars")
+    error ("camorbit: THETA and PHI must be numeric scalars");
   endif
 
   if (nargin < 3)
@@ -124,7 +124,7 @@
   else
     coorsys = varargin{3};
     if (! any (strcmpi (coorsys, {"data" "camera"})))
-      error ("camorbit: COORSYS must be 'data' or 'camera'")
+      error ("camorbit: COORSYS must be 'data' or 'camera'");
     endif
   endif
 
@@ -132,13 +132,13 @@
     dir = "z";
   else
     if (strcmpi (coorsys, "camera"))
-      error ("camorbit: DIR must not be used with 'camera' COORSYS.");
+      error ("camorbit: DIR must not be used with 'camera' COORSYS");
     endif
     dir = varargin{4};
   endif
 
   if (ischar (dir))
-    switch tolower (dir)
+    switch (tolower (dir))
       case "x"
         dir = [1 0 0];
       case "y"
@@ -172,7 +172,7 @@
     yaw_ax = up;
   else
     yaw_ax = dir;
-  end
+  endif
 
   ## First pitch up then yaw right (order matters)
   pos = num2cell (campos (hax));
@@ -219,7 +219,7 @@
 %! hf = figure ("visible", "off");
 %! unwind_protect
 %!   sphere ();
-%!   camorbit(20, 30, "camera")
+%!   camorbit (20, 30, "camera")
 %!   p = campos ();
 %!   u = camup ();
 %!   ## Matlab 2008a
--- a/scripts/plot/appearance/campos.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/campos.m	Thu Nov 19 13:08:00 2020 -0800
@@ -145,7 +145,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   sphere();
+%!   sphere ();
 %!   p_orig = campos ();
 %!   m = campos ("mode");
 %!   assert (strcmp (m, "auto"));
--- a/scripts/plot/appearance/camup.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/camup.m	Thu Nov 19 13:08:00 2020 -0800
@@ -57,8 +57,8 @@
 ## @end example
 ##
 ## Modifying the up vector does not modify the camera target
-## (@pxref{XREFcamtarget,,camtarget}).  Thus, the camera up vector might not be
-## orthogonal to the direction of the camera's view:
+## (@pxref{XREFcamtarget,,@code{camtarget}}).  Thus, the camera up vector might
+## not be orthogonal to the direction of the camera's view:
 ##
 ## @example
 ## @group
--- a/scripts/plot/appearance/camva.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/camva.m	Thu Nov 19 13:08:00 2020 -0800
@@ -135,7 +135,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   sphere();
+%!   sphere ();
 %!   a_orig = camva ();
 %!   m = camva ("mode");
 %!   assert (strcmp (m, "auto"));
--- a/scripts/plot/appearance/camzoom.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/camzoom.m	Thu Nov 19 13:08:00 2020 -0800
@@ -114,14 +114,14 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   sphere();
+%!   sphere ();
 %!   x = camva ();
 %!   camzoom (2);
 %!   y = camva ();
 %!   ## Matlab 2016a
 %!   xm = 10.339584907201974;
 %!   ym = 5.1803362845094822;
-%!   assert (tand (x/2) / tand (y/2), tand (xm/2) / tand (ym/2), 2e-14)
+%!   assert (tand (x/2) / tand (y/2), tand (xm/2) / tand (ym/2), 2e-14);
 %! unwind_protect_cleanup
 %!   close (hf);
 %! end_unwind_protect
@@ -138,7 +138,7 @@
 %!   ## Matlab 2014a
 %!   xm = 13.074668029506947;
 %!   ym = 2.6258806698721222;
-%!   assert (tand (x/2) / tand (y/2), tand (xm/2) / tand (ym/2), 2e-14)
+%!   assert (tand (x/2) / tand (y/2), tand (xm/2) / tand (ym/2), 2e-14);
 %! unwind_protect_cleanup
 %!   close (hf);
 %! end_unwind_protect
@@ -154,7 +154,7 @@
 %!   camzoom (hax1, 2)
 %!   x = camva (hax1);
 %!   y = camva (hax2);
-%!   assert (tand (y/2) / tand (x/2), 2, 2*eps)
+%!   assert (tand (y/2) / tand (x/2), 2, 2*eps);
 %! unwind_protect_cleanup
 %!   close (hf);
 %! end_unwind_protect
--- a/scripts/plot/appearance/daspect.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/daspect.m	Thu Nov 19 13:08:00 2020 -0800
@@ -104,7 +104,7 @@
 %!demo
 %! clf;
 %! x = 0:0.01:4;
-%! plot (x,cos(x), x,sin(x));
+%! plot (x,cos (x), x,sin (x));
 %! axis square;
 %! daspect ([1 1 1]);
 %! title ("square plot box with axis limits [0, 4, -2, 2]");
@@ -120,7 +120,7 @@
 %!demo
 %! clf;
 %! x = 0:0.01:4;
-%! plot (x,cos(x), x,sin(x));
+%! plot (x,cos (x), x,sin (x));
 %! daspect ([1 2 1]);
 %! pbaspect ([2 1 1]);
 %! title ("2x1 plot box with axis limits [0, 4, -2, 2]");
@@ -128,18 +128,18 @@
 %!demo
 %! clf;
 %! x = 0:0.01:4;
-%! plot (x,cos(x), x, sin(x));
+%! plot (x,cos (x), x, sin (x));
 %! axis square;
-%! set (gca, "activepositionproperty", "position");
+%! set (gca, "positionconstraint", "innerposition");
 %! daspect ([1 1 1]);
 %! title ("square plot box with axis limits [0, 4, -2, 2]");
 
 %!demo
 %! clf;
 %! x = 0:0.01:4;
-%! plot (x,cos(x), x,sin(x));
+%! plot (x,cos (x), x,sin (x));
 %! axis ([0 4 -1 1]);
-%! set (gca, "activepositionproperty", "position");
+%! set (gca, "positionconstraint", "innerposition");
 %! daspect ([2 1 1]);
 %! title ("square plot box with axis limits [0, 4, -1, 1]");
 
--- a/scripts/plot/appearance/datetick.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/datetick.m	Thu Nov 19 13:08:00 2020 -0800
@@ -94,7 +94,7 @@
 %! xlabel ("year");
 %! ylabel ("average price");
 %! title ("datetick() with MM/DD/YY format");
-%! ax = gca;
+%! ax = gca ();
 %! set (ax, "xtick", datenum (1990:5:2005,1,1));
 %! datetick ("x", 2, "keepticks");
 %! set (ax, "ytick", 12:16);
--- a/scripts/plot/appearance/hidden.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/hidden.m	Thu Nov 19 13:08:00 2020 -0800
@@ -48,9 +48,7 @@
 
 function state = hidden (mode = "toggle")
 
-  if (nargin > 2)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! ischar (mode))
       error ("hidden: MODE must be a string");
     elseif (! any (strcmpi (mode, {"on", "off"})))
--- a/scripts/plot/appearance/legend.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/legend.m	Thu Nov 19 13:08:00 2020 -0800
@@ -195,7 +195,11 @@
 
   ## Use the old legend code to handle gnuplot toolkit
   if (strcmp (graphics_toolkit (), "gnuplot"))
-    [hleg, hleg_obj, hplot, labels] = __gnuplot_legend__ (varargin{:});
+    if (nargout > 0)
+      [hleg, hleg_obj, hplot, labels] = __gnuplot_legend__ (varargin{:});
+    else
+      __gnuplot_legend__ (varargin{:});
+    endif
     return;
   endif
 
@@ -309,17 +313,17 @@
     hf = ancestor (hax, "figure");
 
     add_safe_listener (hl, hf, "colormap", ...
-                       @() set (hl, "colormap", get (hax, "colormap")));
+                       @(~, ~) set (hl, "colormap", get (hax, "colormap")));
 
     add_safe_listener (hl, hax, "position", {@maybe_update_layout_cb, hl});
     add_safe_listener (hl, hax, "tightinset", ...
-                       @(h) update_layout_cb (get (h, "__legend_handle__")));
+                       @(h, ~) update_layout_cb (get (h, "__legend_handle__")));
     add_safe_listener (hl, hax, "clim", ...
-                       @(hax) set (hl, "clim", get (hax, "clim")));
+                       @(hax, ~) set (hl, "clim", get (hax, "clim")));
     add_safe_listener (hl, hax, "colormap", ...
-                       @(hax) set (hl, "colormap", get (hax, "colormap")));
+                       @(hax, ~) set (hl, "colormap", get (hax, "colormap")));
     add_safe_listener (hl, hax, "fontsize", ...
-                       @(hax) set (hl, "fontsize", 0.9*get (hax, "fontsize")));
+                       @(hax, ~) set (hl, "fontsize", 0.9*get (hax, "fontsize")));
     add_safe_listener (hl, hax, "children", {@legend_autoupdate_cb, hl});
 
     ## Listeners to legend properties
@@ -345,8 +349,8 @@
     addlistener (hl, "string", @update_string_cb);
 
     addlistener (hl, "textcolor", ...
-                 @(h) set (findobj (h, "type", "text"), ...
-                           "color", get (hl, "textcolor")));
+                 @(h, ~) set (findobj (h, "type", "text"), ...
+                               "color", get (hl, "textcolor")));
 
     addlistener (hl, "visible", @update_visible_cb);
 
@@ -378,7 +382,7 @@
 
 endfunction
 
-function update_box_cb (hl)
+function update_box_cb (hl, ~)
 
   if (strcmp (get (hl, "box"), "on"))
     if (strcmp (get (hl, "color"), "none"))
@@ -404,14 +408,14 @@
 
 endfunction
 
-function update_edgecolor_cb (hl)
+function update_edgecolor_cb (hl, ~)
 
   ecolor = get (hl, "edgecolor");
   set (hl, "xcolor", ecolor, "ycolor", ecolor);
 
 endfunction
 
-function update_position_cb (hl)
+function update_position_cb (hl, ~)
 
   updating = getappdata (hl, "__updating_layout__");
   if (isempty (updating) || ! updating)
@@ -420,7 +424,7 @@
 
 endfunction
 
-function update_string_cb (hl)
+function update_string_cb (hl, ~)
 
   ## Check that the number of legend item and the number of labels match
   ## before calling update_layout_cb.
@@ -454,7 +458,7 @@
 
 endfunction
 
-function update_visible_cb (hl)
+function update_visible_cb (hl, ~)
 
   location = get (hl, "location");
   if (strcmp (location(end:-1:end-3), "edis"))
@@ -463,7 +467,7 @@
 
 endfunction
 
-function reset_cb (ht, evt, hl, deletelegend = true)
+function reset_cb (ht, ~, hl, deletelegend = true)
 
   if (ishghandle (hl))
     listeners = getappdata (hl, "__listeners__");
@@ -480,7 +484,7 @@
 
 endfunction
 
-function delete_legend_cb (hl)
+function delete_legend_cb (hl, ~)
 
   reset_cb ([], [], hl, false);
 
@@ -525,7 +529,7 @@
 
   addproperty ("numcolumnsmode", hl, "radio", "{auto}|manual");
 
-  addlistener (hl, "numcolumns", @(h) set (h, "numcolumnsmode", "manual"));
+  addlistener (hl, "numcolumns", @(h, ~) set (h, "numcolumnsmode", "manual"));
 
   addproperty ("autoupdate", hl, "radio", "{on}|off");
 
@@ -543,7 +547,7 @@
 
 endfunction
 
-function maybe_update_layout_cb (h, d, hl)
+function maybe_update_layout_cb (h, ~, hl)
 
   persistent updating = false;
 
@@ -569,7 +573,7 @@
 
 endfunction
 
-function update_numchild_cb (hl)
+function update_numchild_cb (hl, ~)
 
   if (strcmp (get (hl, "autoupdate"), "on"))
 
@@ -587,7 +591,7 @@
 
 endfunction
 
-function legend_autoupdate_cb (hax, d, hl)
+function legend_autoupdate_cb (hax, ~, hl)
 
   ## Get all current children including eventual peer plotyy axes children
   try
@@ -895,7 +899,7 @@
     return;
   endif
 
-  setappdata(hl, "__updating_layout__", true);
+  setappdata (hl, "__updating_layout__", true);
 
   ## Scale limits so that item positions are expressed in points, from
   ## top to bottom and from left to right or reverse depending on textposition
@@ -927,7 +931,7 @@
 
   unwind_protect_cleanup
     set (hl, "units", units);
-    setappdata(hl, "__updating_layout__", false);
+    setappdata (hl, "__updating_layout__", false);
   end_unwind_protect
 
 endfunction
@@ -1056,12 +1060,12 @@
       safe_property_link (hplt(1), hicon, lprops);
       safe_property_link (hplt(end), hmarker, mprops);
       addlistener (hicon, "ydata", ...
-                   @(h) set (hmarker, "ydata", get (h, "markerydata")));
+                   @(h, ~) set (hmarker, "ydata", get (h, "markerydata")));
       addlistener (hicon, "xdata", ...
-                   @(h) set (hmarker, "xdata", get (h, "markerxdata")));
+                   @(h, ~) set (hmarker, "xdata", get (h, "markerxdata")));
       addlistener (hmarker, "markersize", @update_marker_cb);
       add_safe_listener (hl, hplt(1), "beingdeleted",
-                         @() delete ([hicon hmarker]))
+                         @(~, ~) delete ([hicon hmarker]))
       if (! strcmp (typ, "__errplot__"))
         setappdata (hicon, "__creator__", typ);
       else
@@ -1099,11 +1103,11 @@
       safe_property_link (hplt(1), hicon, pprops);
       safe_property_link (hplt(end), htmp, pprops);
       addlistener (hicon, "ydata", ...
-                   @(h) set (htmp, "ydata", get (h, "innerydata")));
+                   @(h, ~) set (htmp, "ydata", get (h, "innerydata")));
       addlistener (hicon, "xdata", ...
-                   @(h) set (htmp, "xdata", get (h, "innerxdata")));
+                   @(h, ~) set (htmp, "xdata", get (h, "innerxdata")));
       add_safe_listener (hl, hplt(1), "beingdeleted",
-                         @() delete ([hicon htmp]))
+                         @(~, ~) delete ([hicon htmp]))
 
       setappdata (hicon, "__creator__", typ);
 
@@ -1119,9 +1123,9 @@
 function safe_property_link (h1, h2, props)
   for ii = 1:numel (props)
     prop = props{ii};
-    lsn = {h1, prop, @(h) set (h2, prop, get (h, prop))};
+    lsn = {h1, prop, @(h, ~) set (h2, prop, get (h, prop))};
     addlistener (lsn{:});
-    addlistener (h2, "beingdeleted", @() dellistener (lsn{:}));
+    addlistener (h2, "beingdeleted", @(~, ~) dellistener (lsn{:}));
   endfor
 endfunction
 
@@ -1143,7 +1147,7 @@
 
 endfunction
 
-function update_marker_cb (h)
+function update_marker_cb (h, ~)
 
   if (get (h, "markersize") > 8)
     set (h, "markersize", 8);
@@ -1237,7 +1241,7 @@
 
     nrow = ceil (nitem / ncol);
 
-    colwidth = arrayfun (@(idx) max(ext(idx:ncol:end, 1)),
+    colwidth = arrayfun (@(idx) max (ext(idx:ncol:end, 1)),
                          1:ncol);
     y = vmargin;
     for ii = 1:nrow
@@ -1347,12 +1351,13 @@
       set (hicon, "markerxdata", x0, "markerydata", y0, ...
            "xdata", xdata, "ydata", ydata);
     case "__scatter__"
-      set (hicon, "xdata", mean(xdata), "ydata", mean(ydata));
+      set (hicon, "xdata", mean (xdata), "ydata", mean (ydata));
     case "__stem__"
       xdata(2) -= (get (get (hicon, "peer_object"), "markersize") / 2);
       set (hicon, "markerxdata", xdata(2), "markerydata", mean (ydata), ...
            "xdata", xdata, "ydata", [mean(ydata), mean(ydata)]);
   endswitch
+
 endfunction
 
 function pos = boxposition (axpos, pba, pbam, dam)
@@ -1749,7 +1754,7 @@
 %!demo
 %! clf;
 %! x = 0:0.1:7;
-%! h = plot (x,sin(x), x,cos(x), x,sin(x.^2/10), x,cos(x.^2/10));
+%! h = plot (x,sin (x), x,cos (x), x,sin (x.^2/10), x,cos (x.^2/10));
 %! title ("Only the sin() objects have keylabels");
 %! legend (h([1, 3]), {"sin (x)", "sin (x^2/10)"}, "location", "southwest");
 
--- a/scripts/plot/appearance/lighting.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/lighting.m	Thu Nov 19 13:08:00 2020 -0800
@@ -184,10 +184,10 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   ha = axes;
+%!   ha = axes ();
 %!   hm = mesh (sombrero ());
-%!   hp = patch;
-%!   hs = surface;
+%!   hp = patch ();
+%!   hs = surface ();
 %!   lighting flat
 %!   assert (get (hp, "facelighting"), "flat");
 %!   assert (get (hs, "facelighting"), "flat");
@@ -225,7 +225,7 @@
 %!   close (hf);
 %! end_unwind_protect
 
-%!error lighting ()
+%!error <Invalid call> lighting ()
 %!error lighting (1, 2, "flat")
 %!error <MODE must be a string> lighting (-1)
 %!error <MODE must be a string> lighting ({})
--- a/scripts/plot/appearance/material.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/material.m	Thu Nov 19 13:08:00 2020 -0800
@@ -227,8 +227,8 @@
 %!test
 %! hf = figure ("Visible", "off");
 %! unwind_protect
-%!   hp = patch;
-%!   hs = surface;
+%!   hp = patch ();
+%!   hs = surface ();
 %!   material dull
 %!   assert (get (hp, "ambientstrength"), 0.3);
 %!   assert (get (hs, "ambientstrength"), 0.3);
@@ -296,7 +296,7 @@
 
 %!test
 %! refl_props = material ("metal");
-%! assert (refl_props, {0.3, 0.3, 1, 25, 0.5})
+%! assert (refl_props, {0.3, 0.3, 1, 25, 0.5});
 
 ## Test input validation
 %!error <Invalid call to material> material ()
@@ -305,7 +305,7 @@
 %!error <Invalid call to material> a = material (-1, 2)
 %!error <Invalid call to material> a = material ({})
 %!error <Invalid call to material> a = material ([.3 .4 .5])
-%!error <Invalid call to material> [a, b] = material ()
+%!error <called with too many outputs> [a, b] = material ()
 %!error <first argument must be a list of handles> material (-1, "metal")
 %!error <unknown material type 'foo'> material foo
 %!error <incorrect number of elements in material vector> material (-1)
--- a/scripts/plot/appearance/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -5,9 +5,11 @@
 %canon_reldir%_PRIVATE_FCN_FILES = \
   %reldir%/private/__axis_label__.m \
   %reldir%/private/__axis_limits__.m \
-  %reldir%/private/__gnuplot_legend__.m
+  %reldir%/private/__gnuplot_legend__.m \
+  %reldir%/private/__tickangle__.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/__clabel__.m \
   %reldir%/__getlegenddata__.m \
   %reldir%/__rotate_around_axis__.m \
@@ -45,15 +47,18 @@
   %reldir%/whitebg.m \
   %reldir%/xlabel.m \
   %reldir%/xlim.m \
+  %reldir%/xtickangle.m \
   %reldir%/xticks.m \
   %reldir%/xticklabels.m \
   %reldir%/ylabel.m \
   %reldir%/ylim.m \
   %reldir%/yticks.m \
+  %reldir%/ytickangle.m \
   %reldir%/yticklabels.m \
   %reldir%/zlabel.m \
   %reldir%/zlim.m \
   %reldir%/zticks.m \
+  %reldir%/ztickangle.m \
   %reldir%/zticklabels.m
 
 %canon_reldir%dir = $(fcnfiledir)/plot/appearance
--- a/scripts/plot/appearance/pbaspect.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/pbaspect.m	Thu Nov 19 13:08:00 2020 -0800
@@ -105,21 +105,21 @@
 %!demo
 %! clf;
 %! x = 0:0.01:4;
-%! plot (x,cos(x), x,sin(x));
+%! plot (x,cos (x), x,sin (x));
 %! pbaspect ([1 1 1]);
 %! title ("plot box is square");
 
 %!demo
 %! clf;
 %! x = 0:0.01:4;;
-%! plot (x,cos(x), x,sin(x));
+%! plot (x,cos (x), x,sin (x));
 %! pbaspect ([2 1 1]);
 %! title ("plot box aspect ratio is 2x1");
 
 %!demo
 %! clf;
 %! x = 0:0.01:4;
-%! plot (x,cos(x), x,sin(x));
+%! plot (x,cos (x), x,sin (x));
 %! daspect ([1 1 1]);
 %! pbaspect ([2 1 1]);
 %! title ("plot box is 2x1, and axes [0 4 -1 1]");
--- a/scripts/plot/appearance/private/__gnuplot_legend__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/private/__gnuplot_legend__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -623,7 +623,7 @@
                           "box", box,
                           "xtick", [], "ytick", [],
                           "xlim", [0, 1], "ylim", [0, 1],
-                          "activepositionproperty", "position");
+                          "positionconstraint", "innerposition");
           setappdata (hlegend, "__axes_handle__", ud);
           try
             addproperty ("__legend_handle__", ud(1), "handle", hlegend);
@@ -1063,7 +1063,7 @@
                 ## This violates strict Matlab compatibility, but reliably
                 ## renders an aesthetic result.
                 set (ca(i), "position",  unmodified_axes_position,
-                            "activepositionproperty", "outerposition");
+                            "positionconstraint", "outerposition");
               else
                 ## numel (ca) > 1 for axes overlays (like plotyy)
                 set (ca(i), "position", new_pos);
@@ -1182,8 +1182,8 @@
       outerposition = get (hleg, "unmodified_axes_outerposition");
       units = get (hax, "units");
       set (hax, "units", "points");
-      switch (get (hax, "activepositionproperty"))
-        case "position"
+      switch (get (hax, "positionconstraint"))
+        case "innerposition"
           set (hax, "outerposition", outerposition, "position", position);
         case "outerposition"
           set (hax, "position", position, "outerposition", outerposition);
@@ -1242,11 +1242,11 @@
 endfunction
 
 ## The legend "location" property has changed.
-function cb_legend_location (hleg, d)
+function cb_legend_location (hleg, ~)
 
-  ## If it isn't "none", which means manual positioning, then rebuild .
+  ## If it isn't "none", which means manual positioning, then rebuild.
   if (! strcmp (get (hleg, "location"), "none"))
-    cb_legend_update (hleg, d);
+    cb_legend_update (hleg, []);
   endif
 
 endfunction
@@ -1557,7 +1557,7 @@
 %!demo
 %! clf;
 %! x = 0:0.1:7;
-%! h = plot (x,sin(x), x,cos(x), x,sin(x.^2/10), x,cos(x.^2/10));
+%! h = plot (x,sin (x), x,cos (x), x,sin (x.^2/10), x,cos (x.^2/10));
 %! title ("Only the sin() objects have keylabels");
 %! legend (h([1, 3]), {"sin (x)", "sin (x^2/10)"}, "location", "southwest");
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/appearance/private/__tickangle__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,68 @@
+########################################################################
+##
+## Copyright (C) 2020 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn {} {@var{retval} =} __tickangle__ (@var{caller}, @var{hax}, @var{angle})
+## Undocumented internal function.
+## @seealso{xtickangle, ytickangle, ztickangle}
+## @end deftypefn
+
+function retval = __tickangle__ (caller, hax, angle)
+
+  ax = tolower (caller(1));
+  switch (nargin)
+    case 1
+      retval = get (gca (), [ax, "ticklabelrotation"]);
+      return;
+
+    case 2
+      if (isaxes (hax))
+        retval = get (hax, [ax, "ticklabelrotation"]);
+        return;
+      else
+        angle = hax;
+        hax = [];
+      endif
+
+    case 3
+      if (! isaxes (hax))
+        error ([caller, ": HAX must be a handle to an axes object"]);
+      endif
+
+  endswitch
+
+  if (! (isscalar (angle) && isnumeric (angle) && isfinite (angle)))
+    error ([caller ": ANGLE must be a finite, numeric, scalar value"]);
+  elseif (nargout > 0)
+    error ([caller ": function called with output query and input set value"]);
+  endif
+
+  if (isempty (hax))
+    hax = gca ();
+  endif
+
+  set (hax, [ax, "ticklabelrotation"], angle);
+
+endfunction
--- a/scripts/plot/appearance/rticks.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/rticks.m	Thu Nov 19 13:08:00 2020 -0800
@@ -120,7 +120,7 @@
 %! hf = figure ("visible", "off");
 %! unwind_protect
 %!   polar (linspace (0, pi, 20), rand (20,1));
-%!   hax = gca;
+%!   hax = gca ();
 %!   ticks = rticks;
 %!   assert (rticks (hax), ticks);
 %!   rticks (hax, [0 0.25 0.75 1 2]);
@@ -135,7 +135,7 @@
 %! hf = figure ("visible", "off");
 %! unwind_protect
 %!   polar (linspace (0, pi, 20), 1:20);
-%!   hax = gca;
+%!   hax = gca ();
 %!   fail ("rticks (-1, [0 1])", "HAX must be a handle to an axes");
 %!   fail ("tmp = rticks (hax, [0 1])", "too many output arguments");
 %!   fail ("tmp = rticks (hax, 'mode')", "MODE is not yet implemented");
--- a/scripts/plot/appearance/shading.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/shading.m	Thu Nov 19 13:08:00 2020 -0800
@@ -265,10 +265,10 @@
 %!test
 %! hf = figure ("Visible", "off");
 %! unwind_protect
-%!   ha = axes;
+%!   ha = axes ();
 %!   hm = mesh (sombrero ());
-%!   hp = patch;
-%!   hs = surface;
+%!   hp = patch ();
+%!   hs = surface ();
 %!   shading interp;
 %!   assert (get (hp, "facecolor"), "interp");
 %!   assert (get (hs, "facecolor"), "interp");
@@ -308,7 +308,7 @@
 %!   close (hf);
 %! end_unwind_protect
 
-%!error shading ()
+%!error <Invalid call> shading ()
 %!error shading (1, 2, "flat")
 %!error <MODE must be a valid string> shading (-1)
 %!error <MODE must be a valid string> shading ({})
--- a/scripts/plot/appearance/specular.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/specular.m	Thu Nov 19 13:08:00 2020 -0800
@@ -42,7 +42,7 @@
 
 function retval = specular (sx, sy, sz, lv, vv, se)
 
-  if (nargin < 5 || nargin > 6)
+  if (nargin < 5)
     print_usage ();
   endif
 
--- a/scripts/plot/appearance/thetaticks.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/thetaticks.m	Thu Nov 19 13:08:00 2020 -0800
@@ -124,7 +124,7 @@
 %! hf = figure ("visible", "off");
 %! unwind_protect
 %! polar (linspace (0, pi, 20), rand (20,1));
-%!   hax = gca;
+%!   hax = gca ();
 %!   ticks = thetaticks;
 %!   assert (thetaticks (hax), ticks);
 %!   thetaticks (hax, [0 45 90 135 180]);
@@ -139,7 +139,7 @@
 %! hf = figure ("visible", "off");
 %! unwind_protect
 %!   polar (linspace (0, pi, 20), 1:20);
-%!   hax = gca;
+%!   hax = gca ();
 %!   fail ("thetaticks (-1, [0 1])", "HAX must be a handle to an axes");
 %!   fail ("tmp = thetaticks (hax, [0 1])", "too many output arguments");
 %!   fail ("tmp = thetaticks (hax, 'mode')", "MODE is not yet implemented");
--- a/scripts/plot/appearance/view.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/view.m	Thu Nov 19 13:08:00 2020 -0800
@@ -110,13 +110,13 @@
 %! hf = figure ("visible", "off");
 %! unwind_protect
 %!   plot3 ([0,1], [0,1], [0,1]);
-%!   [az, el] = view;
+%!   [az, el] = view ();
 %!   assert ([az, el], [-37.5, 30], eps);
 %!   view (2);
-%!   [az, el] = view;
+%!   [az, el] = view ();
 %!   assert ([az, el], [0, 90], eps);
 %!   view ([1 1 0]);
-%!   [az, el] = view;
+%!   [az, el] = view ();
 %!   assert ([az, el], [135, 0], eps);
 %! unwind_protect_cleanup
 %!   close (hf);
@@ -125,11 +125,11 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   line;
-%!   [az, el] = view;
+%!   line ();
+%!   [az, el] = view ();
 %!   assert ([az, el], [0, 90], eps);
 %!   view (3);
-%!   [az, el] = view;
+%!   [az, el] = view ();
 %!   assert ([az, el], [-37.5, 30], eps);
 %! unwind_protect_cleanup
 %!   close (hf);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/appearance/xtickangle.m	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,93 @@
+########################################################################
+##
+## Copyright (C) 2020 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn  {} {@var{angle} =} xtickangle ()
+## @deftypefnx {} {@var{angle} =} xtickangle (@var{hax})
+## @deftypefnx {} {} xtickangle (@var{angle})
+## @deftypefnx {} {} xtickangle (@var{hax}, @var{angle})
+## Query or set the rotation angle of the tick labels on the x-axis of the
+## current axes.
+##
+## When called without an argument, return the rotation angle in degrees of the
+## tick labels as specified in the axes property @qcode{"XTickLabelRotation"}.
+## When called with a numeric scalar @var{angle}, rotate the tick labels
+## counterclockwise to @var{angle} degrees.
+##
+## If the first argument @var{hax} is an axes handle, then operate on this axes
+## rather than the current axes returned by @code{gca}.
+##
+## Programming Note: Requesting a return value while also setting a specified
+## rotation will result in an error.
+##
+## @seealso{ytickangle, ztickangle, get, set}
+## @end deftypefn
+
+function retval = xtickangle (hax, angle)
+
+  switch (nargin)
+    case 0
+      retval = __tickangle__ (mfilename ());
+
+    case 1
+      if (nargout > 0)
+        retval = __tickangle__ (mfilename (), hax);
+      else
+        __tickangle__ (mfilename (), hax);
+      endif
+
+    case 2
+      if (nargout > 0)
+        retval = __tickangle__ (mfilename (), hax, angle);
+      else
+        __tickangle__ (mfilename (), hax, angle);
+      endif
+
+  endswitch
+
+endfunction
+
+
+%!test
+%! hf = figure ("visible", "off");
+%! hax = axes (hf);
+%! unwind_protect
+%!   xtickangle (45);
+%!   assert (xtickangle (), 45);
+%!   xtickangle (hax, 90);
+%!   a1 = xtickangle ();
+%!   a2 = xtickangle (hax);
+%!   assert (a1, a2);
+%!   assert (a1, 90);
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
+## Test input validation
+%!error <HAX must be a handle to an axes object> xtickangle (0, 45)
+%!error <ANGLE must be .* scalar> xtickangle (eye (2))
+%!error <ANGLE must be .* numeric> xtickangle ({90})
+%!error <ANGLE must be .* finite> xtickangle (Inf)
+%!error <called with output query and input set value> ang = xtickangle (45)
--- a/scripts/plot/appearance/xticklabels.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/xticklabels.m	Thu Nov 19 13:08:00 2020 -0800
@@ -142,7 +142,7 @@
 %! hf = figure ("visible", "off");
 %! unwind_protect
 %!   set (gca, "xticklabelmode", "auto");
-%!   hax = gca;
+%!   hax = gca ();
 %!   vals1 = xticklabels;
 %!   assert (xticklabels (hax), vals1);
 %!   mode1 = xticklabels ("mode");
@@ -164,7 +164,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   hax = gca;
+%!   hax = gca ();
 %!   fail ("xticklabels (-1, {})", "HAX must be a handle to an axes");
 %!   fail ("tmp = xticklabels (hax, {'A','B'})", "too many output arguments");
 %!   fail ("tmp = xticklabels (hax, [0, 1])", "too many output arguments");
--- a/scripts/plot/appearance/xticks.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/xticks.m	Thu Nov 19 13:08:00 2020 -0800
@@ -122,7 +122,7 @@
 %! hf = figure ("visible", "off");
 %! unwind_protect
 %!   set (gca, "xtickmode", "auto");
-%!   hax = gca;
+%!   hax = gca ();
 %!   vals1 = xticks;
 %!   assert (xticks (hax), vals1);
 %!   mode1 = xticks ("mode");
@@ -143,7 +143,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   hax = gca;
+%!   hax = gca ();
 %!   fail ("xticks (-1, [0 1])", "HAX must be a handle to an axes");
 %!   fail ("tmp = xticks (hax, [0 1])", "too many output arguments");
 %!   fail ("tmp = xticks (hax, 'auto')", "too many .* for arg: auto");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/appearance/ytickangle.m	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,93 @@
+########################################################################
+##
+## Copyright (C) 2020 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn  {} {@var{angle} =} ytickangle ()
+## @deftypefnx {} {@var{angle} =} ytickangle (@var{hax})
+## @deftypefnx {} {} ytickangle (@var{angle})
+## @deftypefnx {} {} ytickangle (@var{hax}, @var{angle})
+## Query or set the rotation angle of the tick labels on the y-axis of the
+## current axes.
+##
+## When called without an argument, return the rotation angle in degrees of the
+## tick labels as specified in the axes property @qcode{"YTickLabelRotation"}.
+## When called with a numeric scalar @var{angle}, rotate the tick labels
+## counterclockwise to @var{angle} degrees.
+##
+## If the first argument @var{hax} is an axes handle, then operate on this axes
+## rather than the current axes returned by @code{gca}.
+##
+## Programming Note: Requesting a return value while also setting a specified
+## rotation will result in an error.
+##
+## @seealso{xtickangle, ztickangle, get, set}
+## @end deftypefn
+
+function retval = ytickangle (hax, angle)
+
+  switch (nargin)
+    case 0
+      retval = __tickangle__ (mfilename ());
+
+    case 1
+      if (nargout > 0)
+        retval = __tickangle__ (mfilename (), hax);
+      else
+        __tickangle__ (mfilename (), hax);
+      endif
+
+    case 2
+      if (nargout > 0)
+        retval = __tickangle__ (mfilename (), hax, angle);
+      else
+        __tickangle__ (mfilename (), hax, angle);
+      endif
+
+  endswitch
+
+endfunction
+
+
+%!test
+%! hf = figure ("visible", "off");
+%! hax = axes (hf);
+%! unwind_protect
+%!   ytickangle (45);
+%!   assert (ytickangle (), 45);
+%!   ytickangle (hax, 90);
+%!   a1 = ytickangle ();
+%!   a2 = ytickangle (hax);
+%!   assert (a1, a2);
+%!   assert (a1, 90);
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
+## Test input validation
+%!error <HAX must be a handle to an axes object> ytickangle (0, 45)
+%!error <ANGLE must be .* scalar> ytickangle (eye (2))
+%!error <ANGLE must be .* numeric> ytickangle ({90})
+%!error <ANGLE must be .* finite> ytickangle (Inf)
+%!error <called with output query and input set value> ang = ytickangle (45)
--- a/scripts/plot/appearance/yticklabels.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/yticklabels.m	Thu Nov 19 13:08:00 2020 -0800
@@ -142,7 +142,7 @@
 %! hf = figure ("visible", "off");
 %! unwind_protect
 %!   set (gca, "yticklabelmode", "auto");
-%!   hax = gca;
+%!   hax = gca ();
 %!   vals1 = yticklabels;
 %!   assert (yticklabels (hax), vals1);
 %!   mode1 = yticklabels ("mode");
@@ -164,7 +164,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   hax = gca;
+%!   hax = gca ();
 %!   fail ("yticklabels (-1, {})", "HAX must be a handle to an axes");
 %!   fail ("tmp = yticklabels (hax, {'A','B'})", "too many output arguments");
 %!   fail ("tmp = yticklabels (hax, [0, 1])", "too many output arguments");
--- a/scripts/plot/appearance/yticks.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/yticks.m	Thu Nov 19 13:08:00 2020 -0800
@@ -124,7 +124,7 @@
 %! hf = figure ("visible", "off");
 %! unwind_protect
 %!   set (gca, "ytickmode", "auto");
-%!   hax = gca;
+%!   hax = gca ();
 %!   vals1 = yticks;
 %!   assert (yticks (hax), vals1);
 %!   mode1 = yticks ("mode");
@@ -145,7 +145,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   hax = gca;
+%!   hax = gca ();
 %!   fail ("yticks (-1, [0 1])", "HAX must be a handle to an axes");
 %!   fail ("tmp = yticks (hax, [0 1])", "too many output arguments");
 %!   fail ("tmp = yticks (hax, 'auto')", "too many .* for arg: auto");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/appearance/ztickangle.m	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,93 @@
+########################################################################
+##
+## Copyright (C) 2020 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn  {} {@var{angle} =} ztickangle ()
+## @deftypefnx {} {@var{angle} =} ztickangle (@var{hax})
+## @deftypefnx {} {} ztickangle (@var{angle})
+## @deftypefnx {} {} ztickangle (@var{hax}, @var{angle})
+## Query or set the rotation angle of the tick labels on the z-axis of the
+## current axes.
+##
+## When called without an argument, return the rotation angle in degrees of the
+## tick labels as specified in the axes property @qcode{"ZTickLabelRotation"}.
+## When called with a numeric scalar @var{angle}, rotate the tick labels
+## counterclockwise to @var{angle} degrees.
+##
+## If the first argument @var{hax} is an axes handle, then operate on this axes
+## rather than the current axes returned by @code{gca}.
+##
+## Programming Note: Requesting a return value while also setting a specified
+## rotation will result in an error.
+##
+## @seealso{xtickangle, ytickangle, get, set}
+## @end deftypefn
+
+function retval = ztickangle (hax, angle)
+
+  switch (nargin)
+    case 0
+      retval = __tickangle__ (mfilename ());
+
+    case 1
+      if (nargout > 0)
+        retval = __tickangle__ (mfilename (), hax);
+      else
+        __tickangle__ (mfilename (), hax);
+      endif
+
+    case 2
+      if (nargout > 0)
+        retval = __tickangle__ (mfilename (), hax, angle);
+      else
+        __tickangle__ (mfilename (), hax, angle);
+      endif
+
+  endswitch
+
+endfunction
+
+
+%!test
+%! hf = figure ("visible", "off");
+%! hax = axes (hf);
+%! unwind_protect
+%!   ztickangle (45);
+%!   assert (ztickangle (), 45);
+%!   ztickangle (hax, 90);
+%!   a1 = ztickangle ();
+%!   a2 = ztickangle (hax);
+%!   assert (a1, a2);
+%!   assert (a1, 90);
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
+## Test input validation
+%!error <HAX must be a handle to an axes object> ztickangle (0, 45)
+%!error <ANGLE must be .* scalar> ztickangle (eye (2))
+%!error <ANGLE must be .* numeric> ztickangle ({90})
+%!error <ANGLE must be .* finite> ztickangle (Inf)
+%!error <called with output query and input set value> ang = ztickangle (45)
--- a/scripts/plot/appearance/zticklabels.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/zticklabels.m	Thu Nov 19 13:08:00 2020 -0800
@@ -80,7 +80,7 @@
       arg = varargin{2};
 
     otherwise
-      print_usage;
+      print_usage ();
 
   endswitch
 
@@ -132,7 +132,7 @@
     endswitch
 
   else
-    print_usage;
+    print_usage ();
   endif
 
 endfunction
@@ -142,7 +142,7 @@
 %! hf = figure ("visible", "off");
 %! unwind_protect
 %!   set (gca, "zticklabelmode", "auto");
-%!   hax = gca;
+%!   hax = gca ();
 %!   vals1 = zticklabels;
 %!   assert (zticklabels (hax), vals1);
 %!   mode1 = zticklabels ("mode");
@@ -164,7 +164,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   hax = gca;
+%!   hax = gca ();
 %!   fail ("zticklabels (-1, {})", "HAX must be a handle to an axes");
 %!   fail ("tmp = zticklabels (hax, {'A','B'})", "too many output arguments");
 %!   fail ("tmp = zticklabels (hax, [0, 1])", "too many output arguments");
--- a/scripts/plot/appearance/zticks.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/appearance/zticks.m	Thu Nov 19 13:08:00 2020 -0800
@@ -122,7 +122,7 @@
 %! hf = figure ("visible", "off");
 %! unwind_protect
 %!   set (gca, "ztickmode", "auto");
-%!   hax = gca;
+%!   hax = gca ();
 %!   vals1 = zticks;
 %!   assert (zticks (hax), vals1);
 %!   mode1 = zticks ("mode");
@@ -143,7 +143,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   hax = gca;
+%!   hax = gca ();
 %!   fail ("zticks (-1, [0 1])", "HAX must be a handle to an axes");
 %!   fail ("tmp = zticks (hax, [0 1])", "too many output arguments");
 %!   fail ("tmp = zticks (hax, 'auto')", "too many .* for arg: auto");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/draw/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/plot/draw/area.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/area.m	Thu Nov 19 13:08:00 2020 -0800
@@ -41,7 +41,7 @@
 ## the shading under the curve should be defined.  The default level is 0.
 ##
 ## Additional property/value pairs are passed directly to the underlying patch
-## object. The full list of properties is documented at
+## object.  The full list of properties is documented at
 ## @ref{Patch Properties}.
 ##
 ## If the first argument @var{hax} is an axes handle, then plot into this axes,
@@ -207,7 +207,7 @@
   set (kids, prop, get (h, prop));
 endfunction
 
-function move_baseline (h, d)
+function move_baseline (h, ~)
   persistent recursion = false;
 
   ## Don't allow recursion
@@ -225,7 +225,7 @@
           endif
         endif
       endfor
-      update_data (h, d);
+      update_data (h, []);
     unwind_protect_cleanup
       recursion = false;
     end_unwind_protect
@@ -233,7 +233,7 @@
 
 endfunction
 
-function update_data (h, d)
+function update_data (h, ~)
 
   hlist = get (h, "areagroup");
   bv = get (h, "basevalue");
@@ -288,7 +288,7 @@
 %! title ("area() plot of sorted data");
 
 ## Test input validation
-%!error area ()
+%!error <Invalid call> area ()
 %!error area (1,2,3,4)
 %!error <X and Y must be real vectors or matrices> area ({1})
 %!error <X and Y must be real vectors or matrices> area (1+i)
--- a/scripts/plot/draw/bar.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/bar.m	Thu Nov 19 13:08:00 2020 -0800
@@ -124,7 +124,6 @@
   [varargout{:}] = __bar__ (true, "bar", varargin{:});
 endfunction
 
-
 %!demo
 %! clf;
 %! y = rand (11, 1);
@@ -144,3 +143,17 @@
 %! clf;
 %! h = bar (rand (5, 3), "stacked");
 %! title ("bar() graph with stacked style");
+
+%!demo
+%! clf;
+%! y = -rand (3) .* eye (3) + rand (3) .* (! eye (3));
+%! h = bar (y, "stacked");
+%! title ("stacked bar() graph including intermingled negative values");
+
+%% Test input validation
+%!error bar ()
+%!error <Y must be numeric> bar ("foo")
+%!error <X must be a vector> bar ([1 2; 3 4], [1 2 3 4])
+%!error <X vector values must be unique> bar ([1 2 3 3], [1 2 3 4])
+%!error <length of X and Y must be equal> bar ([1 2 3], [1 2 3 4])
+%!error <length of X and Y must be equal> bar ([1 2 3 4], [1 2 3])
--- a/scripts/plot/draw/barh.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/barh.m	Thu Nov 19 13:08:00 2020 -0800
@@ -72,7 +72,7 @@
 ##
 ## The optional return value @var{h} is a graphics handle to the created
 ## bar series hggroup.  For a description of the use of the
-## bar series, @pxref{XREFbar,,bar}.
+## bar series, @pxref{XREFbar,,@code{bar}}.
 ## @seealso{bar, hist, pie, plot, patch}
 ## @end deftypefn
 
@@ -95,3 +95,17 @@
 %! set (h(2), "facecolor", "g");
 %! set (h(3), "facecolor", "b");
 %! title ("barh() graph w/multiple bars");
+
+%!demo
+%! clf;
+%! x = -rand (3) .* eye (3) + rand (3) .* (! eye (3));
+%! h = barh (x, "stacked");
+%! title ("stacked barh() graph including intermingled negative values");
+
+%% Test input validation
+%!error barh ()
+%!error <Y must be numeric> barh ("foo")
+%!error <X must be a vector> barh ([1 2; 3 4], [1 2 3 4])
+%!error <X vector values must be unique> barh ([1 2 3 3], [1 2 3 4])
+%!error <length of X and Y must be equal> barh ([1 2 3], [1 2 3 4])
+%!error <length of X and Y must be equal> barh ([1 2 3 4], [1 2 3])
--- a/scripts/plot/draw/camlight.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/camlight.m	Thu Nov 19 13:08:00 2020 -0800
@@ -80,10 +80,11 @@
 ## @end group
 ## @end example
 ##
-## Here the light is first pitched upwards (@pxref{XREFcamup,,camup}) from the
-## camera position (@pxref{XREFcampos,,campos}) by 30 degrees.  It is then
-## yawed by 45 degrees to the right.  Both rotations are centered around the
-## camera target (@pxref{XREFcamtarget,,camtarget}).
+## Here the light is first pitched upwards (@pxref{XREFcamup,,@code{camup}})
+## from the camera position (@pxref{XREFcampos,,@code{campos}}) by 30
+## degrees.  It is then yawed by 45 degrees to the right.  Both rotations
+## are centered around the camera target
+## (@pxref{XREFcamtarget,,@code{camtarget}}).
 ##
 ## Return a handle to further manipulate the light object
 ##
--- a/scripts/plot/draw/colorbar.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/colorbar.m	Thu Nov 19 13:08:00 2020 -0800
@@ -220,7 +220,7 @@
     set (hax, "units", orig_props.units,
               "position", orig_props.position,
               "outerposition", orig_props.outerposition,
-              "activepositionproperty", orig_props.activepositionproperty);
+              "positionconstraint", orig_props.positionconstraint);
     set (hax, "units", units);
   endif
 
@@ -252,7 +252,7 @@
     ## FIXME: Matlab does not require the "position" property to be active.
     ##        Is there a way to determine the plotbox position for the
     ##        gnuplot graphics toolkit when the outerposition is active?
-    set (hax, "activepositionproperty", "position");
+    set (hax, "positionconstraint", "innerposition");
     props = get (hax);
     props.__axes_handle__ = hax;
     position = props.position;
@@ -277,7 +277,7 @@
     ## Create colorbar axes if necessary
     if (new_colorbar)
       hcb = axes ("parent", hpar, "tag", "colorbar",
-                  "activepositionproperty", "position",
+                  "positionconstraint", "innerposition",
                   "units", get (hax, "units"), "position", cbpos,
                   "colormap", cmap,
                   "box", "on", "xdir", "normal", "ydir", "normal");
@@ -440,7 +440,7 @@
     set (hax, "units", orig_props.units,
               "position", orig_props.position,
               "outerposition", orig_props.outerposition,
-              "activepositionproperty", orig_props.activepositionproperty);
+              "positionconstraint", orig_props.positionconstraint);
     set (hax, "units", units);
 
     ## Nullify colorbar link (can't delete properties yet)
@@ -471,7 +471,7 @@
 endfunction
 
 ## Update colorbar when changes to axes or figure colormap have occurred.
-function cb_colormap (h, d, hax, hcb, hi, init_sz)
+function cb_colormap (h, ~, hax, hcb, hi, init_sz)
   persistent sz = init_sz;
 
   if (ishghandle (h))
@@ -536,7 +536,7 @@
       scale = [scale, 1];
     endif
     if (strcmp (get (cf, "__graphics_toolkit__"), "gnuplot")
-        && strcmp (props.activepositionproperty, "outerposition"))
+        && strcmp (props.positionconstraint, "outerposition"))
       props.outerposition = props.outerposition .* [1, 1, scale];
       off = 0.5 * (props.outerposition (3:4) - __actual_axis_position__ (props)(3:4));
     else
@@ -859,7 +859,7 @@
 %!demo
 %! clf;
 %! colormap ("default");
-%! axes;
+%! axes ();
 %! colorbar ();
 %! hold on;
 %! contour (peaks ());
@@ -886,7 +886,7 @@
 %! shading interp;
 %! axis ("tight", "square");
 %! colorbar ();
-#%! axes ("color","none","box","on","activepositionproperty","position");
+#%! axes ("color", "none", "box", "on", "positionconstraint", "innerposition");
 
 %!demo
 %! clf;
--- a/scripts/plot/draw/comet.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/comet.m	Thu Nov 19 13:08:00 2020 -0800
@@ -46,9 +46,11 @@
 
   [hax, varargin, nargin] = __plt_get_axis_arg__ ("comet", varargin{:});
 
-  if (nargin == 0)
+  if (nargin == 0 || nargin > 3)
     print_usage ();
-  elseif (nargin == 1)
+  endif
+
+  if (nargin == 1)
     y = varargin{1};
     x = 1:numel (y);
     p = 5 / numel (y);
--- a/scripts/plot/draw/compass.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/compass.m	Thu Nov 19 13:08:00 2020 -0800
@@ -137,8 +137,8 @@
 %! title ("compass() example");
 
 ## Test input validation
-%!error compass ()
-%!error compass (1,2,3,4)
+%!error <Invalid call> compass ()
+%!error <Invalid call> compass (1,2,3,4)
 %!error compass (1, "-r", 2)
 %!error <invalid linestyle STYLE> compass (1, "abc")
 %!error <invalid linestyle STYLE> compass (1, {1})
--- a/scripts/plot/draw/contourc.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/contourc.m	Thu Nov 19 13:08:00 2020 -0800
@@ -181,8 +181,8 @@
 %! assert (lev_obs, lev_exp, eps);
 
 ## Test input validation
-%!error contourc ()
-%!error contourc (1,2,3,4,5)
+%!error <Invalid call> contourc ()
+%!error <Invalid call> contourc (1,2,3,4,5)
 %!error <X, Y, and Z must be numeric> contourc ({1})
 %!error <X, Y, and Z must be numeric> contourc ({1}, 2, 3)
 %!error <X, Y, and Z must be numeric> contourc (1, {2}, 3)
--- a/scripts/plot/draw/cylinder.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/cylinder.m	Thu Nov 19 13:08:00 2020 -0800
@@ -61,17 +61,17 @@
 
   [hax, args, nargs] = __plt_get_axis_arg__ ("cylinder", varargin{:});
 
-  if (nargs == 0)
+  if (nargs > 2)
+    print_usage ();
+  elseif (nargs == 0)
     r = [1, 1];
     n = 20;
   elseif (nargs == 1)
     r = args{1};
     n = 20;
-  elseif (nargs == 2)
+  else
     r = args{1};
     n = args{2};
-  else
-    print_usage ();
   endif
 
   if (length (r) < 2)
--- a/scripts/plot/draw/errorbar.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/errorbar.m	Thu Nov 19 13:08:00 2020 -0800
@@ -247,7 +247,7 @@
 ## Invisible figure used for tests
 %!shared hf, hax
 %! hf = figure ("visible", "off");
-%! hax = axes;
+%! hax = axes ();
 
 %!error errorbar ()
 %!error errorbar (1)
--- a/scripts/plot/draw/feather.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/feather.m	Thu Nov 19 13:08:00 2020 -0800
@@ -135,8 +135,8 @@
 %! title ("feather plot");
 
 ## Test input validation
-%!error feather ()
-%!error feather (1,2,3,4)
+%!error <Invalid call> feather ()
+%!error <Invalid call> feather (1,2,3,4)
 %!error feather (1, "-r", 2)
 %!error <invalid linestyle STYLE> feather (1, "abc")
 %!error <invalid linestyle STYLE> feather (1, {1})
--- a/scripts/plot/draw/fplot.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/fplot.m	Thu Nov 19 13:08:00 2020 -0800
@@ -128,6 +128,7 @@
   n = 5;
   tol = 2e-3;
   fmt = {};
+  prop_vals = {};
   while (i <= numel (varargin))
     arg = varargin{i};
     if (ischar (arg))
@@ -138,7 +139,7 @@
         if (i == numel (varargin))
           error ("fplot: bad input in position %d", i);
         endif
-        fmt(end+(1:2)) = varargin([i, i+1]);
+        prop_vals(end+(1:2)) = varargin([i, i+1]);
         i++;  # Skip PROPERTY.
       endif
     elseif (isnumeric (arg) && isscalar (arg) && arg > 0)
@@ -225,18 +226,24 @@
     if (isempty (hax))
       hax = gca ();
     endif
-    plot (hax, x, y, fmt{:});
+    hl = plot (hax, x, y, fmt{:});
+    if (isempty (get (hl(1), "displayname")))
+      ## Set displayname for legend if FMT did not contain a name.
+      if (isvector (y))
+        set (hl, "displayname", nam);
+      else
+        for i = 1:columns (y)
+          nams{i} = sprintf ("%s(:,%i)", nam, i);
+        endfor
+        set (hl, {"displayname"}, nams(:));
+      endif
+    endif
+    ## Properties passed as input arguments override other properties.
+    if (! isempty (prop_vals))
+      set (hl, prop_vals{:});
+    endif
     axis (hax, limits);
-    ## FIXME: If hold is on, then this erases the existing legend rather than
-    ##        adding to it.
-    if (isvector (y))
-      legend (hax, nam);
-    else
-      for i = 1:columns (y)
-        nams{i} = sprintf ("%s(:,%i)", nam, i);
-      endfor
-      legend (hax, nams{:});
-    endif
+    legend (hax, "show");
   endif
 
 endfunction
@@ -281,9 +288,31 @@
 %! assert (rows (x) == rows (y));
 %! assert (y, repmat ([0], size (x)));
 
+%!test <*59274>
+%! ## Manual displayname overrides automatic legend entry
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   fplot (@sin, [0, 3], "displayname", "mysin");
+%!   hl = legend ();
+%!   assert (get (hl, "string"), {"mysin"});
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
+%!test <*59274>
+%! ## displayname in format string overrides automatic legend entry
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   fplot (@sin, [0, 3], "+;mysin;");
+%!   hl = legend ();
+%!   assert (get (hl, "string"), {"mysin"});
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
 ## Test input validation
-%!error fplot ()
-%!error fplot (1,2,3,4,5,6)
+%!error <Invalid call> fplot ()
+%!error <Invalid call> fplot (1,2,3,4,5,6)
 %!error <FN must be a function handle> fplot (1, [0 1])
 %!error <LIMITS must be a real vector> fplot (@cos, [i, 2*i])
 %!error <LIMITS must be a real vector with 2 or 4> fplot (@cos, [1])
--- a/scripts/plot/draw/hist.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/hist.m	Thu Nov 19 13:08:00 2020 -0800
@@ -118,14 +118,15 @@
   ## Process possible second argument
   if (nargin == 1 || ischar (varargin{iarg}))
     n = 10;
-    ## Use range type to preserve accuracy
+    ## Use integer range values and perform division last to preserve
+    ## accuracy.
     if (min_val != max_val)
-      x = (0.5:n) * (1/n);
-      x = (max_val - min_val) * x + min_val;
+      x = 1:2:2*n;
+      x = ((max_val - min_val) * x + 2*n*min_val) / (2*n);
     else
       x = (-floor ((n-1)/2):ceil ((n-1)/2)) + min_val;
     endif
-    x = x.';  # Convert to matrix;
+    x = x.';  # Convert to matrix
   else
     ## Parse bin specification argument
     x = varargin{iarg++};
@@ -143,14 +144,15 @@
       if (n <= 0)
         error ("hist: number of bins NBINS must be positive");
       endif
-      ## Use range type to preserve accuracy
+      ## Use integer range values and perform division last to preserve
+      ## accuracy.
       if (min_val != max_val)
-        x = (0.5:n) * (1/n);
-        x = (max_val - min_val) * x + min_val;
+        x = 1:2:2*n;
+        x = ((max_val - min_val) * x + 2*n*min_val) / (2*n);
       else
         x = (-floor ((n-1)/2):ceil ((n-1)/2)) + min_val;
       endif
-      x = x.';  # Convert to matrix;
+      x = x.';  # Convert to matrix
     elseif (isvector (x))
       equal_bin_spacing = strcmp (typeinfo (x), "range");
       if (! equal_bin_spacing)
@@ -198,7 +200,7 @@
     ## Lookup is more efficient if y is sorted, but sorting costs.
     if (! equal_bin_spacing && n > sqrt (rows (y) * 1e4))
       y = sort (y);
-    end
+    endif
 
     nanidx = isnan (y);
     y(nanidx) = 0;
@@ -208,21 +210,21 @@
         d = 1;
       else
         d = (x(end) - x(1)) / (length (x) - 1);
-      end
+      endif
       cutlen = length (cutoff);
       for j = 1:y_nc
         freq(:,j) = accumarray (1 + max (0, min (cutlen, ceil ((double (y(:,j))
                                                          - cutoff(1)) / d))),
                                 double (! nanidx(:,j)),
                                 [n, 1]);
-      end
+      endfor
     else
       for j = 1:y_nc
         i = lookup (cutoff, y(:,j));
         i = 1 + i - (cutoff(max (i, 1)) == y(:,j));
         freq(:,j) = accumarray (i, double (! nanidx(:,j)), [n, 1]);
-      end
-    end
+      endfor
+    endif
   endif
 
   if (norm)
@@ -386,13 +388,13 @@
 %! assert (isa (xx, "single"));
 
 ## Test input validation
-%!error hist ()
+%!error <Invalid call> hist ()
 %!error <Y must be real-valued> hist (2+i)
 %!error <bin specification must be a numeric> hist (1, {0,1,2})
 %!error <number of bins NBINS must be positive> hist (1, 0)
 %!test
 %! hf = figure ("visible", "off");
-%! hax = gca;
+%! hax = gca ();
 %! unwind_protect
 %!   fail ("hist (hax, 1, [2 1 0])", "warning", "bin values X not sorted");
 %! unwind_protect_cleanup
--- a/scripts/plot/draw/isocaps.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/isocaps.m	Thu Nov 19 13:08:00 2020 -0800
@@ -57,7 +57,7 @@
 ## vectors with lengths corresponding to the dimensions of @var{v}, then the
 ## volume data is taken at the specified points.  If @var{x}, @var{y}, or
 ## @var{z} are empty, the grid corresponds to the indices (@code{1:n}) in
-## the respective direction (@pxref{XREFmeshgrid,,meshgrid}).
+## the respective direction (@pxref{XREFmeshgrid,,@code{meshgrid}}).
 ##
 ## The optional parameter @var{which_caps} can have one of the following
 ## string values which defines how the data will be enclosed:
@@ -376,7 +376,7 @@
 %! [x, y, z] = meshgrid (lin, lin, lin);
 %! v = abs ((x-0.45).^2 + (y-0.55).^2 + (z-0.8).^2);
 %! hf = clf;
-%! ha = axes;
+%! ha = axes ();
 %! view (3);  box off;
 %! fvc_iso = isosurface (x, y, z, v, isoval);
 %! cmap = get (hf, "Colormap");
@@ -544,8 +544,8 @@
 %! assert (rows (vertices), rows (fvcdata));
 
 ## test for each error
-%!error isocaps ()
-%!error isocaps (1,2,3,4,5,6,7,8,9)
+%!error <Invalid call> isocaps ()
+%!error <Invalid call> isocaps (1,2,3,4,5,6,7,8,9)
 %!error <parameter 'foo' not supported> isocaps (val, iso, "foo")
 %!error <incorrect number of input arguments> isocaps (x, val, iso)
 %!error <incorrect number of input arguments> isocaps (xx, yy, zz, val, iso, 5)
--- a/scripts/plot/draw/isocolors.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/isocolors.m	Thu Nov 19 13:08:00 2020 -0800
@@ -185,11 +185,11 @@
 %! assert (rows (cdat) == rows (v));
 
 ## Test input validation
-%!error isocolors ()
-%!error isocolors (1)
-%!error isocolors (1,2,3)
-%!error isocolors (1,2,3,4,5,6)
-%!error isocolors (1,2,3,4,5,6,7,8)
+%!error <Invalid call> isocolors ()
+%!error <Invalid call> isocolors (1)
+%!error <Invalid call> isocolors (1,2,3)
+%!error <Invalid call> isocolors (1,2,3,4,5,6)
+%!error <Invalid call> isocolors (1,2,3,4,5,6,7,8)
 %!error <last argument must be a vertex list> isocolors (1, {1})
 %!error <last argument must be a vertex list> isocolors (1, [1 2 3 4])
 %!error <last argument must be a .*patch handle> isocolors (1, 0)
--- a/scripts/plot/draw/isonormals.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/isonormals.m	Thu Nov 19 13:08:00 2020 -0800
@@ -65,12 +65,14 @@
 
   narg = nargin;
   negate = false;
-  if (ischar (varargin{narg}))
-    if (strcmpi (varargin{narg}, "negate"))
-      negate = true;
-      narg -= 1;
-    else
-      error ("isonormals: Unknown option '%s'", varargin{narg});
+  if (nargin > 2)
+    if (ischar (varargin{end}))
+      if (strcmpi (varargin{end}, "negate"))
+        negate = true;
+        narg -= 1;
+      else
+        error ("isonormals: Unknown option '%s'", varargin{end});
+      endif
     endif
   endif
 
@@ -191,11 +193,11 @@
 %! assert (all (dirn(isfinite (dirn)) <= 0));
 
 ## Test input validation
-%!error isonormals ()
-%!error isonormals (1)
-%!error isonormals (1,2,3)
-%!error isonormals (1,2,3,4)
-%!error isonormals (1,2,3,4,5,6)
+%!error <Invalid call> isonormals ()
+%!error <Invalid call> isonormals (1)
+%!error <Invalid call> isonormals (1,2,3)
+%!error <Invalid call> isonormals (1,2,3,4)
+%!error <Invalid call> isonormals (1,2,3,4,5,6)
 %!error <Unknown option 'foo'> isonormals (x, y, z, val, vert, "foo")
 %!error <must be a list of vertices> isonormals (1, {1})
 %!error <must be a list of vertices> isonormals (1, [1 2 3 4])
--- a/scripts/plot/draw/isosurface.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/isosurface.m	Thu Nov 19 13:08:00 2020 -0800
@@ -59,7 +59,7 @@
 ## vectors with lengths corresponding to the dimensions of @var{v}, then the
 ## volume data is taken at the specified points.  If @var{x}, @var{y}, or
 ## @var{z} are empty, the grid corresponds to the indices (@code{1:n}) in
-## the respective direction (@pxref{XREFmeshgrid,,meshgrid}).
+## the respective direction (@pxref{XREFmeshgrid,,@code{meshgrid}}).
 ##
 ## The optional input argument @var{col}, which is a three-dimensional array
 ## of the same size as @var{v}, specifies coloring of the isosurface.  The
@@ -168,7 +168,7 @@
     warning ("isosurface: triangulation is empty");
   endif
 
-  # remove faces for which at least one of the vertices is NaN
+  ## remove faces for which at least one of the vertices is NaN
   vert_nan = 1:size (fvc.vertices, 1);
   vert_nan(any (isnan (fvc.vertices), 2)) = NaN;
   fvc.faces = vert_nan(fvc.faces);
@@ -307,7 +307,7 @@
       colors = varargin{6};
 
     otherwise
-      error ("isosurface: incorrect number of input arguments")
+      error ("isosurface: incorrect number of input arguments");
 
   endswitch
 
@@ -355,19 +355,19 @@
   endif
 
   if (! isscalar (isoval))
-    error ("isosurface: ISOVAL must be a scalar")
+    error ("isosurface: ISOVAL must be a scalar");
   endif
 
   ## check colors
   if (! isempty (colors))
     if (! size_equal (v, colors))
-      error ("isosurface: COL must match the size of V")
+      error ("isosurface: COL must match the size of V");
     endif
     if (nout == 2)
-      warning ("isosurface: colors will be calculated, but no output argument to receive it.");
+      warning ("isosurface: colors will be calculated, but no output argument to receive it");
     endif
   elseif (nout >= 3)
-    error ("isosurface: COL must be passed to return C")
+    error ("isosurface: COL must be passed to return C");
   endif
 
 endfunction
@@ -559,8 +559,8 @@
 %! assert (size (fvc.facevertexcdata), [7 1]);
 
 ## test for each error and warning
-%!error isosurface ()
-%!error isosurface (1,2,3,4,5,6,7,8,9)
+%!error <Invalid call> isosurface ()
+%!error <Invalid call> isosurface (1,2,3,4,5,6,7,8,9)
 %!error <parameter 'foobar' not supported>
 %! fvc = isosurface (val, iso, "foobar");
 %!error <incorrect number of input arguments>
@@ -592,9 +592,9 @@
 %! [xx, yy, zz] = meshgrid (x, y, z);
 %! fvc = isosurface (xx, yy, zz, val, iso);
 %!error <ISOVAL must be a scalar> fvc = isosurface (val, [iso iso], yy)
-%!error <COL must match the size of V> fvc = isosurface (val, [iso iso]);
+%!error <COL must match the size of V> fvc = isosurface (val, [iso iso])
 %!error <COL must be passed to return C> [f, v, c] = isosurface (val, iso)
-%!warning <colors will be calculated, but no output argument to receive it.>
+%!warning <colors will be calculated, but no output argument to receive it>
 %! [f, v] = isosurface (val, iso, yy);
 
 ## test for __calc_isovalue_from_data__
--- a/scripts/plot/draw/light.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/light.m	Thu Nov 19 13:08:00 2020 -0800
@@ -163,9 +163,9 @@
 %! h_axes1 = axes ();
 %! surf (X, Y, Z, "LineStyle", "none", "FaceLighting", "none");
 %! hold on;
-%! surf (X + round(1.2 * size (Z, 2)), Y, Z, "LineStyle", "none", ...
+%! surf (X + round (1.2 * size (Z, 2)), Y, Z, "LineStyle", "none", ...
 %!       "FaceLighting", "flat");
-%! surf (X + round(2.4 * size (Z, 2)), Y, Z, "LineStyle", "none", ...
+%! surf (X + round (2.4 * size (Z, 2)), Y, Z, "LineStyle", "none", ...
 %!       "FaceLighting", "gouraud");
 %! axis tight
 %! axis equal
@@ -592,7 +592,7 @@
 
 %!test
 %! hf = figure ("visible", "off");
-%! ha = gca;
+%! ha = gca ();
 %! unwind_protect
 %!   h = light (ha, "Position", [1 2 3], "Color", "r");
 %!   assert (get (h, "Position"), [1 2 3]);
--- a/scripts/plot/draw/lightangle.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/lightangle.m	Thu Nov 19 13:08:00 2020 -0800
@@ -122,7 +122,7 @@
     pos -= get (hax, "CameraTarget");
   endif
 
-  pos = sph2cart (az, el, norm (pos));
+  [pos(1), pos(2), pos(3)] = sph2cart (az, el, norm (pos));
 
   if (strcmp (get (hl, "Style"), "local"))
     pos += get (hax, "CameraTarget");
@@ -165,8 +165,8 @@
 ## Test input validation
 %!error <Invalid call> lightangle ()
 %!error <Invalid call> lightangle (1, 2, 3, 4)
+%!error <Invalid call> [a, b, c] = lightangle (45, 30)
 %!error <Invalid call> [a, b] = lightangle (45, 30)
-%!error <Invalid call> [a, b, c] = lightangle (45, 30)
 %!error <HL must be a handle to a light object> lightangle (0)
 %!error <H must be a handle to an axes or light object> lightangle (0, 90, 45)
 %!error <AZ and EL must be numeric scalars> lightangle ([1 2], 0)
--- a/scripts/plot/draw/line.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/line.m	Thu Nov 19 13:08:00 2020 -0800
@@ -123,7 +123,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   h = line;
+%!   h = line ();
 %!   assert (findobj (hf, "type", "line"), h);
 %!   assert (get (h, "xdata"), [0 1], eps);
 %!   assert (get (h, "ydata"), [0 1], eps);
--- a/scripts/plot/draw/loglogerr.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/loglogerr.m	Thu Nov 19 13:08:00 2020 -0800
@@ -46,8 +46,8 @@
 ## @noindent
 ## which produces a double logarithm plot of @var{y} versus @var{x}
 ## with errors in the @var{y}-scale defined by @var{ey} and the plot
-## format defined by @var{fmt}.  @xref{XREFerrorbar,,errorbar}, for available
-## formats and additional information.
+## format defined by @var{fmt}.  @xref{XREFerrorbar,,@code{errorbar}}, for
+## available formats and additional information.
 ##
 ## If the first argument @var{hax} is an axes handle, then plot into this axes,
 ## rather than the current axes returned by @code{gca}.
--- a/scripts/plot/draw/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -9,6 +9,7 @@
   %reldir%/private/__contour__.m \
   %reldir%/private/__errplot__.m \
   %reldir%/private/__ezplot__.m \
+  %reldir%/private/__gnuplot_scatter__.m \
   %reldir%/private/__interp_cube__.m \
   %reldir%/private/__line__.m \
   %reldir%/private/__marching_cube__.m \
@@ -21,6 +22,7 @@
   %reldir%/private/__unite_shared_vertices__.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/area.m \
   %reldir%/bar.m \
   %reldir%/barh.m \
@@ -98,6 +100,7 @@
   %reldir%/stream2.m \
   %reldir%/stream3.m \
   %reldir%/streamline.m \
+  %reldir%/streamribbon.m \
   %reldir%/streamtube.m \
   %reldir%/surf.m \
   %reldir%/surface.m \
--- a/scripts/plot/draw/ostreamtube.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/ostreamtube.m	Thu Nov 19 13:08:00 2020 -0800
@@ -71,7 +71,7 @@
 ## @end group
 ## @end example
 ##
-## @seealso{stream3, streamline, streamtube}
+## @seealso{stream3, streamline, streamribbon, streamtube}
 ## @end deftypefn
 
 ## References:
@@ -97,8 +97,6 @@
   options = [];
   xyz = [];
   switch (nargin)
-    case 0
-      print_usage ();
     case 6
       [u, v, w, spx, spy, spz] = varargin{:};
       [m, n, p] = size (u);
@@ -118,7 +116,7 @@
     case 10
       [x, y, z, u, v, w, spx, spy, spz, options] = varargin{:};
     otherwise
-      error ("ostreamtube: invalid number of inputs");
+      print_usage ();
   endswitch
 
   scale = 1;
@@ -131,7 +129,7 @@
         scale = options(1);
         num_circum = options(2);
       otherwise
-        error ("ostreamtube: invalid number of OPTIONS elements");
+        error ("ostreamtube: OPTIONS must be a 1- or 2-element vector");
     endswitch
 
     if (! isreal (scale) || scale <= 0)
@@ -161,7 +159,7 @@
   for i = 1 : length (xyz)
     sl = xyz{i};
     if (! isempty (sl))
-      slx = sl(:, 1); sly = sl(:, 2); slz = sl(:, 3);
+      slx = sl(:,1); sly = sl(:,2); slz = sl(:,3);
       mxx(j) = max (slx); mnx(j) = min (slx);
       mxy(j) = max (sly); mny(j) = min (sly);
       mxz(j) = max (slz); mnz(j) = min (slz);
@@ -179,12 +177,12 @@
     num_vertices = rows (sl);
     if (! isempty (sl) && num_vertices > 2)
 
-      usl = interp3 (x, y, z, u, sl(:, 1), sl(:, 2), sl(:, 3));
-      vsl = interp3 (x, y, z, v, sl(:, 1), sl(:, 2), sl(:, 3));
-      wsl = interp3 (x, y, z, w, sl(:, 1), sl(:, 2), sl(:, 3));
+      usl = interp3 (x, y, z, u, sl(:,1), sl(:,2), sl(:,3));
+      vsl = interp3 (x, y, z, v, sl(:,1), sl(:,2), sl(:,3));
+      wsl = interp3 (x, y, z, w, sl(:,1), sl(:,2), sl(:,3));
       vv = sqrt (usl.*usl + vsl.*vsl + wsl.*wsl);
 
-      div_sl = interp3 (x, y, z, div, sl(:, 1), sl(:, 2), sl(:, 3));
+      div_sl = interp3 (x, y, z, div, sl(:,1), sl(:,2), sl(:,3));
       is_singular_div = find (isnan (div_sl), 1, "first");
 
       if (! isempty (is_singular_div))
@@ -211,61 +209,65 @@
   cp = cos (phi);
   sp = sin (phi);
 
-  X0 = sl(1, :);
-  X1 = sl(2, :);
-
-  ## 1st rotation axis
+  ## 1st streamline segment
+  X0 = sl(1,:);
+  X1 = sl(2,:);
   R = X1 - X0;
   RE = R / norm (R);
 
-  ## Initial radius
-  vold = vv(1);
-  vact = vv(2);
-  ract = rstart * exp (0.5 * div_sl(2) * norm (R) / vact) * sqrt (vold / vact);
-  vold = vact;
+  ## Guide point and its rotation to create a segment
+  KE = get_normal1 (RE);
+  K = rstart * KE;
+  XS0 = rotation (K, RE, cp, sp) + repmat (X0.', 1, num_circum);
+
+  ## End of first segment
+  ract = rstart * exp (0.5 * div_sl(2) * norm (R) / vv(2)) * ...
+                  sqrt (vv(1) / vv(2));
   rold = ract;
-
-  ## Guide point and its rotation to create a segment
-  N = get_normal1 (R);
-  K = ract * N;
+  K = ract * KE;
   XS = rotation (K, RE, cp, sp) + repmat (X1.', 1, num_circum);
 
-  px = zeros (num_circum, max_vertices - 1);
-  py = zeros (num_circum, max_vertices - 1);
-  pz = zeros (num_circum, max_vertices - 1);
-  pc = zeros (num_circum, max_vertices - 1);
+  px = zeros (num_circum, max_vertices);
+  py = zeros (num_circum, max_vertices);
+  pz = zeros (num_circum, max_vertices);
+  pc = zeros (num_circum, max_vertices);
 
-  px(:, 1) = XS(1, :).';
-  py(:, 1) = XS(2, :).';
-  pz(:, 1) = XS(3, :).';
-  pc(:, 1) = vact * ones (num_circum, 1);
+  px(:,1) = XS0(1,:).';
+  py(:,1) = XS0(2,:).';
+  pz(:,1) = XS0(3,:).';
+  pc(:,1) = vv(1) * ones (num_circum, 1);
+
+  px(:,2) = XS(1,:).';
+  py(:,2) = XS(2,:).';
+  pz(:,2) = XS(3,:).';
+  pc(:,2) = vv(2) * ones (num_circum, 1);
 
   for i = 3 : max_vertices
 
-    KK = K;
+    ## Next streamline segment
     X0 = X1;
-    X1 = sl(i, :);
+    X1 = sl(i,:);
     R = X1 - X0;
     RE = R / norm (R);
 
     ## Tube radius
-    vact = vv(i);
-    ract = rold * exp (0.5 * div_sl(i) * norm (R) / vact) * sqrt (vold / vact);
-    vold = vact;
+    ract = rold * exp (0.5 * div_sl(i) * norm (R) / vv(i)) * ...
+                  sqrt (vv(i-1) / vv(i));
     rold = ract;
 
-    ## Project KK onto RE and get the difference in order to calculate the next
-    ## guiding point
-    Kp = KK - RE * dot (KK, RE);
-    K = ract * Kp / norm (Kp);
+    ## Project KE onto RE and get the difference in order to transport
+    ## the normal vector KE along the vertex array
+    Kp = KE - RE * dot (KE, RE);
+    KE = Kp / norm (Kp);
+    K = ract * KE;
 
     ## Rotate around RE and collect surface patches
     XS = rotation (K, RE, cp, sp) + repmat (X1.', 1, num_circum);
 
-    px(:, i - 1) = XS(1, :).';
-    py(:, i - 1) = XS(2, :).';
-    pz(:, i - 1) = XS(3, :).';
-    pc(:, i - 1) = vact * ones (num_circum, 1);
+    px(:,i) = XS(1,:).';
+    py(:,i) = XS(2,:).';
+    pz(:,i) = XS(3,:).';
+    pc(:,i) = vv(i) * ones (num_circum, 1);
 
   endfor
 
@@ -277,9 +279,9 @@
 function N = get_normal1 (X)
 
   if ((X(3) == 0) && (X(1) == -X(2)))
-    N = [- X(2) - X(3), X(1), X(1)];
+    N = [(- X(2) - X(3)), X(1), X(1)];
   else
-    N = [X(3), X(3), - X(1) - X(2)];
+    N = [X(3), X(3), (- X(1) - X(2))];
   endif
 
   N /= norm (N);
@@ -294,20 +296,21 @@
   uy = U(2);
   uz = U(3);
 
-  Y(1, :) = X(1) * (cp + ux * ux * (1 - cp)) + ...
-            X(2) * (ux * uy * (1 - cp) - uz * sp) + ...
-            X(3) * (ux * uz * (1 - cp) + uy * sp);
+  Y(1,:) = X(1) * (cp + ux * ux * (1 - cp)) + ...
+           X(2) * (ux * uy * (1 - cp) - uz * sp) + ...
+           X(3) * (ux * uz * (1 - cp) + uy * sp);
 
-  Y(2, :) = X(1) * (uy * ux * (1 - cp) + uz * sp) + ...
-            X(2) * (cp + uy * uy * (1 - cp)) + ...
-            X(3) * (uy * uz * (1 - cp) - ux * sp);
+  Y(2,:) = X(1) * (uy * ux * (1 - cp) + uz * sp) + ...
+           X(2) * (cp + uy * uy * (1 - cp)) + ...
+           X(3) * (uy * uz * (1 - cp) - ux * sp);
 
-  Y(3, :) = X(1) * (uz * ux * (1 - cp) - uy * sp) + ...
-            X(2) * (uz * uy * (1 - cp) + ux * sp) + ...
-            X(3) * (cp + uz * uz * (1 - cp));
+  Y(3,:) = X(1) * (uz * ux * (1 - cp) - uy * sp) + ...
+           X(2) * (uz * uy * (1 - cp) + ux * sp) + ...
+           X(3) * (cp + uz * uz * (1 - cp));
 
 endfunction
 
+
 %!demo
 %! clf;
 %! [x, y, z] = meshgrid (-1:0.1:1, -1:0.1:1, -3.5:0.1:0);
@@ -353,14 +356,14 @@
 %! title ("Integration Towards Sink");
 
 ## Test input validation
-%!error ostreamtube ()
-%!error <invalid number of inputs> ostreamtube (1)
-%!error <invalid number of inputs> ostreamtube (1,2)
-%!error <invalid number of inputs> ostreamtube (1,2,3)
-%!error <invalid number of inputs> ostreamtube (1,2,3,4)
-%!error <invalid number of inputs> ostreamtube (1,2,3,4,5)
-%!error <invalid number of OPTIONS> ostreamtube (1,2,3,4,5,6, [1,2,3])
-%!error <SCALE must be a real scalar . 0> ostreamtube (1,2,3,4,5,6, [1i])
-%!error <SCALE must be a real scalar . 0> ostreamtube (1,2,3,4,5,6, [0])
-%!error <N must be greater than 2> ostreamtube (1,2,3,4,5,6, [1, 1i])
-%!error <N must be greater than 2> ostreamtube (1,2,3,4,5,6, [1, 2])
+%!error <Invalid call> ostreamtube ()
+%!error <Invalid call> ostreamtube (1)
+%!error <Invalid call> ostreamtube (1,2)
+%!error <Invalid call> ostreamtube (1,2,3)
+%!error <Invalid call> ostreamtube (1,2,3,4)
+%!error <Invalid call> ostreamtube (1,2,3,4,5)
+%!error <OPTIONS must be a 1- or 2-element> ostreamtube (1,2,3,4,5,6,[1,2,3])
+%!error <SCALE must be a real scalar . 0> ostreamtube (1,2,3,4,5,6,[1i])
+%!error <SCALE must be a real scalar . 0> ostreamtube (1,2,3,4,5,6,[0])
+%!error <N must be greater than 2> ostreamtube (1,2,3,4,5,6,[1,1i])
+%!error <N must be greater than 2> ostreamtube (1,2,3,4,5,6,[1,2])
--- a/scripts/plot/draw/pareto.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/pareto.m	Thu Nov 19 13:08:00 2020 -0800
@@ -72,7 +72,7 @@
 
   [hax, varargin, nargin] = __plt_get_axis_arg__ ("pareto", varargin{:});
 
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1 || nargin > 2)
     print_usage ();
   endif
 
--- a/scripts/plot/draw/patch.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/patch.m	Thu Nov 19 13:08:00 2020 -0800
@@ -94,16 +94,6 @@
     print_usage ();
   endif
 
-  ## FIXME: ishold called this way is very slow.
-  if (! ishold (hax))
-    ## FIXME: This is a hack to get 'layer' command to work for 2D patches
-    ##        Alternative is much more complicated surgery in graphics.cc.
-    ##        of get_children_limits() for 'z' axis and 'patch' object type.
-    if (isempty (get (htmp, "zdata")))
-      set (hax, "zlim", [-1 1]);
-    endif
-  endif
-
   if (nargout > 0)
     h = htmp;
   endif
@@ -259,21 +249,21 @@
 
 %!demo
 %! clf;
-%! vertices = [0 0 0; 0.5 -0.5 0; 1 0 0; 1 1 0; 0 1 1; 1 0 1; 0 -1 0;]+3;
+%! vertices = [0 0 0; 0.5 -0.5 0; 1 0 0; 1 1 0; 0 1 1; 1 0 1; 0 -1 0] + 3;
 %! faces = [1 2 3 4 5 6 7];
 %! ha = axes ();
-%! hp = patch ('Vertices', vertices, 'Faces', faces, 'FaceColor', 'g');
-%! xlabel('x'), ylabel('y'), zlabel('z')
-%! view(3)
-%! set (ha, "XTick", [], "YTick", [], "ZTick", [])
-%! text (vertices(1,1), vertices(1,2), vertices(1,3), "1")
-%! text (vertices(2,1), vertices(2,2), vertices(2,3), "2")
-%! text (vertices(3,1), vertices(3,2), vertices(3,3), "3")
-%! text (vertices(4,1), vertices(4,2), vertices(4,3), "4")
-%! text (vertices(5,1), vertices(5,2), vertices(5,3), "5")
-%! text (vertices(6,1), vertices(6,2), vertices(6,3), "6")
-%! text (vertices(7,1), vertices(7,2), vertices(7,3), "7")
-%! title ("Non-coplanar patch")
+%! hp = patch ("Vertices", vertices, "Faces", faces, "FaceColor", "g");
+%! xlabel ("x"), ylabel ("y"), zlabel ("z");
+%! view (3);
+%! set (ha, "XTick", [], "YTick", [], "ZTick", []);
+%! text (vertices(1,1), vertices(1,2), vertices(1,3), "1");
+%! text (vertices(2,1), vertices(2,2), vertices(2,3), "2");
+%! text (vertices(3,1), vertices(3,2), vertices(3,3), "3");
+%! text (vertices(4,1), vertices(4,2), vertices(4,3), "4");
+%! text (vertices(5,1), vertices(5,2), vertices(5,3), "5");
+%! text (vertices(6,1), vertices(6,2), vertices(6,3), "6");
+%! text (vertices(7,1), vertices(7,2), vertices(7,3), "7");
+%! title ("Non-coplanar patch");
 
 
 %!test
@@ -297,7 +287,7 @@
 %!   assert (get (h, "linewidth"), get (0, "defaultpatchlinewidth"), eps);
 %!   assert (get (h, "marker"), get (0, "defaultpatchmarker"));
 %!   assert (get (h, "markersize"), get (0, "defaultpatchmarkersize"));
-%!   hl = light;
+%!   hl = light ();
 %!   assert (get (h, "facelighting"), "flat");
 %!   assert (get (h, "facenormals"), [0 0 1], eps);
 %!   assert (get (h, "vertexnormals"), []);
--- a/scripts/plot/draw/pie.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/pie.m	Thu Nov 19 13:08:00 2020 -0800
@@ -113,6 +113,6 @@
 %! title ("pie() with missing slice");
 
 ## Test input validation
-%!error pie ()
+%!error <Invalid call> pie ()
 %!error <all data in X must be finite> pie ([1 2 Inf])
 %!error <all data in X must be finite> pie ([1 2 NaN])
--- a/scripts/plot/draw/pie3.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/pie3.m	Thu Nov 19 13:08:00 2020 -0800
@@ -112,6 +112,6 @@
 %! title ("pie3() with missing slice");
 
 ## Test input validation
-%!error pie3 ()
+%!error <Invalid call> pie3 ()
 %!error <all data in X must be finite> pie3 ([1 2 Inf])
 %!error <all data in X must be finite> pie3 ([1 2 NaN])
--- a/scripts/plot/draw/plotmatrix.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/plotmatrix.m	Thu Nov 19 13:08:00 2020 -0800
@@ -78,7 +78,7 @@
 
   [bigax2, varargin, nargin] = __plt_get_axis_arg__ ("plotmatrix", varargin{:});
 
-  if (nargin > 3 || nargin < 1)
+  if (nargin < 1 || nargin > 3)
     print_usage ();
   endif
 
@@ -121,7 +121,7 @@
 %! title ("plotmatrix() demo #1");
 
 
-function plotmatrixdelete (h, d, ax)
+function plotmatrixdelete (h, ~, ax)
 
   for i = 1 : numel (ax)
     hc = ax(i);
--- a/scripts/plot/draw/plotyy.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/plotyy.m	Thu Nov 19 13:08:00 2020 -0800
@@ -93,7 +93,7 @@
       hax = get (hax, "__plotyy_axes__");
     else
       hax = [hax; axes("nextplot", get (hax(1), "nextplot"), ...
-                       "parent", get(hax(1), "parent"))];
+                       "parent", get (hax(1), "parent"))];
     endif
 
     [axtmp, h1tmp, h2tmp] = __plotyy__ (hax, varargin{:});
@@ -142,9 +142,9 @@
   if (strcmp (get (ax(1), "__autopos_tag__"), "subplot"))
     set (ax(2), "__autopos_tag__", "subplot");
   elseif (strcmp (graphics_toolkit (), "gnuplot"))
-    set (ax, "activepositionproperty", "position");
+    set (ax, "positionconstraint", "innerposition");
   else
-    set (ax, "activepositionproperty", "outerposition");
+    set (ax, "positionconstraint", "outerposition");
   endif
 
   ## Don't replace axis which has colororder property already modified
@@ -161,7 +161,7 @@
   endif
 
   set (ax(2), "units", get (ax(1), "units"));
-  if (strcmp (get(ax(1), "activepositionproperty"), "position"))
+  if (strcmp (get (ax(1), "positionconstraint"), "innerposition"))
     set (ax(2), "position", get (ax(1), "position"));
   else
     set (ax(2), {"outerposition", "looseinset"},
@@ -241,8 +241,8 @@
       val = get (h, prop);
       if (strcmpi (prop, "position") || strcmpi (prop, "outerposition"))
         ## Save/restore "positionconstraint"
-        constraint = get (ax2, "activepositionproperty");
-        set (ax2, prop, get (h, prop), "activepositionproperty", constraint);
+        constraint = get (ax2, "positionconstraint");
+        set (ax2, prop, get (h, prop), "positionconstraint", constraint);
       else
         set (ax2, prop, get (h, prop));
       endif
@@ -292,13 +292,13 @@
 %! colormap ("default");
 %! x = linspace (-1, 1, 201);
 %! subplot (2,2,1);
-%!  plotyy (x,sin(pi*x), x,10*cos(pi*x));
+%!  plotyy (x,sin (pi*x), x,10*cos (pi*x));
 %!  title ("plotyy() in subplot");
 %! subplot (2,2,2);
 %!  surf (peaks (25));
 %! subplot (2,2,3);
 %!  contour (peaks (25));
 %! subplot (2,2,4);
-%!  plotyy (x,10*sin(2*pi*x), x,cos(2*pi*x));
+%!  plotyy (x,10*sin (2*pi*x), x,cos (2*pi*x));
 %!  title ("plotyy() in subplot");
 %!  axis square;
--- a/scripts/plot/draw/polar.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/polar.m	Thu Nov 19 13:08:00 2020 -0800
@@ -34,8 +34,8 @@
 ##
 ## The input @var{theta} is assumed to be radians and is converted to degrees
 ## for plotting.  If you have degrees then you must convert
-## (@pxref{XREFcart2pol,,cart2pol}) to radians before passing the data to this
-## function.
+## (@pxref{XREFcart2pol,,@code{cart2pol}}) to radians before passing the
+## data to this function.
 ##
 ## If a single complex input @var{cplx} is given then the real part is used
 ## for @var{theta} and the imaginary part is used for @var{rho}.
@@ -398,6 +398,7 @@
 endfunction
 
 function resetaxis (~, ~, hax)
+
   if (isaxes (hax))
     dellistener (hax, "rtick");
     dellistener (hax, "ttick");
@@ -412,6 +413,7 @@
     dellistener (hax, "gridlinestyle");
     dellistener (hax, "linewidth");
   endif
+
 endfunction
 
 
--- a/scripts/plot/draw/private/__bar__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/private/__bar__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -38,6 +38,7 @@
 
   width = 0.8;
   group = true;
+  stacked = false;
   histc = NA;
   ## BaseValue
   if (strcmp (get (hax, "yscale"), "log"))
@@ -84,6 +85,7 @@
       group = true;
       idx += 1;
     elseif (ischar (varargin{idx}) && strcmpi (varargin{idx}, "stacked"))
+      stacked = true;
       group = false;
       idx += 1;
     elseif (ischar (varargin{idx}) && strcmpi (varargin{idx}, "histc"))
@@ -185,8 +187,22 @@
     y0 = zeros (size (y)) + bv;
     y1 = y;
   else
-    y1 = cumsum (y,2);
-    y0 = [zeros(ngrp,1)+bv, y1(:,1:end-1)];
+    if (stacked && any (y(:) < 0))
+      ypos = (y >= 0);
+      yneg = (y <  0);
+
+      y1p =  cumsum (y .* ypos, 2);
+      y1n =  cumsum (y .* yneg, 2);
+      y1 = y1p .* ypos + y1n .* yneg;
+
+      y0p = [zeros(ngrp,1)+bv, y1p(:,1:end-1)];
+      y0n = [zeros(ngrp,1)+bv, y1n(:,1:end-1)];
+      y0 = y0p .* ypos + y0n .* yneg;
+
+    else
+      y1 = cumsum (y,2);
+      y0 = [zeros(ngrp,1)+bv, y1(:,1:end-1)];
+    endif
   endif
 
   yb = zeros (4*ngrp, nbars);
--- a/scripts/plot/draw/private/__ezplot__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/private/__ezplot__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -364,7 +364,7 @@
         Y = __eliminate_sing__ (Y);
         Z = __eliminate_sing__ (Z);
       endif
-    else  ## non-parametric plots
+    else  # non-parametric plots
       if (isplot && nargs == 2)
         Z = feval (fun, X, Y);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/draw/private/__gnuplot_scatter__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,345 @@
+########################################################################
+##
+## Copyright (C) 2020 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn {} {@var{hg} =} __gnuplot_scatter__ (@dots{})
+## Undocumented internal function.
+## @end deftypefn
+
+function hg = __gnuplot_scatter__ (hax, fcn, x, y, z, c, s, marker, filled, newargs)
+
+if (isempty (c))
+  c = __next_line_color__ ();
+endif
+
+## Must occur after __next_line_color__ in order to work correctly.
+hg = hggroup (hax, "__appdata__", struct ("__creator__", "__scatter__"));
+newargs = __add_datasource__ (fcn, hg, {"x", "y", "z", "c", "size"},
+                              newargs{:});
+
+addproperty ("xdata", hg, "data", x);
+addproperty ("ydata", hg, "data", y);
+addproperty ("zdata", hg, "data", z);
+if (ischar (c))
+  ## For single explicit color, cdata is unused
+  addproperty ("cdata", hg, "data", []);
+else
+  addproperty ("cdata", hg, "data", c);
+endif
+addproperty ("sizedata", hg, "data", s);
+addlistener (hg, "xdata", @update_data);
+addlistener (hg, "ydata", @update_data);
+addlistener (hg, "zdata", @update_data);
+addlistener (hg, "cdata", @update_data);
+addlistener (hg, "sizedata", @update_data);
+
+one_explicit_color = ischar (c) || isequal (size (c), [1, 3]);
+s = sqrt (s);  # size adjustment for visual compatibility w/Matlab
+
+if (numel (x) <= 100)
+
+  ## For small number of points, we'll construct an object for each point.
+
+  if (numel (s) == 1)
+    s = repmat (s, numel (x), 1);
+  endif
+
+  if (one_explicit_color)
+    for i = 1 : numel (x)
+      if (filled)
+        __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
+                      "xdata", x(i), "ydata", y(i), "zdata", z(i,:),
+                      "faces", 1, "vertices", [x(i), y(i), z(i,:)],
+                      "marker", marker,  "markersize", s(i),
+                      "markeredgecolor", c, "markerfacecolor", c,
+                      "linestyle", "none");
+      else
+        __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
+                      "xdata", x(i), "ydata", y(i), "zdata", z(i,:),
+                      "faces", 1, "vertices", [x(i), y(i), z(i,:)],
+                      "marker", marker,  "markersize", s(i),
+                      "markeredgecolor", c, "markerfacecolor", "none",
+                      "linestyle", "none");
+      endif
+    endfor
+  else
+    if (rows (c) == 1)
+      c = repmat (c, rows (x), 1);
+    endif
+    for i = 1 : numel (x)
+      if (filled)
+        __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
+                      "xdata", x(i), "ydata", y(i), "zdata", z(i,:),
+                      "faces", 1, "vertices", [x(i), y(i), z(i,:)],
+                      "marker", marker, "markersize", s(i),
+                      "markeredgecolor", "none",
+                      "markerfacecolor", "flat",
+                      "cdata", c(i,:), "facevertexcdata", c(i,:),
+                      "linestyle", "none");
+      else
+        __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
+                      "xdata", x(i), "ydata", y(i), "zdata", z(i,:),
+                      "faces", 1, "vertices", [x(i), y(i), z(i,:)],
+                      "marker", marker, "markersize", s(i),
+                      "markeredgecolor", "flat",
+                      "markerfacecolor", "none",
+                      "cdata", c(i,:), "facevertexcdata", c(i,:),
+                      "linestyle", "none");
+      endif
+    endfor
+  endif
+
+else
+
+  ## For larger numbers of points, we use one single object.
+  vert = [x, y, z];
+  render_size_color (hg, vert, s, c, marker, filled, true);
+
+endif
+
+if (! ischar (c) && rows (c) > 1)
+  ax = get (hg, "parent");
+  clim = get (ax, "clim");
+  if (min (c(:)) < clim(1))
+    clim(1) = min (c(:));
+    set (ax, "clim", clim);
+  endif
+  if (max (c(:)) > clim(2))
+    set (ax, "clim", [clim(1), max(c(:))]);
+  endif
+endif
+
+addproperty ("linewidth", hg, "patchlinewidth", 0.5);
+addproperty ("marker", hg, "patchmarker", marker);
+if (filled)
+  addproperty ("markeredgecolor", hg, "patchmarkeredgecolor", "none");
+  if (one_explicit_color)
+    addproperty ("markerfacecolor", hg, "patchmarkerfacecolor", c);
+  else
+    addproperty ("markerfacecolor", hg, "patchmarkerfacecolor", "flat");
+  endif
+else
+  addproperty ("markerfacecolor", hg, "patchmarkerfacecolor", "none");
+  if (one_explicit_color)
+    addproperty ("markeredgecolor", hg, "patchmarkeredgecolor", c);
+  else
+    addproperty ("markeredgecolor", hg, "patchmarkeredgecolor", "flat");
+  endif
+endif
+addlistener (hg, "linewidth", @update_props);
+addlistener (hg, "marker", @update_props);
+addlistener (hg, "markerfacecolor", @update_props);
+addlistener (hg, "markeredgecolor", @update_props);
+
+## Matlab property, although Octave does not implement it.
+addproperty ("hittestarea", hg, "radio", "on|{off}", "off");
+
+if (! isempty (newargs))
+  set (hg, newargs{:});
+endif
+
+endfunction
+
+function render_size_color (hg, vert, s, c, marker, filled, isflat)
+
+  if (isempty (c))
+    c = __next_line_color__ ();
+  endif
+
+  if (isscalar (s))
+    x = vert(:,1);
+    y = vert(:,2);
+    z = vert(:,3:end);
+    toolkit = get (ancestor (hg, "figure"), "__graphics_toolkit__");
+    ## Does gnuplot only support triangles with different vertex colors ?
+    ## FIXME: Verify gnuplot can only support one color.  If RGB triplets
+    ##        can be assigned to each vertex, then fix __gnuplot_draw_axes__.m
+    gnuplot_hack = (numel (x) > 1 && columns (c) == 3
+                    && strcmp (toolkit, "gnuplot"));
+    if (ischar (c) || ! isflat || gnuplot_hack)
+      if (filled)
+        ## "facecolor" and "edgecolor" must be set before any other properties
+        ## to skip co-planarity check (see bug #55751).
+        __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
+                          "xdata", x, "ydata", y, "zdata", z,
+                          "faces", 1:numel (x), "vertices", vert,
+                          "marker", marker,
+                          "markeredgecolor", "none",
+                          "markerfacecolor", c(1,:),
+                          "markersize", s, "linestyle", "none");
+      else
+        __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
+                          "xdata", x, "ydata", y, "zdata", z,
+                          "faces", 1:numel (x), "vertices", vert,
+                          "marker", marker,
+                          "markeredgecolor", c(1,:),
+                          "markerfacecolor", "none",
+                          "markersize", s, "linestyle", "none");
+      endif
+    else
+      if (filled)
+        __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
+                          "xdata", x, "ydata", y, "zdata", z,
+                          "faces", 1:numel (x), "vertices", vert,
+                          "marker", marker, "markersize", s,
+                          "markeredgecolor", "none",
+                          "markerfacecolor", "flat",
+                          "cdata", c, "facevertexcdata", c,
+                          "linestyle", "none");
+      else
+        __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
+                          "xdata", x, "ydata", y, "zdata", z,
+                          "faces", 1:numel (x), "vertices", vert,
+                          "marker", marker, "markersize", s,
+                          "markeredgecolor", "flat",
+                          "markerfacecolor", "none",
+                          "cdata", c, "facevertexcdata", c,
+                          "linestyle", "none");
+      endif
+    endif
+  else
+    ## Round size to one decimal place.
+    [ss, ~, s_to_ss] = unique (ceil (s*10) / 10);
+    for i = 1:rows (ss)
+      idx = (i == s_to_ss);
+      render_size_color (hg, vert(idx,:), ss(i), c,
+                             marker, filled, isflat);
+    endfor
+  endif
+
+endfunction
+
+function update_props (h, ~)
+
+  lw = get (h, "linewidth");
+  m  = get (h, "marker");
+  fc = get (h, "markerfacecolor");
+  ec = get (h, "markeredgecolor");
+  kids = get (h, "children");
+
+  set (kids, "linewidth", lw, "marker", m,
+             "markerfacecolor", fc, "markeredgecolor", ec);
+
+endfunction
+
+## FIXME: This callback routine doesn't handle the case where N > 100.
+function update_data (h, ~)
+
+  x = get (h, "xdata");
+  y = get (h, "ydata");
+  z = get (h, "zdata");
+  if (numel (x) > 100)
+    error ("scatter: cannot update data with more than 100 points.  Call scatter (x, y, ...) with new data instead.");
+  endif
+  c = get (h, "cdata");
+  one_explicit_color = ischar (c) || isequal (size (c), [1, 3]);
+  if (! one_explicit_color)
+    if (rows (c) == 1)
+      c = repmat (c, numel (x), 1);
+    endif
+  endif
+  filled = ! strcmp (get (h, "markerfacecolor"), "none");
+  s = get (h, "sizedata");
+  ## Size adjustment for visual compatibility with Matlab.
+  s = sqrt (s);
+  if (numel (s) == 1)
+    s = repmat (s, numel (x), 1);
+  endif
+  hlist = get (h, "children");
+
+  if (one_explicit_color)
+    if (filled)
+      if (isempty (z))
+        for i = 1 : length (hlist)
+          set (hlist(i), "vertices", [x(i), y(i)],
+                         "markersize", s(i),
+                         "markeredgecolor", c, "markerfacecolor", c);
+
+        endfor
+      else
+        for i = 1 : length (hlist)
+          set (hlist(i), "vertices", [x(i), y(i), z(i)],
+                         "markersize", s(i),
+                         "markeredgecolor", c, "markerfacecolor", c);
+        endfor
+      endif
+    else
+      if (isempty (z))
+        for i = 1 : length (hlist)
+          set (hlist(i), "vertices", [x(i), y(i)],
+                         "markersize", s(i),
+                         "markeredgecolor", c, "markerfacecolor", "none");
+
+        endfor
+      else
+        for i = 1 : length (hlist)
+          set (hlist(i), "vertices", [x(i), y(i), z(i)],
+                         "markersize", s(i),
+                         "markeredgecolor", c, "markerfacecolor", "none");
+        endfor
+      endif
+    endif
+  else
+    if (filled)
+      if (isempty (z))
+        for i = 1 : length (hlist)
+          set (hlist(i), "vertices", [x(i), y(i)],
+                         "markersize", s(i),
+                         "markeredgecolor", "none", "markerfacecolor", "flat",
+                         "cdata", reshape (c(i,:),[1, size(c)(2:end)]),
+                         "facevertexcdata", c(i,:));
+        endfor
+      else
+        for i = 1 : length (hlist)
+          set (hlist(i), "vertices", [x(i), y(i), z(i)],
+                         "markersize", s(i),
+                         "markeredgecolor", "none", "markerfacecolor", "flat",
+                         "cdata", reshape (c(i,:),[1, size(c)(2:end)]),
+                         "facevertexcdata", c(i,:));
+        endfor
+      endif
+    else
+      if (isempty (z))
+        for i = 1 : length (hlist)
+          set (hlist(i), "vertices", [x(i), y(i)],
+                         "markersize", s(i),
+                         "markeredgecolor", "flat", "markerfacecolor", "none",
+                         "cdata", reshape (c(i,:),[1, size(c)(2:end)]),
+                         "facevertexcdata", c(i,:));
+        endfor
+      else
+        for i = 1 : length (hlist)
+          set (hlist(i), "vertices", [x(i), y(i), z(i)],
+                         "markersize", s(i),
+                         "markeredgecolor", "flat", "markerfacecolor", "none",
+                         "cdata", reshape (c(i,:),[1, size(c)(2:end)]),
+                         "facevertexcdata", c(i,:));
+        endfor
+      endif
+    endif
+  endif
+
+endfunction
+
--- a/scripts/plot/draw/private/__line__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/private/__line__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -24,8 +24,8 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn {} {@var{h} =} __line__ (@var{parent}, @dots{})
-## Create line object with parent @var{parent}.
+## @deftypefn {} {@var{h} =} __line__ (@var{hp}, @dots{})
+## Create line object with parent handle @var{hp}.
 ##
 ## Return handle @var{h} to created line objects.
 ## @end deftypefn
--- a/scripts/plot/draw/private/__marching_cube__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/private/__marching_cube__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -24,18 +24,18 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn  {} {[@var{t}, @var{p}] =} __marching_cube__ (@var{x}, @var{y}, @var{z}, @var{val}, @var{iso})
-## @deftypefnx {} {[@var{t}, @var{p}, @var{c}] =} __marching_cube__ (@var{x}, @var{y}, @var{z}, @var{val}, @var{iso}, @var{col})
+## @deftypefn  {} {[@var{t}, @var{p}] =} __marching_cube__ (@var{xx}, @var{yy}, @var{zz}, @var{val}, @var{iso})
+## @deftypefnx {} {[@var{t}, @var{p}, @var{c}] =} __marching_cube__ (@var{xx}, @var{yy}, @var{zz}, @var{v}, @var{iso}, @var{colors})
 ##
 ## Return the triangulation information @var{t} at points @var{p} for the
-## isosurface values resp. the volume data @var{val} and the iso level
-## @var{iso}.  It is considered that the volume data @var{val} is given at
-## the points @var{x}, @var{y} and @var{z} which are of type
+## isosurface values resp. the volume data @var{v} and the iso level
+## @var{iso}.  It is considered that the volume data @var{v} is given at
+## the points @var{xx}, @var{yy}, and @var{zz} which are of type
 ## three-dimensional numeric arrays.  The orientation of the triangles is
 ## chosen such that the normals point from the higher values to the lower
 ## values.
 ##
-## Optionally the color data @var{col} can be passed to this function
+## Optionally the color data @var{colors} can be passed to this function
 ## whereas computed vertices color data @var{c} is returned as third
 ## argument.
 ##
@@ -51,10 +51,10 @@
 ## @group
 ## N = 20;
 ## lin = linspace (0, 2, N);
-## [x, y, z] = meshgrid (lin, lin, lin);
+## [xx, yy, zz] = meshgrid (lin, lin, lin);
 ##
-## c = (x-.5).^2 + (y-.5).^2 + (z-.5).^2;
-## [t, p] = __marching_cube__ (x, y, z, c, .5);
+## v = (xx-.5).^2 + (yy-.5).^2 + (zz-.5).^2;
+## [t, p] = __marching_cube__ (xx, yy, zz, v, .5);
 ##
 ## figure ();
 ## trimesh (t, p(:,1), p(:,2), p(:,3));
@@ -82,7 +82,7 @@
 ##
 ## @end deftypefn
 
-function [T, p, col] = __marching_cube__ (xx, yy, zz, c, iso, colors)
+function [T, p, col] = __marching_cube__ (xx, yy, zz, v, iso, colors)
 
   persistent edge_table = [];
   persistent tri_table = [];
@@ -94,19 +94,14 @@
     [edge_table, tri_table] = init_mc ();
   endif
 
-  ## FIXME: Do we need all of the following validation on an internal function?
-  if ((nargin != 5 && nargin != 6) || (nargout != 2 && nargout != 3))
-    print_usage ();
+  if (! isnumeric (xx) || ! isnumeric (yy) || ! isnumeric (zz)
+      || ! isnumeric (v) || ndims (xx) != 3 || ndims (yy) != 3
+      || ndims (zz) != 3 || ndims (v) != 3)
+    error ("__marching_cube__: XX, YY, ZZ, v must be 3-D matrices");
   endif
 
-  if (! isnumeric (xx) || ! isnumeric (yy) || ! isnumeric (zz)
-      || ! isnumeric (c) || ndims (xx) != 3 || ndims (yy) != 3
-      || ndims (zz) != 3 || ndims (c) != 3)
-    error ("__marching_cube__: XX, YY, ZZ, C must be 3-D matrices");
-  endif
-
-  if (! size_equal (xx, yy, zz, c))
-    error ("__marching_cube__: XX, YY, ZZ, C must be of equal size");
+  if (! size_equal (xx, yy, zz, v))
+    error ("__marching_cube__: XX, YY, ZZ, v must be of equal size");
   endif
 
   if (any (size (xx) < [2 2 2]))
@@ -118,14 +113,14 @@
   endif
 
   if (nargin == 6)
-    if (! isnumeric (colors) || ndims (colors) != 3 || ! size_equal (colors, c))
-      error ( "COLORS must be a 3-D matrix with the same size as C" );
+    if (! isnumeric (colors) || ndims (colors) != 3 || ! size_equal (colors, v))
+      error ( "COLORS must be a 3-D matrix with the same size as v" );
     endif
     calc_cols = true;
     lindex = 5;
   endif
 
-  n = size (c) - 1;
+  n = size (v) - 1;
 
   ## phase I: assign information to each voxel which edges are intersected by
   ## the isosurface.
@@ -143,7 +138,7 @@
 
   ## calculate which vertices have values higher than iso
   for ii = 1:8
-    idx = c(vertex_idx{ii, :}) > iso;
+    idx = v(vertex_idx{ii, :}) > iso;
     cc(idx) = bitset (cc(idx), ii);
   endfor
 
@@ -157,7 +152,7 @@
   ## phase II: calculate the list of intersection points
   xyz_off = [1, 1, 1; 2, 1, 1; 2, 2, 1; 1, 2, 1; 1, 1, 2; 2, 1, 2; 2, 2, 2; 1, 2, 2];
   edges = [1 2; 2 3; 3 4; 4 1; 5 6; 6 7; 7 8; 8 5; 1 5; 2 6; 3 7; 4 8];
-  offset = sub2ind (size (c), xyz_off(:, 1), xyz_off(:, 2), xyz_off(:, 3)) - 1;
+  offset = sub2ind (size (v), xyz_off(:, 1), xyz_off(:, 2), xyz_off(:, 3)) - 1;
   pp = zeros (length (id), lindex, 12);
   ccedge = [vec(cedge(id)), id];
   ix_offset=0;
@@ -165,16 +160,16 @@
     id__ = bitget (ccedge(:, 1), jj);
     id_ = ccedge(id__, 2);
     [ix iy iz] = ind2sub (size (cc), id_);
-    id_c = sub2ind (size (c), ix, iy, iz);
+    id_c = sub2ind (size (v), ix, iy, iz);
     id1 = id_c + offset(edges(jj, 1));
     id2 = id_c + offset(edges(jj, 2));
     if (calc_cols)
       pp(id__, 1:5, jj) = [vertex_interp(iso, xx(id1), yy(id1), zz(id1), ...
-        xx(id2), yy(id2), zz(id2), c(id1), c(id2), colors(id1), colors(id2)), ...
+        xx(id2), yy(id2), zz(id2), v(id1), v(id2), colors(id1), colors(id2)), ...
         (1:rows (id_))' + ix_offset ];
     else
       pp(id__, 1:4, jj) = [vertex_interp(iso, xx(id1), yy(id1), zz(id1), ...
-        xx(id2), yy(id2), zz(id2), c(id1), c(id2)), ...
+        xx(id2), yy(id2), zz(id2), v(id1), v(id2)), ...
         (1:rows (id_))' + ix_offset ];
     endif
     ix_offset += rows (id_);
@@ -245,38 +240,38 @@
 function [edge_table, tri_table] = init_mc ()
 
   edge_table = [
-  0x0  , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, ...
-  0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, ...
-  0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, ...
-  0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, ...
-  0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c, ...
-  0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, ...
-  0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac, ...
-  0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, ...
-  0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c, ...
-  0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60, ...
-  0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc, ...
-  0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, ...
-  0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c, ...
-  0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, ...
-  0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc , ...
-  0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, ...
-  0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, ...
-  0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, ...
-  0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, ...
-  0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, ...
-  0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, ...
-  0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, ...
-  0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, ...
-  0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460, ...
-  0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, ...
-  0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0, ...
-  0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, ...
-  0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230, ...
-  0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, ...
-  0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190, ...
-  0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, ...
-  0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0   ];
+    0x0000, 0x0109, 0x0203, 0x030a, 0x0406, 0x050f, 0x0605, 0x070c, ...
+    0x080c, 0x0905, 0x0a0f, 0x0b06, 0x0c0a, 0x0d03, 0x0e09, 0x0f00, ...
+    0x0190, 0x0099, 0x0393, 0x029a, 0x0596, 0x049f, 0x0795, 0x069c, ...
+    0x099c, 0x0895, 0x0b9f, 0x0a96, 0x0d9a, 0x0c93, 0x0f99, 0x0e90, ...
+    0x0230, 0x0339, 0x0033, 0x013a, 0x0636, 0x073f, 0x0435, 0x053c, ...
+    0x0a3c, 0x0b35, 0x083f, 0x0936, 0x0e3a, 0x0f33, 0x0c39, 0x0d30, ...
+    0x03a0, 0x02a9, 0x01a3, 0x00aa, 0x07a6, 0x06af, 0x05a5, 0x04ac, ...
+    0x0bac, 0x0aa5, 0x09af, 0x08a6, 0x0faa, 0x0ea3, 0x0da9, 0x0ca0, ...
+    0x0460, 0x0569, 0x0663, 0x076a, 0x0066, 0x016f, 0x0265, 0x036c, ...
+    0x0c6c, 0x0d65, 0x0e6f, 0x0f66, 0x086a, 0x0963, 0x0a69, 0x0b60, ...
+    0x05f0, 0x04f9, 0x07f3, 0x06fa, 0x01f6, 0x00ff, 0x03f5, 0x02fc, ...
+    0x0dfc, 0x0cf5, 0x0fff, 0x0ef6, 0x09fa, 0x08f3, 0x0bf9, 0x0af0, ...
+    0x0650, 0x0759, 0x0453, 0x055a, 0x0256, 0x035f, 0x0055, 0x015c, ...
+    0x0e5c, 0x0f55, 0x0c5f, 0x0d56, 0x0a5a, 0x0b53, 0x0859, 0x0950, ...
+    0x07c0, 0x06c9, 0x05c3, 0x04ca, 0x03c6, 0x02cf, 0x01c5, 0x00cc, ...
+    0x0fcc, 0x0ec5, 0x0dcf, 0x0cc6, 0x0bca, 0x0ac3, 0x09c9, 0x08c0, ...
+    0x08c0, 0x09c9, 0x0ac3, 0x0bca, 0x0cc6, 0x0dcf, 0x0ec5, 0x0fcc, ...
+    0x00cc, 0x01c5, 0x02cf, 0x03c6, 0x04ca, 0x05c3, 0x06c9, 0x07c0, ...
+    0x0950, 0x0859, 0x0b53, 0x0a5a, 0x0d56, 0x0c5f, 0x0f55, 0x0e5c, ...
+    0x015c, 0x0055, 0x035f, 0x0256, 0x055a, 0x0453, 0x0759, 0x0650, ...
+    0x0af0, 0x0bf9, 0x08f3, 0x09fa, 0x0ef6, 0x0fff, 0x0cf5, 0x0dfc, ...
+    0x02fc, 0x03f5, 0x00ff, 0x01f6, 0x06fa, 0x07f3, 0x04f9, 0x05f0, ...
+    0x0b60, 0x0a69, 0x0963, 0x086a, 0x0f66, 0x0e6f, 0x0d65, 0x0c6c, ...
+    0x036c, 0x0265, 0x016f, 0x0066, 0x076a, 0x0663, 0x0569, 0x0460, ...
+    0x0ca0, 0x0da9, 0x0ea3, 0x0faa, 0x08a6, 0x09af, 0x0aa5, 0x0bac, ...
+    0x04ac, 0x05a5, 0x06af, 0x07a6, 0x00aa, 0x01a3, 0x02a9, 0x03a0, ...
+    0x0d30, 0x0c39, 0x0f33, 0x0e3a, 0x0936, 0x083f, 0x0b35, 0x0a3c, ...
+    0x053c, 0x0435, 0x073f, 0x0636, 0x013a, 0x0033, 0x0339, 0x0230, ...
+    0x0e90, 0x0f99, 0x0c93, 0x0d9a, 0x0a96, 0x0b9f, 0x0895, 0x099c, ...
+    0x069c, 0x0795, 0x049f, 0x0596, 0x029a, 0x0393, 0x0099, 0x0190, ...
+    0x0f00, 0x0e09, 0x0d03, 0x0c0a, 0x0b06, 0x0a0f, 0x0905, 0x080c, ...
+    0x070c, 0x0605, 0x050f, 0x0406, 0x030a, 0x0203, 0x0109, 0x0000 ];
 
   tri_table = [
   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1;
--- a/scripts/plot/draw/private/__pie__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/private/__pie__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -130,7 +130,7 @@
 
       hlist = [hlist;
         patch(xoff + [0, -sind(xn)], yoff + [0, cosd(xn)], zeros (1, ln + 1), i);
-        surface(sx, sy, sz, sc);
+        surface (sx, sy, sz, sc);
         patch(xoff + [0, -sind(xn)], yoff + [0, cosd(xn)], zlvl * ones (1, ln + 1), i);
         text(xt, yt, zlvl, labels{i})];
 
--- a/scripts/plot/draw/private/__plt__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/private/__plt__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -24,7 +24,7 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn {} {} __plt__ (@var{caller}, @var{hparent}, @var{varargin})
+## @deftypefn {} {} __plt__ (@var{caller}, @var{hp}, @var{varargin})
 ## Undocumented internal function.
 ## @end deftypefn
 
@@ -33,125 +33,124 @@
   persistent warned_callers = {};
   nargs = nargin - 2;
 
-  if (nargs > 0)
+  if (nargs < 1)
+    error ("__plt__: invalid number of arguments");
+  endif
 
-    k = 1;
+  k = 1;
 
-    x_set = false;
-    y_set = false;
-    property_set = false;
-    properties = {};
+  x_set = false;
+  y_set = false;
+  property_set = false;
+  properties = {};
+
+  ## Find any legend associated with this axes
+  try
+    hlegend = get (hp, "__legend_handle__");
+  catch
+    hlegend = [];
+  end_try_catch
 
-    ## Find any legend associated with this axes
-    try
-      hlegend = get (hp, "__legend_handle__");
-    catch
-      hlegend = [];
-    end_try_catch
+  setlgnd = false;
+  if (isempty (hlegend))
+    hlgnd = [];
+    tlgnd = {};
+  else
+    [hlgnd, tlgnd] = __getlegenddata__ (hlegend);
+  endif
+
+  ## Gather arguments, decode format, gather plot strings, and plot lines.
 
-    setlgnd = false;
-    if (isempty (hlegend))
-      hlgnd = [];
-      tlgnd = {};
+  retval = [];
+
+  while (nargs > 0 || x_set)
+
+    if (nargs == 0)
+      ## Force the last plot when input variables run out.
+      next_cell = {};
+      next_arg = {""};
     else
-      [hlgnd, tlgnd] = __getlegenddata__ (hlegend);
+      next_cell = varargin(k);
+      next_arg = varargin{k++};
     endif
 
-    ## Gather arguments, decode format, gather plot strings, and plot lines.
-
-    retval = [];
-
-    while (nargs > 0 || x_set)
-
-      if (nargs == 0)
-        ## Force the last plot when input variables run out.
-        next_cell = {};
-        next_arg = {""};
-      else
-        next_cell = varargin(k);
-        next_arg = varargin{k++};
+    if (isnumeric (next_arg) && ndims (next_arg) > 2
+        && any (size (next_arg) == 1))
+      next_arg = squeeze (next_arg);
+      if (! any (strcmp (caller, warned_callers)) && ndims (next_arg) < 3)
+        warning (["%s: N-d inputs have been squeezed to less than " ...
+                  "three dimensions"], caller);
+        warned_callers(end+1) = caller;
       endif
+    endif
+    if (isnumeric (next_arg) && ndims (next_arg) > 2)
+      error ("%s: plot arrays must have less than 2 dimensions", caller);
+    endif
 
-      if (isnumeric (next_arg) && ndims (next_arg) > 2
-          && any (size (next_arg) == 1))
-        next_arg = squeeze (next_arg);
-        if (! any (strcmp (caller, warned_callers)) && ndims (next_arg) < 3)
-          warning (["%s: N-d inputs have been squeezed to less than " ...
-                    "three dimensions"], caller);
-          warned_callers(end+1) = caller;
-        endif
-      endif
-      if (isnumeric (next_arg) && ndims (next_arg) > 2)
-        error ("%s: plot arrays must have less than 2 dimensions", caller);
-      endif
-
-      nargs -= 1;
+    nargs -= 1;
 
-      if (ischar (next_arg) || iscellstr (next_arg))
-        if (x_set)
-          [options, valid] = __pltopt__ (caller, next_arg, false);
-          if (! valid)
-            if (nargs == 0)
-              error ("%s: properties must appear followed by a value", caller);
-            endif
-            properties = [properties, [next_cell, varargin(k++)]];
-            nargs -= 1;
-            continue;
-          else
-            while (nargs > 0 && ischar (varargin{k}))
-              if (nargs < 2)
-                error ("%s: properties must appear followed by a value",
-                       caller);
-              endif
-              properties = [properties, varargin(k:k+1)];
-              k += 2;
-              nargs -= 2;
-            endwhile
+    if (ischar (next_arg) || iscellstr (next_arg))
+      if (x_set)
+        [options, valid] = __pltopt__ (caller, next_arg, false);
+        if (! valid)
+          if (nargs == 0)
+            error ("%s: properties must appear followed by a value", caller);
           endif
-          if (y_set)
-            htmp = __plt2__ (hp, x, y, options, properties);
-            [hlgnd, tlgnd, setlgnd] = ...
-              __plt_key__ (htmp, options, hlgnd, tlgnd, setlgnd);
-            properties = {};
-            retval = [retval; htmp];
-          else
-            htmp = __plt1__ (hp, x, options, properties);
-            [hlgnd, tlgnd, setlgnd] = ...
-               __plt_key__ (htmp, options, hlgnd, tlgnd, setlgnd);
-            properties = {};
-            retval = [retval; htmp];
-          endif
-          x_set = false;
-          y_set = false;
+          properties = [properties, [next_cell, varargin(k++)]];
+          nargs -= 1;
+          continue;
         else
-          error ("plot: no data to plot");
+          while (nargs > 0 && ischar (varargin{k}))
+            if (nargs < 2)
+              error ("%s: properties must appear followed by a value",
+                     caller);
+            endif
+            properties = [properties, varargin(k:k+1)];
+            k += 2;
+            nargs -= 2;
+          endwhile
         endif
-      elseif (x_set)
         if (y_set)
-          options = __pltopt__ (caller, {""});
           htmp = __plt2__ (hp, x, y, options, properties);
           [hlgnd, tlgnd, setlgnd] = ...
             __plt_key__ (htmp, options, hlgnd, tlgnd, setlgnd);
+          properties = {};
           retval = [retval; htmp];
-          x = next_arg;
-          y_set = false;
-          properties = {};
         else
-          y = next_arg;
-          y_set = true;
+          htmp = __plt1__ (hp, x, options, properties);
+          [hlgnd, tlgnd, setlgnd] = ...
+             __plt_key__ (htmp, options, hlgnd, tlgnd, setlgnd);
+          properties = {};
+          retval = [retval; htmp];
         endif
+        x_set = false;
+        y_set = false;
       else
+        error ("plot: no data to plot");
+      endif
+    elseif (x_set)
+      if (y_set)
+        options = __pltopt__ (caller, {""});
+        htmp = __plt2__ (hp, x, y, options, properties);
+        [hlgnd, tlgnd, setlgnd] = ...
+          __plt_key__ (htmp, options, hlgnd, tlgnd, setlgnd);
+        retval = [retval; htmp];
         x = next_arg;
-        x_set = true;
+        y_set = false;
+        properties = {};
+      else
+        y = next_arg;
+        y_set = true;
       endif
-
-    endwhile
+    else
+      x = next_arg;
+      x_set = true;
+    endif
 
-    if (setlgnd)
-      legend (gca (), hlgnd, tlgnd);
-    endif
-  else
-    error ("__plt__: invalid number of arguments");
+  endwhile
+
+  if (setlgnd)
+    legend (gca (), hlgnd, tlgnd);
   endif
 
 endfunction
@@ -365,6 +364,7 @@
   retval = __go_line__ (hp, "xdata", x, "ydata", y,
                         "color", color, "linestyle", linestyle,
                         "marker", marker, properties{:});
+
 endfunction
 
 function retval = __plt2sv__ (hp, x, y, options, properties = {})
--- a/scripts/plot/draw/private/__scatter__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/private/__scatter__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -24,13 +24,13 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn {} {@var{hg} =} __scatter__ (@dots{})
+## @deftypefn {} {@var{hs} =} __scatter__ (@dots{})
 ## Undocumented internal function.
 ## @end deftypefn
 
-function hg = __scatter__ (varargin)
+function hs = __scatter__ (varargin)
 
-  hax = varargin{1};  # We don't do anything with this.  Could remove it.
+  hax = varargin{1};
   nd  = varargin{2};
   fcn = varargin{3};
   x   = varargin{4}(:);
@@ -108,7 +108,7 @@
   x(idx) = [];
   y(idx) = [];
   if (nd == 2)
-    z = zeros (length (x), 0);
+    z = zeros (numel (x), 0);
   endif
   if (numel (s) > 1)
     s(idx) = [];
@@ -169,311 +169,58 @@
     endif
   endwhile
 
-  if (isempty (c))
-    c = __next_line_color__ ();
-  endif
+  if (strcmp ("gnuplot", graphics_toolkit ()))
+    ## Legacy code using patch for gnuplot toolkit
+    hs = __gnuplot_scatter__ (hax, fcn, x, y, z, c, s, marker, filled, newargs);
 
-  ## Must occur after __next_line_color__ in order to work correctly.
-  hg = hggroup ("__appdata__", struct ("__creator__", "__scatter__"));
-  newargs = __add_datasource__ (fcn, hg, {"x", "y", "z", "c", "size"},
-                                newargs{:});
-
-  addproperty ("xdata", hg, "data", x);
-  addproperty ("ydata", hg, "data", y);
-  addproperty ("zdata", hg, "data", z);
-  if (ischar (c))
-    ## For single explicit color, cdata is unused
-    addproperty ("cdata", hg, "data", []);
   else
-    addproperty ("cdata", hg, "data", c);
-  endif
-  addproperty ("sizedata", hg, "data", s);
-  addlistener (hg, "xdata", @update_data);
-  addlistener (hg, "ydata", @update_data);
-  addlistener (hg, "zdata", @update_data);
-  addlistener (hg, "cdata", @update_data);
-  addlistener (hg, "sizedata", @update_data);
-
-  one_explicit_color = ischar (c) || isequal (size (c), [1, 3]);
-  s = sqrt (s);  # size adjustment for visual compatibility w/Matlab
-
-  if (numel (x) <= 100)
-
-    ## For small number of points, we'll construct an object for each point.
-
-    if (numel (s) == 1)
-      s = repmat (s, numel (x), 1);
+    ## Use OpenGL rendering for "qt" and "fltk" graphics toolkits
+    if (isempty (x))
+      c = x;
+    endif
+    if (ischar (c))
+      c = str2rgb (c);
+    endif
+    if (isempty (c))
+      cdata_args = {};
+    else
+      cdata_args = {"cdata", c};
+    endif
+    if (filled)
+      filled_args = {"markeredgecolor", "none", "markerfacecolor", "flat"};
+    else
+      filled_args = {};
     endif
 
-    if (one_explicit_color)
-      for i = 1 : numel (x)
-        if (filled)
-          __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
-                        "xdata", x(i), "ydata", y(i), "zdata", z(i,:),
-                        "faces", 1, "vertices", [x(i), y(i), z(i,:)],
-                        "marker", marker,  "markersize", s(i),
-                        "markeredgecolor", c, "markerfacecolor", c,
-                        "linestyle", "none");
-        else
-          __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
-                        "xdata", x(i), "ydata", y(i), "zdata", z(i,:),
-                        "faces", 1, "vertices", [x(i), y(i), z(i,:)],
-                        "marker", marker,  "markersize", s(i),
-                        "markeredgecolor", c, "markerfacecolor", "none",
-                        "linestyle", "none");
-        endif
-      endfor
-    else
-      if (rows (c) == 1)
-        c = repmat (c, rows (x), 1);
-      endif
-      for i = 1 : numel (x)
-        if (filled)
-          __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
-                        "xdata", x(i), "ydata", y(i), "zdata", z(i,:),
-                        "faces", 1, "vertices", [x(i), y(i), z(i,:)],
-                        "marker", marker, "markersize", s(i),
-                        "markeredgecolor", "none",
-                        "markerfacecolor", "flat",
-                        "cdata", c(i,:), "facevertexcdata", c(i,:),
-                        "linestyle", "none");
-        else
-          __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
-                        "xdata", x(i), "ydata", y(i), "zdata", z(i,:),
-                        "faces", 1, "vertices", [x(i), y(i), z(i,:)],
-                        "marker", marker, "markersize", s(i),
-                        "markeredgecolor", "flat",
-                        "markerfacecolor", "none",
-                        "cdata", c(i,:), "facevertexcdata", c(i,:),
-                        "linestyle", "none");
-        endif
-      endfor
-    endif
-
-  else
-
-    ## For larger numbers of points, we use one single object.
-    vert = [x, y, z];
-    render_size_color (hg, vert, s, c, marker, filled, true);
-
-  endif
-
-  if (! ischar (c) && rows (c) > 1)
-    ax = get (hg, "parent");
-    clim = get (ax, "clim");
-    if (min (c(:)) < clim(1))
-      clim(1) = min (c(:));
-      set (ax, "clim", clim);
-    endif
-    if (max (c(:)) > clim(2))
-      set (ax, "clim", [clim(1), max(c(:))]);
-    endif
-  endif
-
-  addproperty ("linewidth", hg, "patchlinewidth", 0.5);
-  addproperty ("marker", hg, "patchmarker", marker);
-  if (filled)
-    addproperty ("markeredgecolor", hg, "patchmarkeredgecolor", "none");
-    if (one_explicit_color)
-      addproperty ("markerfacecolor", hg, "patchmarkerfacecolor", c);
-    else
-      addproperty ("markerfacecolor", hg, "patchmarkerfacecolor", "flat");
-    endif
-  else
-    addproperty ("markerfacecolor", hg, "patchmarkerfacecolor", "none");
-    if (one_explicit_color)
-      addproperty ("markeredgecolor", hg, "patchmarkeredgecolor", c);
-    else
-      addproperty ("markeredgecolor", hg, "patchmarkeredgecolor", "flat");
-    endif
-  endif
-  addlistener (hg, "linewidth", @update_props);
-  addlistener (hg, "marker", @update_props);
-  addlistener (hg, "markerfacecolor", @update_props);
-  addlistener (hg, "markeredgecolor", @update_props);
-
-  ## Matlab property, although Octave does not implement it.
-  addproperty ("hittestarea", hg, "radio", "on|{off}", "off");
-
-  if (! isempty (newargs))
-    set (hg, newargs{:});
+    hs = __go_scatter__ (hax, "xdata", x(:), "ydata", y(:), "zdata", z(:),
+                         cdata_args{:}, "sizedata", s(:), "marker", marker,
+                         filled_args{:}, newargs{:});
   endif
 
 endfunction
 
-function render_size_color (hg, vert, s, c, marker, filled, isflat)
+
+function rgb = str2rgb (str)
+  ## Convert a color code to the corresponding RGB values
+  rgb = [];
 
-  if (isscalar (s))
-    x = vert(:,1);
-    y = vert(:,2);
-    z = vert(:,3:end);
-    toolkit = get (ancestor (hg, "figure"), "__graphics_toolkit__");
-    ## Does gnuplot only support triangles with different vertex colors ?
-    ## FIXME: Verify gnuplot can only support one color.  If RGB triplets
-    ##        can be assigned to each vertex, then fix __gnuplot_draw_axes__.m
-    gnuplot_hack = (numel (x) > 1 && columns (c) == 3
-                    && strcmp (toolkit, "gnuplot"));
-    if (ischar (c) || ! isflat || gnuplot_hack)
-      if (filled)
-        ## "facecolor" and "edgecolor" must be set before any other properties
-        ## to skip co-planarity check (see bug #55751).
-        __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
-                          "xdata", x, "ydata", y, "zdata", z,
-                          "faces", 1:numel (x), "vertices", vert,
-                          "marker", marker,
-                          "markeredgecolor", "none",
-                          "markerfacecolor", c(1,:),
-                          "markersize", s, "linestyle", "none");
-      else
-        __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
-                          "xdata", x, "ydata", y, "zdata", z,
-                          "faces", 1:numel (x), "vertices", vert,
-                          "marker", marker,
-                          "markeredgecolor", c(1,:),
-                          "markerfacecolor", "none",
-                          "markersize", s, "linestyle", "none");
-      endif
-    else
-      if (filled)
-        __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
-                          "xdata", x, "ydata", y, "zdata", z,
-                          "faces", 1:numel (x), "vertices", vert,
-                          "marker", marker, "markersize", s,
-                          "markeredgecolor", "none",
-                          "markerfacecolor", "flat",
-                          "cdata", c, "facevertexcdata", c,
-                          "linestyle", "none");
-      else
-        __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
-                          "xdata", x, "ydata", y, "zdata", z,
-                          "faces", 1:numel (x), "vertices", vert,
-                          "marker", marker, "markersize", s,
-                          "markeredgecolor", "flat",
-                          "markerfacecolor", "none",
-                          "cdata", c, "facevertexcdata", c,
-                          "linestyle", "none");
-      endif
-    endif
-  else
-    ## Round size to one decimal place.
-    [ss, ~, s_to_ss] = unique (ceil (s*10) / 10);
-    for i = 1:rows (ss)
-      idx = (i == s_to_ss);
-      render_size_color (hg, vert(idx,:), ss(i), c,
-                             marker, filled, isflat);
-    endfor
-  endif
-
-endfunction
-
-function update_props (h, d)
-
-  lw = get (h, "linewidth");
-  m  = get (h, "marker");
-  fc = get (h, "markerfacecolor");
-  ec = get (h, "markeredgecolor");
-  kids = get (h, "children");
-
-  set (kids, "linewidth", lw, "marker", m,
-             "markerfacecolor", fc, "markeredgecolor", ec);
+  switch (str)
+    case 'b'
+      rgb = [0, 0, 1];
+    case 'k'
+      rgb = [0, 0, 0];
+    case 'r'
+      rgb = [1, 0, 0];
+    case 'g'
+      rgb = [0, 1, 0];
+    case 'y'
+      rgb = [1, 1, 0];
+    case 'm'
+      rgb = [1, 0, 1];
+    case 'c'
+      rgb = [0, 1, 1];
+    case 'w'
+      rgb = [1, 1, 1];
+endswitch
 
 endfunction
-
-## FIXME: This callback routine doesn't handle the case where N > 100.
-function update_data (h, d)
-
-  x = get (h, "xdata");
-  y = get (h, "ydata");
-  z = get (h, "zdata");
-  if (numel (x) > 100)
-    error ("scatter: cannot update data with more than 100 points.  Call scatter (x, y, ...) with new data instead.");
-  endif
-  c = get (h, "cdata");
-  one_explicit_color = ischar (c) || isequal (size (c), [1, 3]);
-  if (! one_explicit_color)
-    if (rows (c) == 1)
-      c = repmat (c, numel (x), 1);
-    endif
-  endif
-  filled = ! strcmp (get (h, "markerfacecolor"), "none");
-  s = get (h, "sizedata");
-  ## Size adjustment for visual compatibility with Matlab.
-  s = sqrt (s);
-  if (numel (s) == 1)
-    s = repmat (s, numel (x), 1);
-  endif
-  hlist = get (h, "children");
-
-  if (one_explicit_color)
-    if (filled)
-      if (isempty (z))
-        for i = 1 : length (hlist)
-          set (hlist(i), "vertices", [x(i), y(i)],
-                         "markersize", s(i),
-                         "markeredgecolor", c, "markerfacecolor", c);
-
-        endfor
-      else
-        for i = 1 : length (hlist)
-          set (hlist(i), "vertices", [x(i), y(i), z(i)],
-                         "markersize", s(i),
-                         "markeredgecolor", c, "markerfacecolor", c);
-        endfor
-      endif
-    else
-      if (isempty (z))
-        for i = 1 : length (hlist)
-          set (hlist(i), "vertices", [x(i), y(i)],
-                         "markersize", s(i),
-                         "markeredgecolor", c, "markerfacecolor", "none");
-
-        endfor
-      else
-        for i = 1 : length (hlist)
-          set (hlist(i), "vertices", [x(i), y(i), z(i)],
-                         "markersize", s(i),
-                         "markeredgecolor", c, "markerfacecolor", "none");
-        endfor
-      endif
-    endif
-  else
-    if (filled)
-      if (isempty (z))
-        for i = 1 : length (hlist)
-          set (hlist(i), "vertices", [x(i), y(i)],
-                         "markersize", s(i),
-                         "markeredgecolor", "none", "markerfacecolor", "flat",
-                         "cdata", reshape (c(i,:),[1, size(c)(2:end)]),
-                         "facevertexcdata", c(i,:));
-        endfor
-      else
-        for i = 1 : length (hlist)
-          set (hlist(i), "vertices", [x(i), y(i), z(i)],
-                         "markersize", s(i),
-                         "markeredgecolor", "none", "markerfacecolor", "flat",
-                         "cdata", reshape (c(i,:),[1, size(c)(2:end)]),
-                         "facevertexcdata", c(i,:));
-        endfor
-      endif
-    else
-      if (isempty (z))
-        for i = 1 : length (hlist)
-          set (hlist(i), "vertices", [x(i), y(i)],
-                         "markersize", s(i),
-                         "markeredgecolor", "flat", "markerfacecolor", "none",
-                         "cdata", reshape (c(i,:),[1, size(c)(2:end)]),
-                         "facevertexcdata", c(i,:));
-        endfor
-      else
-        for i = 1 : length (hlist)
-          set (hlist(i), "vertices", [x(i), y(i), z(i)],
-                         "markersize", s(i),
-                         "markeredgecolor", "flat", "markerfacecolor", "none",
-                         "cdata", reshape (c(i,:),[1, size(c)(2:end)]),
-                         "facevertexcdata", c(i,:));
-        endfor
-      endif
-    endif
-  endif
-
-endfunction
--- a/scripts/plot/draw/private/__unite_shared_vertices__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/private/__unite_shared_vertices__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -55,7 +55,7 @@
   [J, idx] = sort (J);
   j(idx) = 1:length (idx);
   vertices = vertices(idx,:);
-  if any (nan_vertices)
+  if (any (nan_vertices))
     j(end+1) = length (idx) + 1;
     vertices(end+1,:) = NaN;
     lut(nan_vertices) = rows (vertices);
--- a/scripts/plot/draw/rectangle.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/rectangle.m	Thu Nov 19 13:08:00 2020 -0800
@@ -107,7 +107,7 @@
         pos = varargin{iarg+1};
         varargin(iarg:iarg+1) = [];
         if (! isvector (pos) || numel (pos) != 4)
-          error ("rectangle: position must be a 4 element vector");
+          error ("rectangle: position must be a 4-element vector");
         endif
       elseif (strcmpi (arg, "curvature"))
         curv2 = varargin{iarg+1};
--- a/scripts/plot/draw/reducepatch.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/reducepatch.m	Thu Nov 19 13:08:00 2020 -0800
@@ -39,7 +39,8 @@
 ## The input patch can be represented by a structure @var{fv} with the
 ## fields @code{faces} and @code{vertices}, by two matrices @var{faces} and
 ## @var{vertices} (see, e.g., the result of @code{isosurface}), or by a
-## handle to a patch object @var{patch_handle} (@pxref{XREFpatch,,patch}).
+## handle to a patch object @var{patch_handle}
+## (@pxref{XREFpatch,,@code{patch}}).
 ##
 ## The number of faces and vertices in the patch is reduced by iteratively
 ## collapsing the shortest edge of the patch to its midpoint (as discussed,
@@ -363,7 +364,7 @@
 %! patch (fv, "FaceColor", "g");
 %! view (3);  axis equal;
 %! title ("Sphere with all faces");
-%! ax2 = subplot(1, 2, 2);
+%! ax2 = subplot (1, 2, 2);
 %! patch (reducepatch (fv, 72), "FaceColor", "g");
 %! view (3);  axis equal;
 %! title ("Sphere with reduced number of faces");
@@ -438,8 +439,8 @@
 %! assert (size (vertices_reduced, 2), 3);
 
 ## test for each error
-%!error reducepatch ()
-%!error reducepatch (fv, faces, vertices, .5, "f", "v")
+%!error <Invalid call> reducepatch ()
+%!error <Invalid call> reducepatch (fv, faces, vertices, .5, "f", "v")
 %!error <reducepatch: parameter 'foo' not supported>
 %! fv_reduced = reducepatch (faces, vertices, .7, "foo");
 %!error <struct FV must contain the fields 'vertices' and 'faces'>
--- a/scripts/plot/draw/reducevolume.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/reducevolume.m	Thu Nov 19 13:08:00 2020 -0800
@@ -43,7 +43,8 @@
 ## Optionally, @var{x}, @var{y}, and @var{z} can be supplied to represent the
 ## set of coordinates of @var{v}.  They can either be matrices of the same size
 ## as @var{v} or vectors with sizes according to the dimensions of @var{v}, in
-## which case they are expanded to matrices (@pxref{XREFmeshgrid,,meshgrid}).
+## which case they are expanded to matrices
+## (@pxref{XREFmeshgrid,,@code{meshgrid}}).
 ##
 ## If @code{reducevolume} is called with two arguments then @var{x}, @var{y},
 ## and @var{z} are assumed to match the respective indices of @var{v}.
@@ -263,9 +264,9 @@
 
 ## Test for each error
 %!test
-%!error reducevolume ()
-%!error reducevolume (1)
-%!error reducevolume (1,2,3,4,5,6)
+%!error <Invalid call> reducevolume ()
+%!error <Invalid call> reducevolume (1)
+%!error <Invalid call> reducevolume (1,2,3,4,5,6)
 %!error <incorrect number of arguments> reducevolume (1, 2, 3)
 %!error <R must be a scalar or a vector of length 3> reducevolume (v, [])
 %!error <R must be a scalar or a vector of length 3> reducevolume (v, [1 2])
--- a/scripts/plot/draw/ribbon.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/ribbon.m	Thu Nov 19 13:08:00 2020 -0800
@@ -60,7 +60,7 @@
     if (isvector (y))
       y = y(:);
     endif
-    x = 1:rows(y);
+    x = 1:rows (y);
     width = 0.75;
   elseif (nargin == 2)
     x = varargin{1};
@@ -122,6 +122,6 @@
 %! colormap ("default");
 %! [x, y, z] = sombrero ();
 %! ribbon (y, z);
-%! title ("ribbon() plot of sombrero()");
+%! title ("ribbon() plot of sombrero ()");
 
 %!FIXME: Could have some input validation tests here
--- a/scripts/plot/draw/rose.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/rose.m	Thu Nov 19 13:08:00 2020 -0800
@@ -72,7 +72,7 @@
 
   [hax, varargin, nargin] = __plt_get_axis_arg__ ("rose", varargin{:});
 
-  if (nargin < 1)
+  if (nargin < 1 || nargin > 2)
     print_usage ();
   endif
 
@@ -166,7 +166,8 @@
 %! title ("rose() angular histogram plot with specified bins");
 
 ## Test input validation
-%!error rose ()
+%!error <Invalid call> rose ()
+%!error <Invalid call> rose (1,2,3)
 %!warning <bin sizes .= pi will not plot correctly>
 %! [th, r] = rose ([1 2 2 4 4 4], 2);
 %!warning <bin 1 and bin 3 are not centered>
--- a/scripts/plot/draw/scatter.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/scatter.m	Thu Nov 19 13:08:00 2020 -0800
@@ -53,10 +53,6 @@
 ## If no marker is specified it defaults to @qcode{"o"} or circles.
 ## If the argument @qcode{"filled"} is given then the markers are filled.
 ##
-## Additional property/value pairs are passed directly to the underlying
-## patch object.  The full list of properties is documented at
-## @ref{Patch Properties}.
-##
 ## If the first argument @var{hax} is an axes handle, then plot into this axes,
 ## rather than the current axes returned by @code{gca}.
 ##
@@ -73,6 +69,8 @@
 ## @end group
 ## @end example
 ##
+## Programming Note: The full list of properties is documented at
+## @ref{Scatter Properties}.
 ## @seealso{scatter3, patch, plot}
 ## @end deftypefn
 
@@ -220,3 +218,20 @@
 %!     title (str);
 %!   endfor
 %! endfor
+
+
+%!testif ; ! strcmp (graphics_toolkit (), "gnuplot")
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   hs = scatter ([], []);
+%!   assert (get (hs, "type"), "scatter");
+%!   assert (isempty (get (hs, "xdata")));
+%!   assert (isempty (get (hs, "ydata")));
+%!   assert (isempty (get (hs, "zdata")));
+%!   assert (get (hs, "cdata"), [0, 0.4470, 0.7410]);
+%!   assert (get (hs, "cdatamode"), "auto");
+%!   assert (get (hs, "sizedata"), 36);
+%!   assert (get (hs, "linewidth"), 0.5);
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
--- a/scripts/plot/draw/scatter3.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/scatter3.m	Thu Nov 19 13:08:00 2020 -0800
@@ -53,14 +53,10 @@
 ## If no marker is specified it defaults to @qcode{"o"} or circles.
 ## If the argument @qcode{"filled"} is given then the markers are filled.
 ##
-## Additional property/value pairs are passed directly to the underlying
-## patch object.  The full list of properties is documented at
-## @ref{Patch Properties}.
-##
 ## If the first argument @var{hax} is an axes handle, then plot into this axes,
 ## rather than the current axes returned by @code{gca}.
 ##
-## The optional return value @var{h} is a graphics handle to the hggroup
+## The optional return value @var{h} is a graphics handle to the scatter
 ## object representing the points.
 ##
 ## @example
@@ -70,6 +66,8 @@
 ## @end group
 ## @end example
 ##
+## Programming Note: The full list of properties is documented at
+## @ref{Scatter Properties}.
 ## @seealso{scatter, patch, plot}
 ## @end deftypefn
 
--- a/scripts/plot/draw/semilogx.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/semilogx.m	Thu Nov 19 13:08:00 2020 -0800
@@ -104,12 +104,12 @@
 %!
 %! subplot (1,2,1);
 %!  semilogx (x, y);
-%!  set (gca, "xdir", "reverse", "activepositionproperty", "outerposition");
+%!  set (gca, "xdir", "reverse", "positionconstraint", "outerposition");
 %!  title ({"semilogx (x, y)", "xdir = reversed"});
 %!
 %! subplot (1,2,2);
 %!  semilogx (-x, y);
-%!  set (gca, "xdir", "reverse", "activepositionproperty", "outerposition");
+%!  set (gca, "xdir", "reverse", "positionconstraint", "outerposition");
 %!  title ({"semilogx (-x, y)", "xdir = reversed"});
 
 %!test
--- a/scripts/plot/draw/semilogxerr.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/semilogxerr.m	Thu Nov 19 13:08:00 2020 -0800
@@ -47,8 +47,8 @@
 ## @noindent
 ## which produces a semi-logarithmic plot of @var{y} versus @var{x}
 ## with errors in the @var{y}-scale defined by @var{ey} and the plot
-## format defined by @var{fmt}.  @xref{XREFerrorbar,,errorbar}, for available
-## formats and additional information.
+## format defined by @var{fmt}.  @xref{XREFerrorbar,,@code{errorbar}}, for
+## available formats and additional information.
 ##
 ## If the first argument @var{hax} is an axes handle, then plot into this axes,
 ## rather than the current axes returned by @code{gca}.
--- a/scripts/plot/draw/semilogy.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/semilogy.m	Thu Nov 19 13:08:00 2020 -0800
@@ -104,12 +104,12 @@
 %!
 %! subplot (2,1,1);
 %!  semilogy (x, y);
-%!  set (gca, "ydir", "reverse", "activepositionproperty", "outerposition");
+%!  set (gca, "ydir", "reverse", "positionconstraint", "outerposition");
 %!  title ({"semilogy (x, y)", "ydir = reversed"});
 %!
 %! subplot (2,1,2);
 %!  semilogy (x, -y);
-%!  set (gca, "ydir", "reverse", "activepositionproperty", "outerposition");
+%!  set (gca, "ydir", "reverse", "positionconstraint", "outerposition");
 %!  title ({"semilogy (x, -y)", "ydir = reversed"});
 
 %!test
--- a/scripts/plot/draw/semilogyerr.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/semilogyerr.m	Thu Nov 19 13:08:00 2020 -0800
@@ -47,8 +47,8 @@
 ## @noindent
 ## which produces a semi-logarithmic plot of @var{y} versus @var{x}
 ## with errors in the @var{y}-scale defined by @var{ey} and the plot
-## format defined by @var{fmt}.  @xref{XREFerrorbar,,errorbar}, for available
-## formats and additional information.
+## format defined by @var{fmt}.  @xref{XREFerrorbar,,@code{errorbar}}, for
+## available formats and additional information.
 ##
 ## If the first argument @var{hax} is an axes handle, then plot into this axes,
 ## rather than the current axes returned by @code{gca}.
--- a/scripts/plot/draw/shrinkfaces.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/shrinkfaces.m	Thu Nov 19 13:08:00 2020 -0800
@@ -73,7 +73,7 @@
 
 function [nf, nv] = shrinkfaces (varargin)
 
-  if (nargin < 1 || nargin > 3 || nargout > 2)
+  if (nargin < 1 || nargin > 3)
     print_usage ();
   endif
 
@@ -215,7 +215,7 @@
 %! axis auto;   # Kludge required for Octave
 %! axis equal;
 %! view (115, 30);
-%! drawnow;
+%! drawnow ();
 %! shrinkfaces (p, 0.6);
 %! title ("shrinkfaces() on 3-D complex shapes");
 
@@ -231,8 +231,8 @@
 %!assert (norm (nfv2.vertices - vertices), 0, 2*eps)
 
 ## Test input validation
-%!error shrinkfaces ()
-%!error shrinkfaces (1,2,3,4)
+%!error <Invalid call> shrinkfaces ()
+%!error <Invalid call> shrinkfaces (1,2,3,4)
 %!error [a,b,c] = shrinkfaces (1)
 %!error <scale factor must be a positive scalar> shrinkfaces (nfv, ones (2))
 %!error <scale factor must be a positive scalar> shrinkfaces (nfv, 0)
--- a/scripts/plot/draw/smooth3.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/smooth3.m	Thu Nov 19 13:08:00 2020 -0800
@@ -65,7 +65,7 @@
 
 function smoothed_data = smooth3 (data, method = "box", sz = 3, std_dev = 0.65)
 
-  if (nargin < 1 || nargin > 4)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -257,8 +257,7 @@
 %! assert (size_equal (a, b), true);
 
 ## Test input validation
-%!error smooth3 ()
-%!error smooth3 (1,2,3,4,5)
+%!error <Invalid call> smooth3 ()
 %!error <DATA must be a 3-D numeric matrix> smooth3 (cell (2,2,2))
 %!error <DATA must be a 3-D numeric matrix> smooth3 (1)
 %!error <METHOD must be a string> smooth3 (ones (2,2,2), {3})
--- a/scripts/plot/draw/sombrero.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/sombrero.m	Thu Nov 19 13:08:00 2020 -0800
@@ -56,9 +56,7 @@
 
 function [x, y, z] = sombrero (n = 41)
 
-  if (nargin > 2)
-    print_usage ();
-  elseif (n <= 1)
+  if (n <= 1)
     error ("sombrero: number of grid lines N must be greater than 1");
   endif
 
--- a/scripts/plot/draw/stairs.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/stairs.m	Thu Nov 19 13:08:00 2020 -0800
@@ -42,7 +42,7 @@
 ## of the same format as the @code{plot} command.
 ##
 ## Multiple property/value pairs may be specified, but they must appear in
-## pairs. The full list of properties is documented at
+## pairs.  The full list of properties is documented at
 ## @ref{Line Properties}.
 ##
 ## If the first argument @var{hax} is an axes handle, then plot into this axes,
@@ -329,9 +329,9 @@
 ## Invisible figure used for tests
 %!shared hf, hax
 %! hf = figure ("visible", "off");
-%! hax = axes;
+%! hax = axes ();
 
-%!error stairs ()
+%!error <Invalid call> stairs ()
 %!error <Y must be a numeric 2-D vector> stairs (hax, {1})
 %!error <Y must be a numeric 2-D vector> stairs (ones (2,2,2))
 %!error <X and Y must be numeric 2-D vector> stairs ({1}, 1)
--- a/scripts/plot/draw/stem.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/stem.m	Thu Nov 19 13:08:00 2020 -0800
@@ -225,7 +225,7 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error stem ()
+%!error <Invalid call> stem ()
 %!error <can not define Z for 2-D stem plot> stem (1,2,3)
 %!error <Y must be a vector or 2-D array> stem (ones (2,2,2))
 %!error <X and Y must be numeric> stem ({1})
--- a/scripts/plot/draw/stem3.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/stem3.m	Thu Nov 19 13:08:00 2020 -0800
@@ -90,7 +90,7 @@
 %! stem3 (cos (theta), sin (theta), theta);
 %! title ("stem3() plot");
 
-%!error stem3 ()
+%!error <Invalid call> stem3 ()
 %!error <must define X, Y, and Z> stem3 (1,2)
 %!error <X, Y, and Z must be numeric> stem3 ({1}, 1, 1)
 %!error <X, Y, and Z must be numeric> stem3 (1, {1}, 1)
--- a/scripts/plot/draw/stemleaf.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/stemleaf.m	Thu Nov 19 13:08:00 2020 -0800
@@ -130,7 +130,7 @@
   ## other options for the kinds of plots described by Tukey could be
   ## provided.  This may best be left to users.
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -585,8 +585,7 @@
 %! assert (r, rexp);
 
 ## Test input validation
-%!error stemleaf ()
-%!error stemleaf (1, 2, 3, 4)
+%!error <Invalid call> stemleaf ()
 %!error <X must be a vector> stemleaf (ones (2,2), "")
 %!warning <X truncated to integer values> tmp = stemleaf ([0 0.5 1],"");
 %!error <X must be a numeric vector> stemleaf ("Hello World", "data")
--- a/scripts/plot/draw/stream2.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/stream2.m	Thu Nov 19 13:08:00 2020 -0800
@@ -82,8 +82,6 @@
 
   options = [];
   switch (numel (varargin))
-    case 0
-      print_usage ();
     case {4,5}
       if (numel (varargin) == 4)
         [u, v, spx, spy] = varargin{:};
@@ -97,7 +95,7 @@
     case 7
       [x, y, u, v, spx, spy, options] = varargin{:};
     otherwise
-      error ("stream2: invalid number of inputs");
+      print_usage ();
   endswitch
 
   stepsize = 0.1;
@@ -110,7 +108,7 @@
         stepsize = options(1);
         max_vertices = options(2);
       otherwise
-        error ("stream2: invalid number of OPTIONS elements");
+        error ("stream2: OPTIONS must be a 1- or 2-element vector");
     endswitch
 
     if (! isreal (stepsize) || stepsize == 0)
@@ -207,11 +205,11 @@
 %! assert (numel (xy{:}), 10);
 
 ## Test input validation
-%!error stream2 ()
-%!error <invalid number of inputs> stream2 (1)
-%!error <invalid number of inputs> stream2 (1,2)
-%!error <invalid number of inputs> stream2 (1,2,3)
-%!error <invalid number of OPTIONS> stream2 (1,2,3,4, [1,2,3])
+%!error <Invalid call> stream2 ()
+%!error <Invalid call> stream2 (1)
+%!error <Invalid call> stream2 (1,2)
+%!error <Invalid call> stream2 (1,2,3)
+%!error <OPTIONS must be a 1- or 2-element> stream2 (1,2,3,4, [1,2,3])
 %!error <STEPSIZE must be a real scalar != 0> stream2 (1,2,3,4, [1i])
 %!error <STEPSIZE must be a real scalar != 0> stream2 (1,2,3,4, [0])
 %!error <MAX_VERTICES must be an integer> stream2 (1,2,3,4, [1, 1i])
--- a/scripts/plot/draw/stream3.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/stream3.m	Thu Nov 19 13:08:00 2020 -0800
@@ -58,7 +58,7 @@
 ## @end group
 ## @end example
 ##
-## @seealso{stream2, streamline, streamtube, ostreamtube}
+## @seealso{stream2, streamline, streamribbon, streamtube, ostreamtube}
 ## @end deftypefn
 
 ## References:
@@ -83,8 +83,6 @@
 
   options = [];
   switch (numel (varargin))
-    case 0
-      print_usage ();
     case {6,7}
       if (numel (varargin) == 6)
         [u, v, w, spx, spy, spz] = varargin{:};
@@ -98,7 +96,7 @@
     case 10
       [x, y, z, u, v, w, spx, spy, spz, options] = varargin{:};
     otherwise
-      error ("stream3: invalid number of inputs");
+      print_usage ();
   endswitch
 
   stepsize = 0.1;
@@ -111,7 +109,7 @@
         stepsize = options(1);
         max_vertices = options(2);
       otherwise
-        error ("stream3: invalid number of OPTIONS elements");
+        error ("stream3: OPTIONS must be a 1- or 2-element vector");
     endswitch
 
     if (! isreal (stepsize) || stepsize == 0)
@@ -231,14 +229,14 @@
 %! assert (numel (xyz{:}), 15);
 
 ## Test input validation
-%!error stream3 ()
-%!error <invalid number of inputs> stream3 (1)
-%!error <invalid number of inputs> stream3 (1,2)
-%!error <invalid number of inputs> stream3 (1,2,3)
-%!error <invalid number of inputs> stream3 (1,2,3,4)
-%!error <invalid number of inputs> stream3 (1,2,3,4,5)
-%!error <invalid number of inputs> stream3 (1,2,3,4,5,6,7,8)
-%!error <invalid number of OPTIONS> stream3 (1,2,3,4,5,6, [1,2,3])
+%!error <Invalid call> stream3 ()
+%!error <Invalid call> stream3 (1)
+%!error <Invalid call> stream3 (1,2)
+%!error <Invalid call> stream3 (1,2,3)
+%!error <Invalid call> stream3 (1,2,3,4)
+%!error <Invalid call> stream3 (1,2,3,4,5)
+%!error <Invalid call> stream3 (1,2,3,4,5,6,7,8)
+%!error <OPTIONS must be a 1- or 2-element> stream3 (1,2,3,4,5,6, [1,2,3])
 %!error <STEPSIZE must be a real scalar != 0> stream3 (1,2,3,4,5,6, [1i])
 %!error <STEPSIZE must be a real scalar != 0> stream3 (1,2,3,4,5,6, [0])
 %!error <MAX_VERTICES must be an integer> stream3 (1,2,3,4,5,6, [1, 1i])
--- a/scripts/plot/draw/streamline.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/streamline.m	Thu Nov 19 13:08:00 2020 -0800
@@ -61,7 +61,7 @@
 ## @end group
 ## @end example
 ##
-## @seealso{stream2, stream3, streamtube, ostreamtube}
+## @seealso{stream2, stream3, streamribbon, streamtube, ostreamtube}
 ## @end deftypefn
 
 function h = streamline (varargin)
@@ -154,7 +154,7 @@
 %! sy = 0.0;
 %! sz = 0.0;
 %! plot3 (sx, sy, sz, ".r", "markersize", 15);
-%! t = linspace (0, 12 * 2 * pi(), 500);
+%! t = linspace (0, 12 * 2 * pi (), 500);
 %! tx = exp (-a * t).*cos (t);
 %! ty = exp (-a * t).*sin (t);
 %! tz = - b * t;
@@ -167,7 +167,7 @@
 %! axis equal tight;
 
 ## Test input validation
-%!error streamline ()
+%!error <Invalid call> streamline ()
 %!error <Invalid call to streamline>
 %! hf = figure ("visible", "off");
 %! unwind_protect
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/draw/streamribbon.m	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,443 @@
+########################################################################
+##
+## Copyright (C) 2020 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn  {} {} streamribbon (@var{x}, @var{y}, @var{z}, @var{u}, @var{v}, @var{w}, @var{sx}, @var{sy}, @var{sz})
+## @deftypefnx {} {} streamribbon (@var{u}, @var{v}, @var{w}, @var{sx}, @var{sy}, @var{sz})
+## @deftypefnx {} {} streamribbon (@var{xyz}, @var{x}, @var{y}, @var{z}, @var{anlr_spd}, @var{lin_spd})
+## @deftypefnx {} {} streamribbon (@var{xyz}, @var{anlr_spd}, @var{lin_spd})
+## @deftypefnx {} {} streamribbon (@var{xyz}, @var{anlr_rot})
+## @deftypefnx {} {} streamribbon (@dots{}, @var{width})
+## @deftypefnx {} {} streamribbon (@var{hax}, @dots{})
+## @deftypefnx {} {@var{h} =} streamribbon (@dots{})
+## Calculate and display streamribbons.
+##
+## The streamribbon is constructed by rotating a normal vector around a
+## streamline according to the angular rotation of the vector field.
+##
+## The vector field is given by @code{[@var{u}, @var{v}, @var{w}]} and is
+## defined over a rectangular grid given by @code{[@var{x}, @var{y}, @var{z}]}.
+## The streamribbons start at the seed points
+## @code{[@var{sx}, @var{sy}, @var{sz}]}.
+##
+## @code{streamribbon} can be called with a cell array that contains
+## pre-computed streamline data.  To do this, @var{xyz} must be created with
+## the @code{stream3} function.  @var{lin_spd} is the linear speed of the
+## vector field and can be calculated from @code{[@var{u}, @var{v}, @var{w}]}
+## by the square root of the sum of the squares.  The angular speed
+## @var{anlr_spd} is the projection of the angular velocity onto the velocity
+## of the normalized vector field and can be calculated with the @code{curl}
+## command.  This option is useful if you need to alter the integrator step
+## size or the maximum number of streamline vertices.
+##
+## Alternatively, ribbons can be created from an array of vertices @var{xyz} of
+## a path curve.  @var{anlr_rot} contains the angles of rotation around the
+## edges between adjacent vertices of the path curve.
+##
+## The input parameter @var{width} sets the width of the streamribbons.
+##
+## Streamribbons are colored according to the total angle of rotation along the
+## ribbon.
+##
+## If the first argument @var{hax} is an axes handle, then plot into this axes,
+## rather than the current axes returned by @code{gca}.
+##
+## The optional return value @var{h} is a graphics handle to the plot objects
+## created for each streamribbon.
+##
+## Example:
+##
+## @example
+## @group
+## [x, y, z] = meshgrid (0:0.2:4, -1:0.2:1, -1:0.2:1);
+## u = - x + 10;
+## v = 10 * z.*x;
+## w = - 10 * y.*x;
+## streamribbon (x, y, z, u, v, w, [0, 0], [0, 0.6], [0, 0]);
+## view (3);
+## @end group
+## @end example
+##
+## @seealso{streamline, stream3, streamtube, ostreamtube}
+##
+## @end deftypefn
+
+## References:
+##
+## @inproceedings{
+##    title = {Feature Detection from Vector Quantities in a Numerically Simulated Hypersonic Flow Field in Combination with Experimental Flow Visualization},
+##    author = {Pagendarm, Hans-Georg and Walter, Birgit},
+##    year = {1994},
+##    publisher = {IEEE Computer Society Press},
+##    booktitle = {Proceedings of the Conference on Visualization ’94},
+##    pages = {117–123},
+## }
+##
+## @article{
+##    title = {Efficient streamline, streamribbon, and streamtube constructions on unstructured grids},
+##    author = {Ueng, Shyh-Kuang and Sikorski, C. and Ma, Kwan-Liu},
+##    year = {1996},
+##    month = {June},
+##    publisher = {IEEE Transactions on Visualization and Computer Graphics},
+## }
+##
+## @inproceedings{
+##    title = {Visualization of 3-D vector fields - Variations on a stream},
+##    author = {Dave Darmofal and Robert Haimes},
+##    year = {1992}
+## }
+##
+## @techreport{
+##    title = {Parallel Transport Approach to Curve Framing},
+##    author = {Andrew J. Hanson and Hui Ma},
+##    year = {1995}
+## }
+##
+## @article{
+##    title = {There is More than One Way to Frame a Curve},
+##    author = {Bishop, Richard},
+##    year = {1975},
+##    month = {03},
+##    volume = {82},
+##    publisher = {The American Mathematical Monthly}
+## }
+
+function h = streamribbon (varargin)
+
+  [hax, varargin, nargin] = __plt_get_axis_arg__ ("streamribbon", varargin{:});
+
+  width = [];
+  xyz = [];
+  anlr_spd = [];
+  lin_spd = [];
+  anlr_rot = [];
+  switch (nargin)
+    case 2
+      [xyz, anlr_rot] = varargin{:};
+    case 3
+      if (numel (varargin{3}) == 1)
+        [xyz, anlr_rot, width] = varargin{:};
+      else
+        [xyz, anlr_spd, lin_spd] = varargin{:};
+        [m, n, p] = size (anlr_spd);
+        [x, y, z] = meshgrid (1:n, 1:m, 1:p);
+      endif
+    case 4
+      [xyz, anlr_spd, lin_spd, width] = varargin{:};
+      [m, n, p] = size (anlr_spd);
+      [x, y, z] = meshgrid (1:n, 1:m, 1:p);
+    case 6
+      if (iscell (varargin{1}))
+        [xyz, x, y, z, anlr_spd, lin_spd] = varargin{:};
+      else
+        [u, v, w, spx, spy, spz] = varargin{:};
+        [m, n, p] = size (u);
+        [x, y, z] = meshgrid (1:n, 1:m, 1:p);
+      endif
+    case 7
+      if (iscell (varargin{1}))
+        [xyz, x, y, z, anlr_spd, lin_spd, width] = varargin{:};
+      else
+        [u, v, w, spx, spy, spz, width] = varargin{:};
+        [m, n, p] = size (u);
+        [x, y, z] = meshgrid (1:n, 1:m, 1:p);
+      endif
+    case 9
+      [x, y, z, u, v, w, spx, spy, spz] = varargin{:};
+    case 10
+      [x, y, z, u, v, w, spx, spy, spz, width] = varargin{:};
+    otherwise
+      print_usage ();
+  endswitch
+
+  if (isempty (xyz))
+    xyz = stream3 (x, y, z, u, v, w, spx, spy, spz);
+    anlr_spd = curl (x, y, z, u, v, w);
+    lin_spd = sqrt (u.*u + v.*v + w.*w);
+  endif
+
+  ## Derive scale factor from the bounding box diagonal
+  if (isempty (width))
+    mxx = mnx = mxy = mny = mxz = mnz = [];
+    j = 1;
+    for i = 1 : length (xyz)
+      sl = xyz{i};
+      if (! isempty (sl))
+        slx = sl(:,1); sly = sl(:,2); slz = sl(:,3);
+        mxx(j) = max (slx); mnx(j) = min (slx);
+        mxy(j) = max (sly); mny(j) = min (sly);
+        mxz(j) = max (slz); mnz(j) = min (slz);
+        j += 1;
+      endif
+    endfor
+    dx = max (mxx) - min (mnx);
+    dy = max (mxy) - min (mny);
+    dz = max (mxz) - min (mnz);
+    width = sqrt (dx*dx + dy*dy + dz*dz) / 25;
+  elseif (! isreal (width) || width <= 0)
+    error ("streamribbon: WIDTH must be a real scalar > 0");
+  endif
+
+  if (! isempty (anlr_rot))
+    for i = 1 : length (xyz)
+      if (rows (anlr_rot{i}) != rows (xyz{i}))
+        error ("streamribbon: ANLR_ROT must have same length as XYZ");
+      endif
+    endfor
+  endif
+
+  if (isempty (hax))
+    hax = gca ();
+  else
+    hax = hax(1);
+  endif
+
+  ## Angular speed of a paddle wheel spinning around a streamline in a fluid
+  ## flow "V":
+  ## dtheta/dt = 0.5 * <curl(V), V/norm(V)>
+  ##
+  ## Integration along a streamline segment with the length "h" yields the
+  ## rotation angle:
+  ## theta = 0.25 * h * <curl(V), V(0)/norm(V(0))^2) + V(h)/norm(V(h))^2)>
+  ##
+  ## Alternative approach using the curl angular speed "c = curl()":
+  ## theta = 0.5 * h * (c(0)/norm(V(0)) + c(h)/norm(V(h)))
+  ##
+  ## Hints:
+  ## i. ) For integration use trapezoidal rule
+  ## ii.) "V" can be assumend to be piecewise linear and curl(V) to be
+  ##      piecewise constant because of the used linear interpolation
+
+  h = [];
+  for i = 1 : length (xyz)
+    sl = xyz{i};
+    num_vertices = rows (sl);
+    if (! isempty (sl) && num_vertices > 1)
+      if (isempty (anlr_rot))
+        ## Plot from vector field
+        ## Interpolate onto streamline vertices
+        [lin_spd_sl, anlr_spd_sl, max_vertices] = ...
+                                  interp_sl (x, y, z, lin_spd, anlr_spd, sl);
+        if (max_vertices > 1)
+          ## Euclidean distance between two adjacent vertices
+          stepsize = vecnorm (diff (sl(1:max_vertices, :)), 2, 2);
+          ## Angular rotation around edges between two adjacent sl-vertices
+          ## Note: Potential "division by zero" is checked in interp_sl()
+          anlr_rot_sl = 0.5 * stepsize.*(anlr_spd_sl(1:max_vertices - 1)./ ...
+                                         lin_spd_sl(1:max_vertices - 1) + ...
+                                         anlr_spd_sl(2:max_vertices)./ ...
+                                         lin_spd_sl(2:max_vertices));
+
+          htmp = plotribbon (hax, sl, anlr_rot_sl, max_vertices, 0.5 * width);
+          h = [h; htmp];
+        endif
+      else
+          ## Plot from vertice array
+          anlr_rot_sl = anlr_rot{i};
+
+          htmp = plotribbon (hax, sl, anlr_rot_sl, num_vertices, 0.5 * width);
+          h = [h; htmp];
+      endif
+    endif
+  endfor
+
+endfunction
+
+function h = plotribbon (hax, sl, anlr_rot_sl, max_vertices, width2)
+
+  total_angle = cumsum (anlr_rot_sl);
+  total_angle = [0; total_angle];
+
+  ## 1st streamline segment
+  X0 = sl(1,:);
+  X1 = sl(2,:);
+  R = X1 - X0;
+  RE = R / norm (R);
+
+  ## Initial vector KE which is to be transported along the vertice array
+  KE = get_normal2 (RE);
+  XS10 = - width2 * KE + X0;
+  XS20 = width2 * KE + X0;
+
+  ## Apply angular rotation
+  cp = cos (anlr_rot_sl(1));
+  sp = sin (anlr_rot_sl(1));
+  KE = rotation (KE, RE, cp, sp).';
+
+  XS1 = - width2 * KE + X1;
+  XS2 = width2 * KE + X1;
+
+  px = zeros (2, max_vertices);
+  py = zeros (2, max_vertices);
+  pz = zeros (2, max_vertices);
+  pc = zeros (2, max_vertices);
+
+  px(:,1) = [XS10(1); XS20(1)];
+  py(:,1) = [XS10(2); XS20(2)];
+  pz(:,1) = [XS10(3); XS20(3)];
+  pc(:,1) = total_angle(1) * [1; 1];
+
+  px(:,2) = [XS1(1); XS2(1)];
+  py(:,2) = [XS1(2); XS2(2)];
+  pz(:,2) = [XS1(3); XS2(3)];
+  pc(:,2) = total_angle(2) * [1; 1];
+
+  for i = 3 : max_vertices
+
+    ## Next streamline segment
+    X0 = X1;
+    X1 = sl(i,:);
+    R = X1 - X0;
+    RE = R / norm (R);
+
+    ## Project KE onto RE and get the difference in order to transport
+    ## the normal vector KE along the vertex array
+    Kp = KE - RE * dot (KE, RE);
+    KE = Kp / norm (Kp);
+
+    ## Apply angular rotation to KE
+    cp = cos (anlr_rot_sl(i - 1));
+    sp = sin (anlr_rot_sl(i - 1));
+    KE = rotation (KE, RE, cp, sp).';
+
+    XS1 = - width2 * KE + X1;
+    XS2 = width2 * KE + X1;
+
+    px(:,i) = [XS1(1); XS2(1)];
+    py(:,i) = [XS1(2); XS2(2)];
+    pz(:,i) = [XS1(3); XS2(3)];
+    pc(:,i) = total_angle(i) * [1; 1];
+
+  endfor
+
+  h = surface (hax, px, py, pz, pc);
+
+endfunction
+
+## Interpolate speed and divergence onto the streamline vertices and
+## return the first chunck of valid samples until a singularity /
+## zero is hit or the streamline vertex array "sl" ends
+function [lin_spd_sl, anlr_spd_sl, max_vertices] = ...
+                               interp_sl (x, y, z, lin_spd, anlr_spd, sl)
+
+  anlr_spd_sl = interp3 (x, y, z, anlr_spd, sl(:,1), sl(:,2), sl(:,3));
+  lin_spd_sl = interp3 (x, y, z, lin_spd, sl(:,1), sl(:,2), sl(:,3));
+
+  is_singular_anlr_spd = find (isnan (anlr_spd_sl), 1, "first");
+  is_zero_lin_spd = find (lin_spd_sl == 0, 1, "first");
+
+  max_vertices = rows (sl);
+  if (! isempty (is_singular_anlr_spd))
+    max_vertices = min (max_vertices, is_singular_anlr_spd - 1);
+  endif
+  if (! isempty (is_zero_lin_spd))
+    max_vertices = min (max_vertices, is_zero_lin_spd - 1);
+  endif
+
+endfunction
+
+## N normal to X, so that N is in span ([0 0 1], X)
+## If not possible then span ([1 0 0], X)
+function N = get_normal2 (X)
+
+  if ((X(1) == 0) && (X(2) == 0))
+    A = [1, 0, 0];
+  else
+    A = [0, 0, 1];
+  endif
+
+  ## Project A onto X and get the difference
+  N = A - X * dot (A, X) / (norm (X)^2);
+  N /= norm (N);
+
+endfunction
+
+## Rotate X around U where |U| = 1
+## cp = cos (angle), sp = sin (angle)
+function Y = rotation (X, U, cp, sp)
+
+  ux = U(1);
+  uy = U(2);
+  uz = U(3);
+
+  Y(1,:) = X(1) * (cp + ux * ux * (1 - cp)) + ...
+           X(2) * (ux * uy * (1 - cp) - uz * sp) + ...
+           X(3) * (ux * uz * (1 - cp) + uy * sp);
+
+  Y(2,:) = X(1) * (uy * ux * (1 - cp) + uz * sp) + ...
+           X(2) * (cp + uy * uy * (1 - cp)) + ...
+           X(3) * (uy * uz * (1 - cp) - ux * sp);
+
+  Y(3,:) = X(1) * (uz * ux * (1 - cp) - uy * sp) + ...
+           X(2) * (uz * uy * (1 - cp) + ux * sp) + ...
+           X(3) * (cp + uz * uz * (1 - cp));
+
+endfunction
+
+
+%!demo
+%! clf;
+%! [x, y, z] = meshgrid (0:0.2:4, -1:0.2:1, -1:0.2:1);
+%! u = - x + 10;
+%! v = 10 * z.*x;
+%! w = - 10 * y.*x;
+%! sx = [0, 0];
+%! sy = [0, 0.6];
+%! sz = [0, 0];
+%! streamribbon (x, y, z, u, v, w, sx, sy, sz);
+%! hold on;
+%! quiver3 (x, y, z, u, v, w);
+%! colormap (jet);
+%! shading interp;
+%! camlight ("headlight");
+%! view (3);
+%! axis tight equal off;
+%! set (gca, "cameraviewanglemode", "manual");
+%! hcb = colorbar;
+%! title (hcb, "Angle");
+%! title ("Streamribbon");
+
+%!demo
+%! clf;
+%! t = (0:pi/50:2*pi).';
+%! xyz{1} = [cos(t), sin(t), 0*t];
+%! twist{1} = ones (numel (t), 1) * pi / (numel (t) - 1);
+%! streamribbon (xyz, twist, 0.5);
+%! colormap (jet);
+%! view (3);
+%! camlight ("headlight");
+%! axis tight equal off;
+%! title ("Moebius Strip");
+
+## Test input validation
+%!error <Invalid call> streamribbon ()
+%!error <Invalid call> streamribbon (1)
+%!error <Invalid call> streamribbon (1,2,3,4,5)
+%!error <Invalid call> streamribbon (1,2,3,4,5,6,7,8)
+%!error <Invalid call> streamribbon (1,2,3,4,5,6,7,8,9,10,11)
+%!error <WIDTH must be a real scalar . 0> streamribbon (1,2,3,1i)
+%!error <WIDTH must be a real scalar . 0> streamribbon (1,2,3,0)
+%!error <WIDTH must be a real scalar . 0> streamribbon (1,2,3,-1)
+%!error <ANLR_ROT must have same length as XYZ> streamribbon ({[1,1,1;2,2,2]},{[1,1,1]})
--- a/scripts/plot/draw/streamtube.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/streamtube.m	Thu Nov 19 13:08:00 2020 -0800
@@ -66,7 +66,7 @@
 ## The optional return value @var{h} is a graphics handle to the plot objects
 ## created for each tube.
 ##
-## @seealso{stream3, streamline, ostreamtube}
+## @seealso{stream3, streamline, streamribbon, ostreamtube}
 ## @end deftypefn
 
 function h = streamtube (varargin)
@@ -78,8 +78,6 @@
   div = [];
   dia = [];
   switch (nargin)
-    case 0
-      print_usage ();
     case 2
       ## "dia" can be a cell array or a constant
       if (iscell (varargin{2}) || numel (varargin{2}) == 1)
@@ -116,7 +114,7 @@
     case 10
       [x, y, z, u, v, w, spx, spy, spz, options] = varargin{:};
     otherwise
-      error ("streamtube: invalid number of inputs");
+      print_usage ();
   endswitch
 
   scale = 1;
@@ -129,7 +127,7 @@
         scale = options(1);
         num_circum = options(2);
       otherwise
-        error ("streamtube: invalid number of OPTIONS elements");
+        error ("streamtube: OPTIONS must be a 1- or 2-element vector");
     endswitch
 
     if (! isreal (scale) || scale <= 0)
@@ -169,7 +167,7 @@
   for i = 1 : length (xyz)
     sl = xyz{i};
     if (! isempty (sl))
-      slx = sl(:, 1); sly = sl(:, 2); slz = sl(:, 3);
+      slx = sl(:,1); sly = sl(:,2); slz = sl(:,3);
       mxx(j) = max (slx); mnx(j) = min (slx);
       mxy(j) = max (sly); mny(j) = min (sly);
       mxz(j) = max (slz); mnz(j) = min (slz);
@@ -226,10 +224,9 @@
   cp = cos (phi);
   sp = sin (phi);
 
-  X0 = sl(1, :);
-  X1 = sl(2, :);
-
-  ## 1st rotation axis
+  ## 1st streamline segment
+  X0 = sl(1,:);
+  X1 = sl(2,:);
   R = X1 - X0;
   RE = R / norm (R);
 
@@ -244,35 +241,34 @@
   py = zeros (num_circum, max_vertices);
   pz = zeros (num_circum, max_vertices);
 
-  px(:, 1) = XS0(1, :).';
-  py(:, 1) = XS0(2, :).';
-  pz(:, 1) = XS0(3, :).';
+  px(:,1) = XS0(1,:).';
+  py(:,1) = XS0(2,:).';
+  pz(:,1) = XS0(3,:).';
 
-  px(:, 2) = XS(1, :).';
-  py(:, 2) = XS(2, :).';
-  pz(:, 2) = XS(3, :).';
+  px(:,2) = XS(1,:).';
+  py(:,2) = XS(2,:).';
+  pz(:,2) = XS(3,:).';
 
   for i = 3 : max_vertices
 
-    KEold = KE;
+    ## Next streamline segment
     X0 = X1;
-
-    X1 = sl(i, :);
+    X1 = sl(i,:);
     R = X1 - X0;
     RE = R / norm (R);
 
-    ## Project KE onto RE and get the difference in order to calculate the next
-    ## guiding point
-    Kp = KEold - RE * dot (KEold, RE);
+    ## Project KE onto RE and get the difference in order to transport
+    ## the normal vector KE along the vertex array
+    Kp = KE - RE * dot (KE, RE);
     KE = Kp / norm (Kp);
     K = radius_sl(i) * KE;
 
     ## Rotate around RE and collect surface patches
     XS = rotation (K, RE, cp, sp) + repmat (X1.', 1, num_circum);
 
-    px(:, i) = XS(1, :).';
-    py(:, i) = XS(2, :).';
-    pz(:, i) = XS(3, :).';
+    px(:,i) = XS(1,:).';
+    py(:,i) = XS(2,:).';
+    pz(:,i) = XS(3,:).';
 
   endfor
 
@@ -285,7 +281,7 @@
 ## the streamline vertex array "sl" ends
 function [div_sl_crop, max_vertices] = interp_sl (x, y, z, div, sl)
 
-  div_sl = interp3 (x, y, z, div, sl(:, 1), sl(:, 2), sl(:, 3));
+  div_sl = interp3 (x, y, z, div, sl(:,1), sl(:,2), sl(:,3));
   is_nan = find (isnan (div_sl), 1, "first");
   is_inf = find (isinf (div_sl), 1, "first");
 
@@ -305,9 +301,9 @@
 function N = get_normal1 (X)
 
   if ((X(3) == 0) && (X(1) == -X(2)))
-    N = [- X(2) - X(3), X(1), X(1)];
+    N = [(- X(2) - X(3)), X(1), X(1)];
   else
-    N = [X(3), X(3), - X(1) - X(2)];
+    N = [X(3), X(3), (- X(1) - X(2))];
   endif
 
   N /= norm (N);
@@ -322,20 +318,21 @@
   uy = U(2);
   uz = U(3);
 
-  Y(1, :) = X(1) * (cp + ux * ux * (1 - cp)) + ...
-            X(2) * (ux * uy * (1 - cp) - uz * sp) + ...
-            X(3) * (ux * uz * (1 - cp) + uy * sp);
+  Y(1,:) = X(1) * (cp + ux * ux * (1 - cp)) + ...
+           X(2) * (ux * uy * (1 - cp) - uz * sp) + ...
+           X(3) * (ux * uz * (1 - cp) + uy * sp);
 
-  Y(2, :) = X(1) * (uy * ux * (1 - cp) + uz * sp) + ...
-            X(2) * (cp + uy * uy * (1 - cp)) + ...
-            X(3) * (uy * uz * (1 - cp) - ux * sp);
+  Y(2,:) = X(1) * (uy * ux * (1 - cp) + uz * sp) + ...
+           X(2) * (cp + uy * uy * (1 - cp)) + ...
+           X(3) * (uy * uz * (1 - cp) - ux * sp);
 
-  Y(3, :) = X(1) * (uz * ux * (1 - cp) - uy * sp) + ...
-            X(2) * (uz * uy * (1 - cp) + ux * sp) + ...
-            X(3) * (cp + uz * uz * (1 - cp));
+  Y(3,:) = X(1) * (uz * ux * (1 - cp) - uy * sp) + ...
+           X(2) * (uz * uy * (1 - cp) + ux * sp) + ...
+           X(3) * (cp + uz * uz * (1 - cp));
 
 endfunction
 
+
 %!demo
 %! clf;
 %! [x, y, z] = meshgrid (-3:0.15:3, -1:0.1:1, -1:0.1:1);
@@ -356,7 +353,7 @@
 %!demo
 %! clf;
 %! t = 0:.15:15;
-%! xyz{1} = [cos(t)' sin(t)' (t/3)'];
+%! xyz{1} = [cos(t)', sin(t)', (t/3)'];
 %! dia{1} = cos(t)';
 %! streamtube (xyz, dia);
 %! grid on;
@@ -369,12 +366,12 @@
 %! title ("Plot Arbitrary Tube");
 
 ## Test input validation
-%!error streamtube ()
-%!error <invalid number of inputs> streamtube (1)
-%!error <invalid number of inputs> streamtube (1,2,3,4)
-%!error <invalid number of inputs> streamtube (1,2,3,4,5,6,7,8)
-%!error <invalid number of inputs> streamtube (1,2,3,4,5,6,7,8,9,10,11)
-%!error <invalid number of OPTIONS elements> streamtube (1,2,[1,2,3])
+%!error <Invalid call> streamtube ()
+%!error <Invalid call> streamtube (1)
+%!error <Invalid call> streamtube (1,2,3,4)
+%!error <Invalid call> streamtube (1,2,3,4,5,6,7,8)
+%!error <Invalid call> streamtube (1,2,3,4,5,6,7,8,9,10,11)
+%!error <OPTIONS must be a 1- or 2-element vector> streamtube (1,2,[1,2,3])
 %!error <SCALE must be a real scalar . 0> streamtube (1,2,[1i])
 %!error <SCALE must be a real scalar . 0> streamtube (1,2,[0])
 %!error <SCALE must be a real scalar . 0> streamtube (1,2,[-1])
--- a/scripts/plot/draw/surface.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/surface.m	Thu Nov 19 13:08:00 2020 -0800
@@ -206,7 +206,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   h = surface;
+%!   h = surface ();
 %!   assert (findobj (hf, "type", "surface"), h);
 %!   assert (get (h, "xdata"), 1:3, eps);
 %!   assert (get (h, "ydata"), (1:3)', eps);
--- a/scripts/plot/draw/surfl.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/surfl.m	Thu Nov 19 13:08:00 2020 -0800
@@ -156,7 +156,7 @@
 
     ## Get view vector (vv).
     [az, el] = view ();
-    vv = sph2cart ((az - 90) * pi/180.0, el * pi/180.0, 1.0);
+    [vv(1), vv(2), vv(3)] = sph2cart ((az - 90) * pi/180.0, el * pi/180.0, 1.0);
 
     if (! have_lv)
       ## Calculate light vector (lv) from view vector.
--- a/scripts/plot/draw/surfnorm.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/surfnorm.m	Thu Nov 19 13:08:00 2020 -0800
@@ -203,8 +203,8 @@
 %!         "sombrero() function with 10 faces"});
 
 ## Test input validation
-%!error surfnorm ()
-%!error surfnorm (1,2)
+%!error <Invalid call> surfnorm ()
+%!error <Invalid call> surfnorm (1,2)
 %!error <X, Y, and Z must be 2-D real matrices> surfnorm (i)
 %!error <X, Y, and Z must be 2-D real matrices> surfnorm (i, 1, 1)
 %!error <X, Y, and Z must be 2-D real matrices> surfnorm (1, i, 1)
--- a/scripts/plot/draw/tetramesh.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/tetramesh.m	Thu Nov 19 13:08:00 2020 -0800
@@ -59,7 +59,7 @@
 
   [reg, prop] = parseparams (varargin);
 
-  if (length (reg) < 2 || length (reg) > 3)
+  if (numel (reg) < 2 || numel (reg) > 3)
     print_usage ();
   endif
 
--- a/scripts/plot/draw/trimesh.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/trimesh.m	Thu Nov 19 13:08:00 2020 -0800
@@ -76,7 +76,7 @@
       varargin(1) = [];
       if (isvector (c))
         c = c(:);
-      end
+      endif
       if (rows (c) != numel (z) && rows (c) != rows (tri))
         error ("trimesh: the numbers of colors specified in C must equal the number of vertices in Z or the number of triangles in TRI");
       elseif (columns (c) != 1 && columns (c) != 3)
@@ -122,9 +122,9 @@
 %! title ("trimesh() plot of sparsely-sampled peaks() function");
 
 ## Test input validation
-%!error trimesh ()
-%!error trimesh (1)
-%!error trimesh (1,2)
+%!error <Invalid call> trimesh ()
+%!error <Invalid call> trimesh (1)
+%!error <Invalid call> trimesh (1,2)
 %!error <the numbers of colors> trimesh (1,2,3,4,[5 6])
 %!error <the numbers of colors> trimesh (1,2,3,4,[5 6]')
 %!error <the numbers of colors> trimesh ([1;1],[2;2],[3;3],[4;4], zeros (3,3))
--- a/scripts/plot/draw/trisurf.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/draw/trisurf.m	Thu Nov 19 13:08:00 2020 -0800
@@ -71,7 +71,7 @@
     varargin(1) = [];
     if (isvector (c))
       c = c(:);
-    end
+    endif
     if (rows (c) != numel (z) && rows (c) != rows (tri))
       error ("trisurf: the numbers of colors specified in C must equal the number of vertices in Z or the number of triangles in TRI");
     elseif (columns (c) != 1 && columns (c) != 3)
@@ -138,7 +138,7 @@
 %! z = peaks (x, y);
 %! tri = delaunay (x(:), y(:));
 %! trisurf (tri, x(:), y(:), z(:));
-%! title ("trisurf() of sparsely-sampled triangulation of peaks()");
+%! title ("trisurf () of sparsely-sampled triangulation of peaks ()");
 
 %!demo
 %! clf;
@@ -171,10 +171,10 @@
 %! title ({"trisurf() of random data", '"facecolor" = "interp", "edgecolor" = "white"'});
 
 ## Test input validation
-%!error trisurf ()
-%!error trisurf (1)
-%!error trisurf (1,2)
-%!error trisurf (1,2,3)
+%!error <Invalid call> trisurf ()
+%!error <Invalid call> trisurf (1)
+%!error <Invalid call> trisurf (1,2)
+%!error <Invalid call> trisurf (1,2,3)
 %!error <the numbers of colors> trisurf (1,2,3,4,[5 6])
 %!error <the numbers of colors> trisurf (1,2,3,4,[5 6]')
 %!error <the numbers of colors> trisurf ([1;1],[2;2],[3;3],[4;4], zeros (3,3))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/util/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/plot/util/__actual_axis_position__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/__actual_axis_position__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -50,7 +50,7 @@
   end_unwind_protect
   ## Get axes size in pixels
   if (strcmp (get (axis_obj.parent, "__graphics_toolkit__"), "gnuplot")
-      && strcmp (axis_obj.activepositionproperty, "outerposition"))
+      && strcmp (axis_obj.positionconstraint, "outerposition"))
     pos_in_pixels = axis_obj.outerposition .* fig_position([3, 4, 3, 4]);
   else
     pos_in_pixels = axis_obj.position .* fig_position([3, 4, 3, 4]);
@@ -82,7 +82,7 @@
     endif
     pos = pos_in_pixels ./ fig_position([3, 4, 3, 4]);
   elseif (strcmp (get (axis_obj.parent, "__graphics_toolkit__"), "gnuplot")
-          && strcmp (axis_obj.activepositionproperty, "outerposition"))
+          && strcmp (axis_obj.positionconstraint, "outerposition"))
     pos = axis_obj.outerposition;
   else
     pos = axis_obj.position;
--- a/scripts/plot/util/__gnuplot_drawnow__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/__gnuplot_drawnow__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -30,7 +30,7 @@
 
 function __gnuplot_drawnow__ (h, term, file, debug_file)
 
-  if (nargin < 1 || nargin > 4 || nargin == 2)
+  if (nargin < 1 || nargin == 2)
     print_usage ();
   endif
 
@@ -269,7 +269,7 @@
     endif
 
     ## Set the gnuplot terminal (type, enhanced, title, options & size).
-    term_str = ["set terminal " term];
+    term_str = ["set encoding utf8;\nset terminal " term];
     if (__gnuplot_has_feature__ ("needs_color_with_postscript") ...
         && strcmp (term, "postscript"))
       term_str = [term_str, " color"];
--- a/scripts/plot/util/__opengl_info__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/__opengl_info__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -59,10 +59,6 @@
 
 function retval = __opengl_info__ ()
 
-  if (nargin != 0)
-    print_usage ();
-  endif
-
   [info, msg] = gl_info ();
 
   if (! isempty (msg))
--- a/scripts/plot/util/__pltopt__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/__pltopt__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -30,59 +30,59 @@
 ##
 ## @var{opt} can currently be some combination of the following:
 ##
-## @table @code
-## @item "-"
+## @table @asis
+## @item @qcode{"-"}
 ## For solid linestyle (default).
 ##
-## @item "--"
+## @item @qcode{"--"}
 ## For dashed line style.
 ##
-## @item "-."
+## @item @qcode{"-."}
 ## For linespoints plot style.
 ##
-## @item ":"
+## @item @qcode{":"}
 ## For dots plot style.
 ##
-## @item "r"
+## @item @qcode{"r"}
 ## Red line color.
 ##
-## @item "g"
+## @item @qcode{"g"}
 ## Green line color.
 ##
-## @item "b"
+## @item @qcode{"b"}
 ## Blue line color.
 ##
-## @item "c"
+## @item @qcode{"c"}
 ## Cyan line color.
 ##
-## @item "m"
+## @item @qcode{"m"}
 ## Magenta line color.
 ##
-## @item "y"
+## @item @qcode{"y"}
 ## Yellow line color.
 ##
-## @item "k"
+## @item @qcode{"k"}
 ## Black line color.
 ##
-## @item "w"
+## @item @qcode{"w"}
 ## White line color.
 ##
-## @item ";title;"
+## @item @qcode{";title;"}
 ## Here @code{"title"} is the label for the key.
 ##
-## @item  "+"
-## @itemx "o"
-## @itemx "*"
-## @itemx "."
-## @itemx "x"
-## @itemx "s"
-## @itemx "d"
-## @itemx "^"
-## @itemx "v"
-## @itemx ">"
-## @itemx "<"
-## @itemx "p"
-## @itemx "h"
+## @item  @qcode{"+"}
+## @itemx @qcode{"o"}
+## @itemx @qcode{"*"}
+## @itemx @qcode{"."}
+## @itemx @qcode{"x"}
+## @itemx @qcode{"s"}
+## @itemx @qcode{"d"}
+## @itemx @qcode{"^"}
+## @itemx @qcode{"v"}
+## @itemx @qcode{">"}
+## @itemx @qcode{"<"}
+## @itemx @qcode{"p"}
+## @itemx @qcode{"h"}
 ## Used in combination with the points or linespoints styles, set the point
 ## style.
 ## @end table
--- a/scripts/plot/util/allchild.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/allchild.m	Thu Nov 19 13:08:00 2020 -0800
@@ -38,7 +38,7 @@
 
 function h = allchild (handles)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -57,7 +57,7 @@
 %! toolkit = graphics_toolkit ("qt");
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   l = line;
+%!   l = line ();
 %!   kids = allchild (hf);
 %!   assert (get (kids, "type"), ...
 %!           {"axes"; "uitoolbar"; "uimenu"; "uimenu"; "uimenu"});
@@ -66,5 +66,4 @@
 %!   graphics_toolkit (toolkit);
 %! end_unwind_protect
 
-%!error allchild ()
-%!error allchild (1, 2)
+%!error <Invalid call> allchild ()
--- a/scripts/plot/util/ancestor.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/ancestor.m	Thu Nov 19 13:08:00 2020 -0800
@@ -42,7 +42,7 @@
 
 function p = ancestor (h, type, toplevel)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -91,7 +91,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   hl = line;
+%!   hl = line ();
 %!   assert (ancestor (hl, "axes"), gca);
 %!   assert (ancestor (hl, "figure"), hf);
 %! unwind_protect_cleanup
@@ -117,7 +117,6 @@
 
 %!assert (ancestor ([], "axes"), [])
 
-%!error ancestor ()
-%!error ancestor (1,2,3)
+%!error <Invalid call> ancestor ()
 %!error <TYPE must be a string> ancestor (1,2)
 %!error <third argument must be "toplevel"> ancestor (1, "axes", "foo")
--- a/scripts/plot/util/cla.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/cla.m	Thu Nov 19 13:08:00 2020 -0800
@@ -49,17 +49,13 @@
 
 function cla (hax, do_reset = false)
 
-  if (nargin > 2)
-    print_usage ();
-  endif
-
   if (nargin == 0)
-    hax = gca;
+    hax = gca ();
   elseif (nargin == 1)
     if (isscalar (hax) && isaxes (hax))
       ## Normal case : cla (hax) without reset
     elseif (ischar (hax) && strcmpi (hax, "reset"))
-      hax = gca;
+      hax = gca ();
       do_reset = true;
     else
       print_usage ();
@@ -98,7 +94,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   hax = gca;
+%!   hax = gca ();
 %!   plot (hax, 1:10);
 %!   assert (get (hax, "colororderindex"), 2);
 %!   set (hax, "ticklabelinterpreter", "none");
--- a/scripts/plot/util/clf.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/clf.m	Thu Nov 19 13:08:00 2020 -0800
@@ -52,14 +52,14 @@
   if (nargin > 2)
     print_usage ();
   elseif (nargin == 0)
-    hfig = gcf;
+    hfig = gcf ();
     do_reset = false;
   elseif (nargin == 1)
     if (isscalar (varargin{1}) && isfigure (varargin{1}))
       hfig = varargin{1};
       do_reset = false;
     elseif (ischar (varargin{1}) && strcmpi (varargin{1}, "reset"))
-      hfig = gcf;
+      hfig = gcf ();
       do_reset = true;
     else
       print_usage ();
@@ -119,7 +119,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   l = line;
+%!   l = line ();
 %!   assert (! isempty (get (gcf, "children")));
 %!   clf;
 %!   assert (isempty (get (gcf, "children")));
--- a/scripts/plot/util/close.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/close.m	Thu Nov 19 13:08:00 2020 -0800
@@ -63,9 +63,7 @@
 
   figs = [];
 
-  if (nargin > 2)
-    print_usage ();
-  elseif (nargin == 0)
+  if (nargin == 0)
     ## Close current figure.
     ## Can't use gcf because it opens a new plot window if one does not exist.
     figs = get (0, "currentfigure");
@@ -181,7 +179,6 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error close (1,2,3)
 %!error <first argument must be "all", a figure handle> close ({"all"})
 %!error <first argument must be "all", a figure handle> close (-1)
 %!error <second argument must be "hidden"> close all hid
--- a/scripts/plot/util/closereq.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/closereq.m	Thu Nov 19 13:08:00 2020 -0800
@@ -34,10 +34,6 @@
 
 function closereq ()
 
-  if (nargin != 0)
-    print_usage ();
-  endif
-
   ## Get current figure, but don't use gcf to avoid creating a new figure.
   cf = get (0, "currentfigure");
   if (isfigure (cf))
--- a/scripts/plot/util/colstyle.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/colstyle.m	Thu Nov 19 13:08:00 2020 -0800
@@ -34,7 +34,7 @@
 
 function [l, c, m, msg] = colstyle (style)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -94,6 +94,6 @@
 %! assert (msg, "colstyle: unrecognized format character: '~'");
 
 ## Test input validation
-%!error colstyle ()
+%!error <Invalid call> colstyle ()
 %!error colstyle (1, 2)
 %!error <STYLE must be a string> colstyle (1.5)
--- a/scripts/plot/util/copyobj.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/copyobj.m	Thu Nov 19 13:08:00 2020 -0800
@@ -48,7 +48,7 @@
   othertypes = {"line", "patch", "surface", "image", "text", "uicontrol"};
   alltypes = [partypes othertypes];
 
-  if (! ishghandle (horig) || nargin > 2)
+  if (! ishghandle (horig))
     print_usage ();
   elseif (! ishghandle (hparent))
     hparent = figure (fix (hparent));
@@ -79,7 +79,7 @@
   endfor
 
   if (kididx <= paridx)
-    error ("copyobj: %s object can't be a child of %s.",
+    error ("copyobj: %s object can't be a child of %s",
            alltypes{kididx}, alltypes{paridx});
   endif
 
--- a/scripts/plot/util/figure.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/figure.m	Thu Nov 19 13:08:00 2020 -0800
@@ -85,7 +85,7 @@
   ## Check to see if we already have a figure on the screen.  If we do,
   ## then update it if it is different from the figure we are creating
   ## or switching to.
-  cf = get (0, "currentfigure");   # Can't use gcf () because it calls figure()
+  cf = get (0, "currentfigure");   # Can't use gcf() because it calls figure()
   if (! isempty (cf) && cf != 0)
     if (init_new_figure || cf != f)
       drawnow ();
--- a/scripts/plot/util/findall.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/findall.m	Thu Nov 19 13:08:00 2020 -0800
@@ -38,7 +38,7 @@
 ##
 ## @code{findall} performs the same search as @code{findobj}, but it
 ## includes hidden objects (HandleVisibility = @qcode{"off"}).  For full
-## documentation, @pxref{XREFfindobj,,findobj}.
+## documentation, @pxref{XREFfindobj,,@code{findobj}}.
 ## @seealso{findobj, allchild, get, set}
 ## @end deftypefn
 
--- a/scripts/plot/util/findobj.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/findobj.m	Thu Nov 19 13:08:00 2020 -0800
@@ -88,8 +88,9 @@
 ## @end example
 ##
 ## Implementation Note: The search only includes objects with visible
-## handles (@w{HandleVisibility} = @qcode{"on"}).  @xref{XREFfindall,,findall},
-## to search for all objects including hidden ones.
+## handles (@w{HandleVisibility} = @qcode{"on"}).
+## @xref{XREFfindall,,@code{findall}}, to search for all objects including
+## hidden ones.
 ## @seealso{findall, allchild, get, set}
 ## @end deftypefn
 
@@ -329,7 +330,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   l = line;
+%!   l = line ();
 %!   obj = findobj (hf, "type", "line");
 %!   assert (l, obj);
 %!   assert (gca, findobj (hf, "type", "axes"));
--- a/scripts/plot/util/gca.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/gca.m	Thu Nov 19 13:08:00 2020 -0800
@@ -57,13 +57,9 @@
 
 function h = gca ()
 
-  if (nargin == 0)
-    h = get (gcf (), "currentaxes");
-    if (isempty (h))
-      h = axes ();
-    endif
-  else
-    print_usage ();
+  h = get (gcf (), "currentaxes");
+  if (isempty (h))
+    h = axes ();
   endif
 
 endfunction
@@ -71,7 +67,7 @@
 
 %!test
 %! hf = figure ("visible", "off");
-%! ax = axes;
+%! ax = axes ();
 %! unwind_protect
 %!   assert (gca, ax);
 %! unwind_protect_cleanup
--- a/scripts/plot/util/gcf.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/gcf.m	Thu Nov 19 13:08:00 2020 -0800
@@ -60,15 +60,11 @@
 
 function h = gcf ()
 
-  if (nargin == 0)
-    h = get (0, "currentfigure");
-    if (isempty (h) || h == 0)
-      ## We only have a root object, so create a new figure object
-      ## and make it the current figure.
-      h = figure ();
-    endif
-  else
-    print_usage ();
+  h = get (0, "currentfigure");
+  if (isempty (h) || h == 0)
+    ## We only have a root object, so create a new figure object
+    ## and make it the current figure.
+    h = figure ();
   endif
 
 endfunction
--- a/scripts/plot/util/ginput.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/ginput.m	Thu Nov 19 13:08:00 2020 -0800
@@ -46,10 +46,6 @@
 
 function varargout = ginput (n = -1)
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   ## Create an axis, if necessary.
   fig = gcf ();
   ax = gca ();
@@ -69,7 +65,7 @@
     else
       [varargout{:}] = feval (toolkit_fcn, fig, n);
     endif
-    return
+    return;
   endif
 
   x = y = button = [];
--- a/scripts/plot/util/graphics_toolkit.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/graphics_toolkit.m	Thu Nov 19 13:08:00 2020 -0800
@@ -45,10 +45,6 @@
 
 function retval = graphics_toolkit (name, hlist = [])
 
-  if (nargin > 2)
-    print_usage ();
-  endif
-
   if (nargout > 0 || nargin == 0)
     retval = get (0, "defaultfigure__graphics_toolkit__");
     ## Handle case where graphics_toolkit has been called before any plotting
@@ -92,7 +88,7 @@
     if (strcmp (name, "gnuplot"))
       valid_version = __gnuplot_has_feature__ ("minimum_version");
       if (valid_version != 1)
-        error ("graphics_toolkit: gnuplot version too old.");
+        error ("graphics_toolkit: gnuplot version too old");
       endif
     endif
     feval (["__init_", name, "__"]);
@@ -109,6 +105,7 @@
 
 endfunction
 
+
 %!testif HAVE_OPENGL, HAVE_QT; have_window_system () && any (strcmp ("qt", available_graphics_toolkits ()))
 %! unwind_protect
 %!   hf = figure ("visible", "off");
--- a/scripts/plot/util/groot.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/groot.m	Thu Nov 19 13:08:00 2020 -0800
@@ -58,16 +58,9 @@
 
 function h = groot ()
 
-  if (nargin != 0)
-    print_usage ();
-  endif
-
   h = 0;
 
 endfunction
 
 
 %!assert (groot (), 0)
-
-## Test input validation
-%!error groot (1)
--- a/scripts/plot/util/hdl2struct.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/hdl2struct.m	Thu Nov 19 13:08:00 2020 -0800
@@ -35,7 +35,7 @@
 
 function s = hdl2struct (h)
 
-  if (nargin != 1 || ! ishghandle (h))
+  if (nargin < 1 || ! ishghandle (h))
     print_usage ();
   endif
 
@@ -139,12 +139,13 @@
   persistent excluded;
 
   if (isempty (excluded))
-    excluded = cell2struct (repmat ({[]}, 1, 15),
+    excluded = cell2struct (repmat ({[]}, 1, 16),
                             {"beingdeleted", "busyaction", "buttondownfcn", ...
-                             "children", "clipping", "createfcn", ...
-                             "deletefcn", "handlevisibility", "hittest", ...
-                             "interruptible", "parent", "selected" , ...
-                             "selectionhighlight", "type", "uicontextmenu"}, 2);
+                             "children", "clipping", "contextmenu", ...
+                             "createfcn", "deletefcn", "handlevisibility", ...
+                             "hittest", "interruptible", "parent", ...
+                             "selected" , "selectionhighlight", "type", ...
+                             "uicontextmenu"}, 2);
   endif
 
   obj = get (h);
--- a/scripts/plot/util/hggroup.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/hggroup.m	Thu Nov 19 13:08:00 2020 -0800
@@ -68,7 +68,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   h = hggroup;
+%!   h = hggroup ();
 %!   assert (findobj (hf, "type", "hggroup"), h);
 %!   assert (get (h, "type"), "hggroup");
 %! unwind_protect_cleanup
--- a/scripts/plot/util/hgload.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/hgload.m	Thu Nov 19 13:08:00 2020 -0800
@@ -45,7 +45,7 @@
 function [h, old_prop] = hgload (filename, prop_struct = struct ())
 
   ## Check number of input arguments
-  if (nargin == 0 || nargin > 2)
+  if (nargin == 0)
     print_usage ();
   endif
 
@@ -133,8 +133,7 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error hgload ()
-%!error hgload (1, 2, 3)
+%!error <Invalid call> hgload ()
 %!error <PROP_STRUCT must be a struct> hgload (1, {})
 %!error <unable to locate file> hgload ("%%_A_REALLY_UNLIKELY_FILENAME_%%")
 %!error <unable to locate file> hgload ("%%_A_REALLY_UNLIKELY_FILENAME_%%.fig")
--- a/scripts/plot/util/hgsave.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/hgsave.m	Thu Nov 19 13:08:00 2020 -0800
@@ -61,7 +61,7 @@
 
 function hgsave (h, filename, fmt = "-binary")
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -134,8 +134,7 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error hgsave ()
-%!error hgsave (1, 2, 3, 4)
+%!error <Invalid call> hgsave ()
 %!error <no current figure to save>
 %! unwind_protect
 %!  old_fig = get (0, "currentfigure");
--- a/scripts/plot/util/isaxes.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/isaxes.m	Thu Nov 19 13:08:00 2020 -0800
@@ -34,7 +34,7 @@
 
 function retval = isaxes (h)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -66,5 +66,4 @@
 %!   close (hf);
 %! end_unwind_protect
 
-%!error isaxes ()
-%!error isaxes (1, 2)
+%!error <Invalid call> isaxes ()
--- a/scripts/plot/util/isfigure.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/isfigure.m	Thu Nov 19 13:08:00 2020 -0800
@@ -35,7 +35,7 @@
 
 function retval = isfigure (h)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -65,5 +65,4 @@
 %!   close (hf);
 %! end_unwind_protect
 
-%!error isfigure ()
-%!error isfigure (1, 2)
+%!error <Invalid call> isfigure ()
--- a/scripts/plot/util/isgraphics.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/isgraphics.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,7 +36,7 @@
 
 function retval = isgraphics (h, type = "")
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -61,8 +61,8 @@
 %!   assert (isgraphics (hf, "figure"));
 %!   assert (! isgraphics (-hf));
 %!   assert (! isgraphics (hf, "foo"));
-%!   l = line;
-%!   ax = gca;
+%!   l = line ();
+%!   ax = gca ();
 %!   assert (isgraphics (ax));
 %!   assert (isgraphics (ax, "axes"));
 %!   assert (! isgraphics (-ax));
@@ -71,17 +71,17 @@
 %!   assert (isgraphics (l, "line"));
 %!   assert (! isgraphics (-l));
 %!   assert (! isgraphics (l, "foo"));
-%!   p = patch;
+%!   p = patch ();
 %!   assert (isgraphics (p));
 %!   assert (isgraphics (p, "patch"));
 %!   assert (! isgraphics (-p));
 %!   assert (! isgraphics (p, "foo"));
-%!   s = surface;
+%!   s = surface ();
 %!   assert (isgraphics (s));
 %!   assert (isgraphics (s, "surface"));
 %!   assert (! isgraphics (-s));
 %!   assert (! isgraphics (s, "foo"));
-%!   t = text;
+%!   t = text ();
 %!   assert (isgraphics (t));
 %!   assert (isgraphics (t, "text"));
 %!   assert (! isgraphics (-t));
@@ -91,7 +91,7 @@
 %!   assert (isgraphics (i, "image"));
 %!   assert (! isgraphics (-i));
 %!   assert (! isgraphics (i, "foo"));
-%!   hg = hggroup;
+%!   hg = hggroup ();
 %!   assert (isgraphics (hg));
 %!   assert (isgraphics (hg, "hggroup"));
 %!   assert (! isgraphics (-hg));
@@ -106,7 +106,6 @@
 %! assert (isgraphics ([-1 0], "foobar"), [false false]);
 
 ## Test input validation
-%!error isgraphics ()
-%!error isgraphics (1, 2, 3)
+%!error <Invalid call> isgraphics ()
 %!error <TYPE must be a string> isgraphics (0, 1)
 %!error <TYPE must be a string> isgraphics (0, {1})
--- a/scripts/plot/util/ishandle.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/ishandle.m	Thu Nov 19 13:08:00 2020 -0800
@@ -41,7 +41,7 @@
 
 function retval = ishandle (h)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -55,8 +55,8 @@
 %! unwind_protect
 %!   assert (ishandle (hf));
 %!   assert (! ishandle (-hf));
-%!   ax = gca;
-%!   l = line;
+%!   ax = gca ();
+%!   l = line ();
 %!   assert (ishandle (ax));
 %!   assert (! ishandle (-ax));
 %!   assert (ishandle ([l, -1, ax, hf]), logical ([1, 0, 1, 1]));
@@ -72,5 +72,4 @@
 %! assert (ishandle (jobj));
 
 ## Test input validation
-%!error ishandle ()
-%!error ishandle (1, 2)
+%!error <Invalid call> ishandle ()
--- a/scripts/plot/util/ishold.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/ishold.m	Thu Nov 19 13:08:00 2020 -0800
@@ -37,10 +37,6 @@
 
 function retval = ishold (h)
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   if (nargin == 0)
     fig = gcf ();
     ax = get (fig, "currentaxes");
--- a/scripts/plot/util/isprop.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/isprop.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,29 +31,42 @@
 ## logical array indicating whether each handle has the property @var{prop}.
 ##
 ## For plotting, @var{obj} is a handle to a graphics object.  Otherwise,
-## @var{obj} should be an instance of a class.
-## @seealso{get, set, ismethod, isobject}
+## @var{obj} should be an instance of a class.  @code{isprop} reports whether
+## the class defines a property, but @code{Access} permissions or visibility
+## restrictions (@code{Hidden = true}) may prevent use by the programmer.
+## @seealso{get, set, properties, ismethod, isobject}
 ## @end deftypefn
 
 function res = isprop (obj, prop)
 
   if (nargin != 2)
     print_usage ();
-  elseif (! ischar (prop))
+  endif
+
+  if (! ischar (prop))
     error ("isprop: PROP name must be a string");
   endif
 
-  warning ("error", "Octave:abbreviated-property-match", "local");
+  if (isobject (obj))
+    ## Separate code for classdef objects because Octave doesn't handle arrays
+    ## of objects and so can't use the generic code.
+    warning ("off", "Octave:classdef-to-struct", "local");
+
+    all_props = __fieldnames__ (obj);
+    res = any (strcmp (prop, all_props));
+  else
+    warning ("error", "Octave:abbreviated-property-match", "local");
 
-  res = false (size (obj));
-  for i = 1:numel (res)
-    if (ishghandle (obj(i)))
-      try
-        v = get (obj(i), prop);
-        res(i) = true;
-      end_try_catch
-    endif
-  endfor
+    res = false (size (obj));
+    for i = 1:numel (res)
+      if (ishghandle (obj(i)))
+        try
+          get (obj(i), prop);
+          res(i) = true;
+        end_try_catch
+      endif
+    endfor
+  endif
 
 endfunction
 
@@ -63,7 +76,11 @@
 %!assert (isprop (zeros (2, 3), "visible"), true (2, 3))
 %!assert (isprop ([-2, -1, 0], "visible"), [false, false, true])
 
-%!error isprop ()
-%!error isprop (1)
-%!error isprop (1,2,3)
+%!test
+%! m = containers.Map ();
+%! assert (isprop (m, "KeyType"));
+%! assert (! isprop (m, "FooBar"));
+
+%!error <Invalid call> isprop ()
+%!error <Invalid call> isprop (1)
 %!error <PROP name must be a string> isprop (0, {"visible"})
--- a/scripts/plot/util/linkaxes.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/linkaxes.m	Thu Nov 19 13:08:00 2020 -0800
@@ -59,7 +59,7 @@
 
 function linkaxes (hax, optstr = "xy")
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -165,6 +165,5 @@
 %!  end_unwind_protect
 
 ## Test input validation
-%!error linkaxes ()
-%!error linkaxes (1,2,3)
+%!error <Invalid call> linkaxes ()
 %!error <HAX must be a vector of axes handles> linkaxes ([pi, e])
--- a/scripts/plot/util/linkprop.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/linkprop.m	Thu Nov 19 13:08:00 2020 -0800
@@ -171,9 +171,8 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error linkprop ()
-%!error linkprop (1)
-%!error linkprop (1,2,3)
+%!error <Invalid call> linkprop ()
+%!error <Invalid call> linkprop (1)
 %!error <H must contain at least 2 handles> linkprop (1, "color")
 %!error <invalid graphic handle in input H> linkprop ([pi, e], "color")
 %!error <PROP must be a string or cell string array> linkprop ([0, 0], 1)
--- a/scripts/plot/util/meshgrid.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/meshgrid.m	Thu Nov 19 13:08:00 2020 -0800
@@ -67,7 +67,7 @@
 
 function [xx, yy, zz] = meshgrid (x, y, z)
 
-  if (nargin == 0 || nargin > 3)
+  if (nargin == 0)
     print_usage ();
   endif
 
@@ -144,8 +144,7 @@
 %! assert (XX(end) * YY(end), x(end) * y(end));
 
 ## Test input validation
-%!error meshgrid ()
-%!error meshgrid (1,2,3,4)
+%!error <Invalid call> meshgrid ()
 %!error <X and Y must be vectors> meshgrid (ones (2,2), 1:3)
 %!error <X and Y must be vectors> meshgrid (1:3, ones (2,2))
 %!error <X, Y, and Z must be vectors> [X,Y,Z] = meshgrid (1:3, 1:3, ones (2,2))
--- a/scripts/plot/util/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -24,6 +24,7 @@
   %reldir%/private/__set_default_mouse_modes__.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/__actual_axis_position__.m \
   %reldir%/__default_plot_options__.m \
   %reldir%/__gnuplot_drawnow__.m \
--- a/scripts/plot/util/ndgrid.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/ndgrid.m	Thu Nov 19 13:08:00 2020 -0800
@@ -95,8 +95,8 @@
 %! x = 1:3;
 %! [XX, YY] = ndgrid (x);
 %! assert (size_equal (XX, YY));
-%! assert (isequal (XX, repmat(x(:), 1, numel(x))));
-%! assert (isequal (YY, repmat(x, numel(x), 1)));
+%! assert (isequal (XX, repmat (x(:), 1, numel (x))));
+%! assert (isequal (YY, repmat (x, numel (x), 1)));
 
 %!test
 %! x = 1:2;
@@ -124,10 +124,10 @@
 %! assert (XX1, XX2.');
 %! assert (YY1, YY2.');
 
-%!assert (ndgrid ([]), zeros(0,1))
+%!assert (ndgrid ([]), zeros (0,1))
 %!assert (ndgrid ([], []), zeros(0,0))
 
 ## Test input validation
-%!error ndgrid ()
+%!error <Invalid call> ndgrid ()
 %!error <wrong number of input arguments> [a,b,c] = ndgrid (1:3,1:3)
 %!error <arguments must be vectors> ndgrid (ones (2,2))
--- a/scripts/plot/util/newplot.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/newplot.m	Thu Nov 19 13:08:00 2020 -0800
@@ -89,10 +89,6 @@
 
 function hax = newplot (hsave = [])
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   cf = [];
   ca = [];
 
--- a/scripts/plot/util/pan.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/pan.m	Thu Nov 19 13:08:00 2020 -0800
@@ -46,35 +46,31 @@
 ## @seealso{rotate3d, zoom}
 ## @end deftypefn
 
-function pan (varargin)
-
-  hfig = NaN;
-
-  nargs = nargin;
+function h = pan (hfig, option)
 
-  if (nargs > 2)
-    print_usage ();
-  endif
-
-  if (nargin == 1 && nargout > 0 && isfigure (varargin{1}))
+  ## FIXME: Presumably should implement this for Matlab compatibility.
+  if (nargin == 1 && nargout > 0 && isfigure (hfig))
     error ("pan: syntax 'handle = pan (hfig)' not implemented");
   endif
 
-  if (nargs == 2)
-    hfig = varargin{1};
-    if (isfigure (hfig))
-      varargin(1) = [];
-      nargs -= 1;
+  if (nargin == 0)
+    hfig = gcf ();
+  else
+    if (nargin == 1)
+      option = hfig;
+      hfig = gcf ();
     else
-      error ("pan: invalid figure handle HFIG");
+      if (! isfigure (hfig))
+        error ("pan: invalid figure handle HFIG");
+      endif
+    endif
+
+    if (! ischar (option))
+      error ("pan: OPTION must be a string");
     endif
   endif
 
-  if (isnan (hfig))
-    hfig = gcf ();
-  endif
-
-  if (nargs == 0)
+  if (nargin == 0)
     pm = get (hfig, "__pan_mode__");
     if (strcmp (pm.Enable, "on"))
       pm.Enable = "off";
@@ -83,31 +79,26 @@
     endif
     set (hfig, "__pan_mode__", pm);
     update_mouse_mode (hfig, pm.Enable);
-  elseif (nargs == 1)
-    arg = varargin{1};
-    if (ischar (arg))
-      switch (arg)
-        case {"on", "off", "xon", "yon"}
-          pm = get (hfig, "__pan_mode__");
-          switch (arg)
-            case {"on", "off"}
-              pm.Enable = arg;
-              pm.Motion = "both";
-            case "xon"
-              pm.Enable = "on";
-              pm.Motion = "horizontal";
-            case "yon"
-              pm.Enable = "on";
-              pm.Motion = "vertical";
-          endswitch
-          set (hfig, "__pan_mode__", pm);
-          update_mouse_mode (hfig, arg);
-        otherwise
-          error ("pan: unrecognized OPTION '%s'", arg);
-      endswitch
-    else
-      error ("pan: wrong type argument '%s'", class (arg));
-    endif
+  else
+    switch (option)
+      case {"on", "off", "xon", "yon"}
+        pm = get (hfig, "__pan_mode__");
+        switch (option)
+          case {"on", "off"}
+            pm.Enable = option;
+            pm.Motion = "both";
+          case "xon"
+            pm.Enable = "on";
+            pm.Motion = "horizontal";
+          case "yon"
+            pm.Enable = "on";
+            pm.Motion = "vertical";
+        endswitch
+        set (hfig, "__pan_mode__", pm);
+        update_mouse_mode (hfig, option);
+      otherwise
+        error ("pan: unrecognized OPTION '%s'", option);
+    endswitch
   endif
 
 endfunction
@@ -119,8 +110,8 @@
   else
     ## FIXME: Is there a better way other than calling these functions
     ##        to set the other mouse mode Enable fields to "off"?
-    rotate3d ("off");
-    zoom ("off");
+    rotate3d (hfig, "off");
+    zoom (hfig, "off");
     set (hfig, "__mouse_mode__", "pan");
   endif
 
--- a/scripts/plot/util/print.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/print.m	Thu Nov 19 13:08:00 2020 -0800
@@ -472,12 +472,21 @@
     set (opts.figure, "__printing__", "on");
     nfig += 1;
 
-    ## print() requires children of axes to have units = "normalized", or "data"
-    hobj = findall (opts.figure, "-not", "type", "figure", ...
-                    "-not", "type", "axes", "-property", "units", ...
+    ## print() requires children of axes to have units = "normalized" or "data"
+    ## FIXME: Bug #59015.  The only graphics object type to which this
+    ## requirement applies seems to be 'text' objects.  It is simpler, and
+    ## clearer, to just select those objects.  The old code is left commented
+    ## out until sufficient testing has been done.
+    ## Change made: 2020/09/02.
+    ##hobj = findall (opts.figure, "-not", "type", "figure", ...
+    ##                "-not", "type", "axes", "-not", "type", "hggroup", ...
+    ##                "-property", "units", ...
+    ##                "-not", "units", "normalized", "-not", "units", "data");
+    ##hobj(strncmp (get (hobj, "type"), "ui", 2)) = [];
+
+    hobj = findall (opts.figure, "type", "text",
                     "-not", "units", "normalized", "-not", "units", "data");
-    hobj(strncmp (get (hobj, "type"), "ui", 2)) = [];
-    for n = 1:numel(hobj)
+    for n = 1:numel (hobj)
       props(end+1).h = hobj(n);
       props(end).name = "units";
       props(end).value = {get(hobj(n), "units")};
@@ -791,6 +800,7 @@
   if (isfigure (orig_figure))
     set (0, "currentfigure", orig_figure);
   endif
+
 endfunction
 
 function cmd = epstool (opts, filein, fileout)
@@ -801,7 +811,7 @@
 
   ## DOS Shell:
   ##   gs.exe [...] -sOutputFile=<filein> - & epstool -bbox -preview-tiff <filein> <fileout> & del <filein>
-  ## Unix Shell;
+  ## Unix Shell:
   ##   cat > <filein> ; epstool -bbox -preview-tiff <filein> <fileout> ; rm <filein>
 
   dos_shell = (ispc () && ! isunix ());
@@ -1004,13 +1014,10 @@
   switch (opts.devopt)
     case {"pdflatexstandalone"}
       packages = "\\usepackage{graphicx,color}";
-      graphicsfile = [opts.name "-inc.pdf"];
     case {"pslatexstandalone"}
       packages = "\\usepackage{epsfig,color}";
-      graphicsfile = [opts.name "-inc.ps"];
     otherwise
       packages = "\\usepackage{epsfig,color}";
-      graphicsfile = [opts.name "-inc.eps"];
   endswitch
 
   packages = {packages "\\usepackage[utf8]{inputenc}"};
@@ -1033,9 +1040,6 @@
     error ("Octave:print:errorclosingfile",
            "print: error closing file '%s'", latexfile);
   endif
-  ## FIXME: should this be fixed in GL2PS?
-  latex = strrep (latex, "\\includegraphics{}",
-                  sprintf ("\\includegraphics{%s}", graphicsfile));
 
   fid = fopen (latexfile, "w");
   if (fid >= 0)
--- a/scripts/plot/util/private/__add_default_menu__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/private/__add_default_menu__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -24,10 +24,14 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn  {} {} __add_default_menu__ (@var{hfig})
-## @deftypefnx {} {} __add_default_menu__ (@var{hfig}, @var{hmenu})
+## @deftypefn  {} {} __add_default_menu__ (@var{hf})
+## @deftypefnx {} {} __add_default_menu__ (@var{hf}, @var{hmenu})
+## @deftypefnx {} {} __add_default_menu__ (@var{hf}, @var{hmenu}, @var{htb})
 ## Add default menu and listeners to figure.
 ##
+## @var{hf} is a figure handle.
+## @var{hmenu} is a uimenu handle.
+## @var{htb} is a uitoolbar handle.
 ##
 ## All uimenu handles have their @qcode{"HandleVisibility"} property set to
 ## @qcode{"off"}.
@@ -37,7 +41,7 @@
 
   ## Gnuplot doesn't handle uimenu and uitoolbar objects
   if (strcmp (graphics_toolkit (), "gnuplot"))
-    return
+    return;
   endif
 
   ## Create
@@ -45,11 +49,11 @@
     ## File menu
     hui = uimenu (hf, "label", "&File", "tag", "__default_menu__File", ...
                       "handlevisibility", "off");
-    uimenu (hui, "label", "&Open", "callback", @open_cb, ...
+    uimenu (hui, "label", "&Open...", "callback", @open_cb, ...
             "accelerator", "o");
     uimenu (hui, "label", "&Save", "callback", {@save_cb, "save"}, ...
             "accelerator", "s");
-    uimenu (hui, "label", "Save &As", "callback", {@save_cb, "saveas"}, ...
+    uimenu (hui, "label", "Save &As...", "callback", {@save_cb, "saveas"}, ...
             "accelerator", "S");
     uimenu (hui, "label", "&Close", "callback", @close_cb, ...
             "accelerator", "w", "separator", "on");
@@ -173,17 +177,16 @@
   set (htb, "visible", toolbar_state);
 endfunction
 
-function open_cb (h, e)
-  [filename, filedir] = uigetfile ({"*.ofig", "Octave Figure File"}, ...
+function open_cb (~, ~)
+  [filename, filedir] = uigetfile ({"*.ofig;*.fig", "Figure Files"}, ...
                                    "Open Figure");
   if (filename != 0)
     fname = fullfile (filedir, filename);
-    tmphf = hgload (fname);
-    set (tmphf, "filename", fname);
+    openfig (fname);
   endif
 endfunction
 
-function save_cb (h, e, action)
+function save_cb (h, ~, action)
   hfig = gcbf ();
   fname = get (hfig, "filename");
 
@@ -198,34 +201,54 @@
   endif
 endfunction
 
+function __save_as__ (hf, fname = "")
+  if (! isempty (fname))
+    def = fname;
+  else
+    def = fullfile (pwd (), "untitled.ofig");
+  endif
+  filter = {"*.ofig", "Octave Figure";
+            "*.eps",  "Encapsulated PostScript";
+            "*.pdf",  "Portable Document Format";
+            "*.ps",   "PostScript";
+            "*.svg",  "Scalable Vector Graphics";
+            "*.gif",  "GIF Image";
+            "*.jpg",  "JPEG Image";
+            "*.png",  "Portable Network Graphics Image";
+            "*.tiff", "TIFF Image"};
+  ## Reorder filters to have current first
+  [~, ~, ext] = fileparts (def);
+  idx = strcmp (filter(:,1), ["*" tolower(ext)]);
+  filter = [filter(idx,:); filter(! idx,:)];
 
-function __save_as__ (hf, fname = "")
-  filter = ifelse (! isempty (fname), fname, ...
-                   {"*.ofig", "Octave Figure File";
-                    "*.eps;*.pdf;*.svg;*.ps", "Vector Image Formats";
-                    "*.gif;*.jpg;*.png;*.tiff", "Bitmap Image Formats"});
-  def = ifelse (! isempty (fname), fname, fullfile (pwd, "untitled.ofig"));
-
-  [filename, filedir] = uiputfile (filter, "Save Figure", def);
+  [filename, filedir, filteridx] = uiputfile (filter, "Save Figure", def);
 
   if (filename != 0)
     fname = fullfile (filedir, filename);
-    set (gcbf, "filename", fname);
-    flen = numel (fname);
-    if (flen > 5 && strcmp (fname(flen-4:end), ".ofig"))
-      hgsave (hf, fname);
+    [~, ~, ext] = fileparts (fname);
+    if (filteridx > rows (filter))
+      ## "All Files" option
+      if (isempty (ext))
+        fmt = "";
+      else
+        fmt = ext(2:end);
+      endif
     else
-      saveas (hf, fname);
+      fmt = filter{filteridx,1}(3:end);
+      if (isempty (ext))
+        fname = [fname "." fmt];
+      endif
     endif
+    set (hf, "filename", fname);
+    saveas (hf, fname, fmt);
   endif
+
 endfunction
 
-
-function close_cb (h, e)
-  close (gcbf);
+function close_cb (~, ~)
+  close (gcbf ());
 endfunction
 
-
 function [hax, fig] = __get_axes__ (h)
   ## Get parent figure
   fig = ancestor (h, "figure");
@@ -234,7 +257,7 @@
   hax = findobj (fig, "type", "axes", "-not", "tag", "legend");
 endfunction
 
-function autoscale_cb (h, e)
+function autoscale_cb (h, ~)
   hax = __get_axes__ (h);
   arrayfun (@(h) axis (h, "auto"), hax);
   drawnow ();
@@ -253,7 +276,8 @@
                                     "FigureHandle", hf));
 endfunction
 
-function guimode_cb (h, e)
+function guimode_cb (h, ~)
+
   [hax, fig] = __get_axes__ (h);
   id = get (h, "tag");
   switch (id)
@@ -273,9 +297,10 @@
     case "zoom_off"
       arrayfun (@(h) set (h, "mousewheelzoom", 0.0), hax);
   endswitch
+
 endfunction
 
-function mouse_tools_cb (h, ev, htools, typ = "")
+function mouse_tools_cb (h, ~, htools, typ = "")
 
   persistent recursion = false;
 
@@ -290,7 +315,7 @@
       mode = get (hf, "__mouse_mode__");
       state = "on";
 
-      switch mode
+      switch (mode)
         case "zoom"
           zm = get (hf, "__zoom_mode__");
           if (strcmp (zm.Direction, "in"))
@@ -318,7 +343,7 @@
       ## Update the mouse mode according to the button state
       state = get (h, "state");
 
-      switch typ
+      switch (typ)
         case {"zoomin", "zoomout"}
           prop = "__zoom_mode__";
           val = get (hf, prop);
@@ -329,7 +354,7 @@
             else
               val.Direction = "out";
             endif
-            set (hf, "__mouse_mode__" , "zoom");
+            set (hf, "__mouse_mode__", "zoom");
           endif
           val.Enable = state;
           set (hf, prop, val);
@@ -338,21 +363,21 @@
           prop = ["__", typ, "_mode__"];
           val = get (hf, prop);
           if (strcmp (state, "on"))
-            set (hf, "__mouse_mode__" , typ);
+            set (hf, "__mouse_mode__", typ);
           endif
           val.Enable = state;
           set (hf, prop, val);
 
         case {"text", "select"}
           if (strcmp (state, "on"))
-            set (hf, "__mouse_mode__" , typ);
+            set (hf, "__mouse_mode__", typ);
           endif
       endswitch
 
       if (strcmp (state, "on"))
         set (htools(htools != h), "state", "off");
       elseif (! any (strcmp (get (htools, "state"), "on")))
-        set (hf, "__mouse_mode__" , "none");
+        set (hf, "__mouse_mode__", "none");
       endif
     endif
 
@@ -361,7 +386,7 @@
 
 endfunction
 
-function axes_cb (h)
+function axes_cb (h, ~)
   hax = get (gcbf (), "currentaxes");
   if (! isempty (hax))
     if (strcmp (get (hax, "visible"), "on"))
@@ -372,7 +397,7 @@
   endif
 endfunction
 
-function grid_cb (h)
+function grid_cb (h, ~)
   hax = get (gcbf (), "currentaxes");
   if (! isempty (hax))
     if (strcmp (get (hax, "xgrid"), "on") && strcmp (get (hax, "ygrid"), "on"))
@@ -383,14 +408,15 @@
   endif
 endfunction
 
-function auto_cb (h)
+function auto_cb (h, ~)
   hax = get (gcbf (), "currentaxes");
   if (! isempty (hax))
     axis (hax, "auto");
   endif
 endfunction
 
-function clipboard_cb (h)
+function clipboard_cb (h, ~)
+
   hf = gcbf ();
   fname = tempname ();
   props = {"inverthardcopy", "paperposition", "paperpositionmode"};
@@ -402,4 +428,5 @@
   unwind_protect_cleanup
     set (hf, props, values);
   end_unwind_protect
+
 endfunction
--- a/scripts/plot/util/private/__gnuplot_draw_axes__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/private/__gnuplot_draw_axes__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -56,6 +56,10 @@
   endif
 
   nd = __calc_dimensions__ (h);
+  if (nd == 2 && (any (get (h, "view") != [0, 90])))
+    ## view() only works correctly on 3-D axes in gnuplot (bug #58526).
+    nd = 3;
+  endif
 
   if (strcmp (axis_obj.dataaspectratiomode, "manual")
       && strcmp (axis_obj.xlimmode, "manual")
@@ -87,7 +91,7 @@
     dr = 1;
   endif
 
-  if (strcmp (axis_obj.activepositionproperty, "position"))
+  if (strcmp (axis_obj.positionconstraint, "innerposition"))
     if (nd == 2 || all (mod (axis_obj.view, 90) == 0))
       x = [1, 1];
     else
@@ -103,7 +107,7 @@
     fprintf (plot_stream, "set rmargin screen %.15g;\n",
              pos(1)+pos(3)/2+x(1)*pos(3)/2);
     sz_str = "";
-  else ## activepositionproperty == outerposition
+  else  # positionconstraint == outerposition
     fprintf (plot_stream, "unset tmargin;\n");
     fprintf (plot_stream, "unset bmargin;\n");
     fprintf (plot_stream, "unset lmargin;\n");
@@ -148,13 +152,13 @@
     fputs (plot_stream, "unset title;\n");
   else
     if (nd == 2)
-      t = get(axis_obj.title);
+      t = get (axis_obj.title);
       colorspec = get_text_colorspec (t.color);
-      [tt, f, s] = __maybe_munge_text__ (enhanced, t, "string", t.interpreter);
+      [tt, f, s] = __maybe_munge_text__ (enhanced, t, "string", ...
+                                         t.interpreter, gnuplot_term);
       fontspec = create_fontspec (f, s, gnuplot_term);
       fprintf (plot_stream, ['set title "%s" %s %s %s;' "\n"],
-               undo_string_escapes (tt), fontspec, colorspec,
-               __do_enhanced_option__ (enhanced, t));
+               tt, fontspec, colorspec, __do_enhanced_option__ (enhanced, t));
     else
       ## Change meaning of "normalized", but it at least gives user some control
       if (! strcmp (get (axis_obj.title, "units"), "normalized"))
@@ -164,7 +168,7 @@
         unwind_protect_cleanup
         end_unwind_protect
       endif
-      t = get(axis_obj.title);
+      t = get (axis_obj.title);
       axispos = axis_obj.position;
       screenpos = t.position;
       screenpos(1) = axispos(1)+screenpos(1)*axispos(3);
@@ -182,16 +186,15 @@
       fprintf (plot_stream, "unset xlabel;\n");
       fprintf (plot_stream, "unset x2label;\n");
     else
-      [tt, f, s] = __maybe_munge_text__ (enhanced, t, "string", t.interpreter);
+      [tt, f, s] = __maybe_munge_text__ (enhanced, t, "string", ...
+                                         t.interpreter, gnuplot_term);
       fontspec = create_fontspec (f, s, gnuplot_term);
       if (strcmp (axis_obj.xaxislocation, "top"))
         fprintf (plot_stream, 'set x2label "%s" %s %s %s',
-                 undo_string_escapes (tt), colorspec, fontspec,
-                 __do_enhanced_option__ (enhanced, t));
+                 tt, colorspec, fontspec, __do_enhanced_option__ (enhanced, t));
       else
         fprintf (plot_stream, 'set xlabel "%s" %s %s %s',
-                 undo_string_escapes (tt), colorspec, fontspec,
-                 __do_enhanced_option__ (enhanced, t));
+                 tt, colorspec, fontspec, __do_enhanced_option__ (enhanced, t));
       endif
       fprintf (plot_stream, " rotate by %f;\n", angle);
       if (strcmp (axis_obj.xaxislocation, "top"))
@@ -210,16 +213,15 @@
       fprintf (plot_stream, "unset ylabel;\n");
       fprintf (plot_stream, "unset y2label;\n");
     else
-      [tt, f, s] = __maybe_munge_text__ (enhanced, t, "string", t.interpreter);
+      [tt, f, s] = __maybe_munge_text__ (enhanced, t, "string", ...
+                                         t.interpreter, gnuplot_term);
       fontspec = create_fontspec (f, s, gnuplot_term);
       if (strcmp (axis_obj.yaxislocation, "right"))
         fprintf (plot_stream, 'set y2label "%s" %s %s %s',
-                 undo_string_escapes (tt), colorspec, fontspec,
-                 __do_enhanced_option__ (enhanced, t));
+                 tt, colorspec, fontspec, __do_enhanced_option__ (enhanced, t));
       else
         fprintf (plot_stream, 'set ylabel "%s" %s %s %s',
-                 undo_string_escapes (tt), colorspec, fontspec,
-                 __do_enhanced_option__ (enhanced, t));
+                 tt, colorspec, fontspec, __do_enhanced_option__ (enhanced, t));
       endif
       fprintf (plot_stream, " rotate by %f;\n", angle);
       if (strcmp (axis_obj.yaxislocation, "right"))
@@ -237,11 +239,11 @@
     if (isempty (t.string))
       fputs (plot_stream, "unset zlabel;\n");
     else
-      [tt, f, s] = __maybe_munge_text__ (enhanced, t, "string", t.interpreter);
+      [tt, f, s] = __maybe_munge_text__ (enhanced, t, "string", ...
+                                         t.interpreter, gnuplot_term);
       fontspec = create_fontspec (f, s, gnuplot_term);
       fprintf (plot_stream, 'set zlabel "%s" %s %s %s',
-               undo_string_escapes (tt), colorspec, fontspec,
-               __do_enhanced_option__ (enhanced, t));
+               tt, colorspec, fontspec, __do_enhanced_option__ (enhanced, t));
       fprintf (plot_stream, " rotate by %f;\n", angle);
     endif
   endif
@@ -625,13 +627,12 @@
             have_3d_patch(data_idx) = false;
             tmpdispname = obj.displayname;
             obj.displayname = get (obj.parent, "displayname");
-            tmp = undo_string_escapes (
-                    __maybe_munge_text__ (enhanced, obj, "displayname", hlgndntrp)
-                  );
+            tmp = __maybe_munge_text__ (enhanced, obj, "displayname", ...
+                                        hlgndntrp, gnuplot_term);
             titlespec{data_idx} = ['title "' tmp '"'];
             obj.displayname = tmpdispname;
             if (! isempty (findobj (obj.parent, "-property", "format", "-depth", 0)))
-              # Place phantom errorbar data for legend
+              ## Place phantom errorbar data for legend
               data{data_idx} = NaN (4,1);
               usingclause{data_idx} = sprintf ("record=1 using ($1):($2):($3):($4)");
               switch (get (obj.parent, "format"))
@@ -646,15 +647,15 @@
                 otherwise
                   errbars = "xerrorbars";
               endswitch
-              withclause{data_idx} = sprintf ("with %s linestyle %d",
+              withclause{data_idx} = sprintf ("with %s linestyle %d", ...
                                               errbars, sidx(1));
             else
               ## Place phantom stemseries data for legend
               data{data_idx} = NaN (2,1);
               usingclause{data_idx} = sprintf ("record=1 using ($1):($2)");
               hgobj = get (obj.parent);
-              [hgstyle, hgsidx] = do_linestyle_command (hgobj, hgobj.color, data_idx,
-                                                        plot_stream);
+              [hgstyle, hgsidx] = do_linestyle_command (hgobj, hgobj.color, ...
+                                                        data_idx, plot_stream);
               withclause{data_idx} = sprintf ("with %s linestyle %d",
                                               hgstyle{1}, hgsidx(1));
             endif
@@ -675,9 +676,8 @@
         if (isempty (obj.displayname))
           titlespec{data_idx} = 'title ""';
         else
-          tmp = undo_string_escapes (
-                  __maybe_munge_text__ (enhanced, obj, "displayname", hlgndntrp)
-                );
+          tmp = __maybe_munge_text__ (enhanced, obj, "displayname", ...
+                                      hlgndntrp, gnuplot_term);
           titlespec{data_idx} = ['title "' tmp '"'];
         endif
         usingclause{data_idx} = sprintf ("record=%d", numel (obj.xdata));
@@ -798,9 +798,8 @@
               if (i > 1 || isempty (obj.displayname))
                 titlespec{local_idx} = 'title ""';
               else
-                tmp = undo_string_escapes (
-                        __maybe_munge_text__ (enhanced, obj, "displayname", hlgndntrp)
-                      );
+                tmp = __maybe_munge_text__ (enhanced, obj, "displayname", ...
+                                            hlgndntrp, gnuplot_term);
                 titlespec{local_idx} = ['title "' tmp '"'];
               endif
               if (isfield (obj, "facecolor"))
@@ -865,7 +864,7 @@
 
               if (nd == 3 && numel (xcol) == 3)
                 if (isnan (ccdat))
-                  ccdat = (cmap_sz + rows (addedcmap) + 1) * ones(3, 1);
+                  ccdat = (cmap_sz + rows (addedcmap) + 1) * ones (3, 1);
                   addedcmap = [addedcmap; reshape(color, 1, 3)];
                 elseif (numel (ccdat) == 1)
                   ccdat = ccdat * ones (size (zcol));
@@ -1001,7 +1000,7 @@
                 colorspec = "palette";
               elseif (columns (ccol) == 3)
                 colorspec = "lc rgb variable";
-                ccol = 255*ccol*[0x1; 0x100; 0x10000];
+                ccol = 255*ccol*double ([0x00_00_01; 0x00_01_00; 0x01_00_00]);
               endif
             else
               colorspec = sprintf ('lc rgb "#%02x%02x%02x"',
@@ -1211,9 +1210,8 @@
           parametric(data_idx) = false;
           have_cdata(data_idx) = false;
           have_3d_patch(data_idx) = false;
-          tmp = undo_string_escapes (
-                  __maybe_munge_text__ (enhanced, obj, "displayname", hlgndntrp)
-                );
+          tmp = __maybe_munge_text__ (enhanced, obj, "displayname", ...
+                                      hlgndntrp, gnuplot_term);
           titlespec{data_idx} = ['title "' tmp '"'];
           data{data_idx} = NaN (3,1);
           usingclause{data_idx} = sprintf ("record=1 using ($1):($2):($3)");
@@ -1976,7 +1974,7 @@
       endif
     endif
   endif
-  if (! isempty(pt) && isfield (obj, "markeredgecolor")
+  if (! isempty (pt) && isfield (obj, "markeredgecolor")
       && ! strcmp (obj.markeredgecolor, "none"))
     if (facesame && (strcmp (obj.markeredgecolor, "auto")
         || (isnumeric (obj.markeredgecolor)
@@ -2007,7 +2005,7 @@
           edgecolor = obj.markeredgecolor;
         else
           edgecolor = obj.color;
-        end
+        endif
         fprintf (plot_stream, ' linecolor rgb "#%02x%02x%02x"',
                  round (255*edgecolor));
       else
@@ -2264,7 +2262,8 @@
   endif
   if (strcmp (interpreter, "tex"))
     for n = 1 : numel (labels)
-      labels{n} = __tex2enhanced__ (labels{n}, fontname, false, false);
+      labels{n} = __tex2enhanced__ (labels{n}, fontname, false, false, ...
+                                    gnuplot_term);
     endfor
   elseif (strcmp (interpreter, "latex"))
     if (! warned_latex)
@@ -2295,7 +2294,7 @@
   fprintf (plot_stream, ['set format %s "%s";' "\n"], ax, fmt);
   if (strcmp (ticmode, "manual") && isempty (tics))
     fprintf (plot_stream, "unset %stics;\nunset m%stics;\n", ax, ax);
-    return
+    return;
   else
     k = 1;
     ntics = numel (tics);
@@ -2305,7 +2304,7 @@
              tickdir, ticklength, axispos, mirror);
     labels = strrep (labels, "%", "%%");
     for i = 1:ntics
-      fprintf (plot_stream, ' "%s" %.15g', labels{k++}, tics(i));
+      fprintf (plot_stream, ' "%s" %.15f', labels{k++}, tics(i));
       if (i < ntics)
         fputs (plot_stream, ", ");
       endif
@@ -2395,7 +2394,8 @@
 
 endfunction
 
-function [str, f, s] = __maybe_munge_text__ (enhanced, obj, fld, ntrp)
+function [str, f, s] = __maybe_munge_text__ (enhanced, obj, fld, ntrp, ...
+                                             gnuplot_term)
   persistent warned_latex = false;
 
   if (strcmp (fld, "string"))
@@ -2432,10 +2432,10 @@
     if (strcmp (ntrp, "tex"))
       if (iscellstr (str))
         for n = 1:numel (str)
-          str{n} = __tex2enhanced__ (str{n}, fnt, it, bld);
+          str{n} = __tex2enhanced__ (str{n}, fnt, it, bld, gnuplot_term);
         endfor
       else
-        str = __tex2enhanced__ (str, fnt, it, bld);
+        str = __tex2enhanced__ (str, fnt, it, bld, gnuplot_term);
       endif
     elseif (strcmp (ntrp, "latex"))
       if (! warned_latex)
@@ -2451,20 +2451,26 @@
 
 endfunction
 
-function str = __tex2enhanced__ (str, fnt, it, bld)
+function str = __tex2enhanced__ (str, fnt, it, bld, gnuplot_term)
   persistent sym = __setup_sym_table__ ();
   persistent flds = fieldnames (sym);
 
+  if (any (strcmp (gnuplot_term, {"postscript", "epscairo"})))
+    symtype = 1;
+  else
+    symtype = 2;
+  endif
+
   [s, e, m] = regexp (str, "\\\\([a-zA-Z]+|0)", "start", "end", "matches");
 
   for i = length (s) : -1 : 1
-    ## special case for "\0"  and replace with empty set "{/Symbol \306}'
+    ## special case for "\0"  and replace with empty set equivalent
     if (strncmp (m{i}, '\0', 2))
-      str = [str(1:s(i) - 1) '{/Symbol \306}' str(s(i) + 2:end)];
+      str = [str(1:s(i) - 1) sym.emptyset{symtype} str(s(i) + 2:end)];
     else
       f = m{i}(2:end);
       if (isfield (sym, f))
-        g = getfield (sym, f);
+        g = sym.(f){symtype};
         ## FIXME: The symbol font doesn't seem to support bold or italic
         ##if (bld)
         ##  if (it)
@@ -2528,8 +2534,8 @@
                  '{}', str(e(i) + b2(1) + 1:end)];
         endif
       elseif (strcmp (f, "fontsize"))
-        b1 = strfind (str(e(i) + 1:end),'{');
-        b2 = strfind (str(e(i) + 1:end),'}');
+        b1 = strfind (str(e (i) + 1:end),'{');
+        b2 = strfind (str(e (i) + 1:end),'}');
         if (isempty (b1) || isempty (b2))
           warning ('syntax error in \fontname argument');
         else
@@ -2541,7 +2547,7 @@
         ## like \pix, that should be translated to the symbol Pi and x
         for j = 1 : length (flds)
           if (strncmp (flds{j}, f, length (flds{j})))
-            g = getfield (sym, flds{j});
+            g = sym.(flds{j}){symtype};
             ## FIXME: The symbol font doesn't seem to support bold or italic
             ##if (bld)
             ##  if (it)
@@ -2564,7 +2570,7 @@
   ## But need to put the shorter of the two arguments first.
   ## Careful of nested {} and unprinted characters when defining
   ## shortest..  Don't have to worry about things like ^\theta as they
-  ## are already converted to ^{/Symbol q}.
+  ## are already converted.
 
   ## FIXME: This is a mess.  Is it worth it just for a "@" character?
 
@@ -2653,118 +2659,122 @@
 endfunction
 
 function sym = __setup_sym_table__ ()
+
   ## Setup the translation table for TeX to gnuplot enhanced mode.
-  sym.forall = '{/Symbol \042}';
-  sym.exists = '{/Symbol \044}';
-  sym.ni = '{/Symbol \047}';
-  sym.cong = '{/Symbol \100}';
-  sym.Delta = '{/Symbol D}';
-  sym.Phi = '{/Symbol F}';
-  sym.Gamma = '{/Symbol G}';
-  sym.vartheta = '{/Symbol J}';
-  sym.Lambda = '{/Symbol L}';
-  sym.Pi = '{/Symbol P}';
-  sym.Theta = '{/Symbol Q}';
-  sym.Sigma = '{/Symbol S}';
-  sym.varsigma = '{/Symbol V}';
-  sym.Omega = '{/Symbol W}';
-  sym.Xi = '{/Symbol X}';
-  sym.Psi = '{/Symbol Y}';
-  sym.perp = '{/Symbol \136}';
-  sym.alpha = '{/Symbol a}';
-  sym.beta = '{/Symbol b}';
-  sym.chi = '{/Symbol c}';
-  sym.delta = '{/Symbol d}';
-  sym.epsilon = '{/Symbol e}';
-  sym.phi = '{/Symbol f}';
-  sym.gamma = '{/Symbol g}';
-  sym.eta = '{/Symbol h}';
-  sym.iota = '{/Symbol i}';
-  sym.varphi = '{/Symbol j}';              # Not in OpenGL
-  sym.kappa = '{/Symbol k}';
-  sym.lambda = '{/Symbol l}';
-  sym.mu = '{/Symbol m}';
-  sym.nu = '{/Symbol n}';
-  sym.o = '{/Symbol o}';
-  sym.pi = '{/Symbol p}';
-  sym.theta = '{/Symbol q}';
-  sym.rho = '{/Symbol r}';
-  sym.sigma = '{/Symbol s}';
-  sym.tau = '{/Symbol t}';
-  sym.upsilon = '{/Symbol u}';
-  sym.varpi = '{/Symbol v}';
-  sym.omega = '{/Symbol w}';
-  sym.xi = '{/Symbol x}';
-  sym.psi = '{/Symbol y}';
-  sym.zeta = '{/Symbol z}';
-  sym.sim = '{/Symbol \176}';
-  sym.Upsilon = '{/Symbol \241}';
-  sym.prime = '{/Symbol \242}';
-  sym.leq = '{/Symbol \243}';
-  sym.infty = '{/Symbol \245}';
-  sym.clubsuit = '{/Symbol \247}';
-  sym.diamondsuit = '{/Symbol \250}';
-  sym.heartsuit = '{/Symbol \251}';
-  sym.spadesuit = '{/Symbol \252}';
-  sym.leftrightarrow = '{/Symbol \253}';
-  sym.leftarrow = '{/Symbol \254}';
-  sym.uparrow = '{/Symbol \255}';
-  sym.rightarrow = '{/Symbol \256}';
-  sym.downarrow = '{/Symbol \257}';
-  sym.circ = '{/Symbol \260}';         # degree symbol, not circ as in FLTK
-  sym.deg = '{/Symbol \260}';
-  sym.ast = '{/Symbol *}';
-  sym.pm = '{/Symbol \261}';
-  sym.geq = '{/Symbol \263}';
-  sym.times = '{/Symbol \264}';
-  sym.propto = '{/Symbol \265}';
-  sym.partial = '{/Symbol \266}';
-  sym.bullet = '{/Symbol \267}';
-  sym.div = '{/Symbol \270}';
-  sym.neq = '{/Symbol \271}';
-  sym.equiv = '{/Symbol \272}';
-  sym.approx = '{/Symbol \273}';
-  sym.ldots = '{/Symbol \274}';
-  sym.mid = '{/Symbol \275}';
-  sym.aleph = '{/Symbol \300}';
-  sym.Im = '{/Symbol \301}';
-  sym.Re = '{/Symbol \302}';
-  sym.wp = '{/Symbol \303}';
-  sym.otimes = '{/Symbol \304}';
-  sym.oplus = '{/Symbol \305}';
+  sym.forall = {'{/Symbol \042}', '∀'};
+  sym.exists = {'{/Symbol \044}', '∃'};
+  sym.ni = {'{/Symbol \047}', '∋'};
+  sym.cong = {'{/Symbol \100}', '≅'};
+  sym.Delta = {'{/Symbol D}', 'Δ'};
+  sym.Phi = {'{/Symbol F}', 'Φ'};
+  sym.Gamma = {'{/Symbol G}', 'Γ'};
+  sym.vartheta = {'{/Symbol J}', 'ϑ'};
+  sym.Lambda = {'{/Symbol L}', 'Λ'};
+  sym.Pi = {'{/Symbol P}', 'Π'};
+  sym.Theta = {'{/Symbol Q}', 'Θ'};
+  sym.Sigma = {'{/Symbol S}', 'Σ'};
+  sym.varsigma = {'{/Symbol V}', 'ς'};
+  sym.Omega = {'{/Symbol W}', 'Ω'};
+  sym.Xi = {'{/Symbol X}', 'Ξ'};
+  sym.Psi = {'{/Symbol Y}', 'Ψ'};
+  sym.perp = {'{/Symbol \136}', '⊥'};
+  sym.alpha = {'{/Symbol a}', 'α'};
+  sym.beta = {'{/Symbol b}', 'β'};
+  sym.chi = {'{/Symbol c}', 'χ'};
+  sym.delta = {'{/Symbol d}', 'δ'};
+  sym.epsilon = {'{/Symbol e}', 'ε'};
+  sym.phi = {'{/Symbol f}', 'ϕ'};
+  sym.gamma = {'{/Symbol g}', 'γ'};
+  sym.eta = {'{/Symbol h}', 'η'};
+  sym.iota = {'{/Symbol i}', 'ι'};
+  sym.varphi = {'{/Symbol j}', 'φ'};              # Not in OpenGL
+  sym.kappa = {'{/Symbol k}', 'κ'};
+  sym.lambda = {'{/Symbol l}', 'λ'};
+  sym.mu = {'{/Symbol m}', 'μ'};
+  sym.nu = {'{/Symbol n}', 'ν'};
+  sym.o = {'{/Symbol o}', 'ο'};
+  sym.pi = {'{/Symbol p}', 'π'};
+  sym.theta = {'{/Symbol q}', 'θ'};
+  sym.rho = {'{/Symbol r}', 'ρ'};
+  sym.sigma = {'{/Symbol s}', 'σ'};
+  sym.tau = {'{/Symbol t}', 'τ'};
+  sym.upsilon = {'{/Symbol u}', 'υ'};
+  sym.varpi = {'{/Symbol v}', 'ϖ'};
+  sym.omega = {'{/Symbol w}', 'ω'};
+  sym.xi = {'{/Symbol x}', 'ξ'};
+  sym.psi = {'{/Symbol y}', 'ψ'};
+  sym.zeta = {'{/Symbol z}', 'ζ'};
+  sym.sim = {'{/Symbol \176}', '∼'};
+  sym.Upsilon = {'{/Symbol \241}', 'Υ'};
+  sym.prime = {'{/Symbol \242}', '′'};
+  sym.leq = {'{/Symbol \243}', '≤'};
+  sym.infty = {'{/Symbol \245}', '∞'};
+  sym.clubsuit = {'{/Symbol \247}', '♣'};
+  sym.diamondsuit = {'{/Symbol \250}', '♢'};
+  sym.heartsuit = {'{/Symbol \251}', '♡'};
+  sym.spadesuit = {'{/Symbol \252}', '♠'};
+  sym.leftrightarrow = {'{/Symbol \253}', '↔'};
+  sym.leftarrow = {'{/Symbol \254}', '←'};
+  sym.uparrow = {'{/Symbol \255}', '↑'};
+  sym.rightarrow = {'{/Symbol \256}', '→'};
+  sym.downarrow = {'{/Symbol \257}', '↓'};
+  sym.circ = {'{/Symbol \260}', '∘'};
+  ## degree symbol, not circ as in FLTK
+  sym.deg = {'{/Symbol \260}', '°'};
+  sym.ast = {'{/Symbol *}', '∗'};
+  sym.pm = {'{/Symbol \261}', '±'};
+  sym.geq = {'{/Symbol \263}', '≥'};
+  sym.times = {'{/Symbol \264}', '×'};
+  sym.propto = {'{/Symbol \265}', '∝'};
+  sym.partial = {'{/Symbol \266}', '∂'};
+  sym.bullet = {'{/Symbol \267}', '∙'};
+  sym.div = {'{/Symbol \270}', '÷'};
+  sym.neq = {'{/Symbol \271}', '≠'};
+  sym.equiv = {'{/Symbol \272}', '≡'};
+  sym.approx = {'{/Symbol \273}', '≈'};
+  sym.ldots = {'{/Symbol \274}', '…'};
+  sym.mid = {'{/Symbol \275}', '∣'};
+  sym.aleph = {'{/Symbol \300}', 'ℵ'};
+  sym.Im = {'{/Symbol \301}', 'ℑ'};
+  sym.Re = {'{/Symbol \302}', 'ℜ'};
+  sym.wp = {'{/Symbol \303}', '℘'};
+  sym.otimes = {'{/Symbol \304}', '⊗'};
+  sym.oplus = {'{/Symbol \305}', '⊕'};
   ## empty set, not circled slash division operator as in FLTK.
-  sym.oslash = '{/Symbol \306}';
-  sym.cap = '{/Symbol \307}';
-  sym.cup = '{/Symbol \310}';
-  sym.supset = '{/Symbol \311}';
-  sym.supseteq = '{/Symbol \312}';
-  sym.subset = '{/Symbol \314}';
-  sym.subseteq = '{/Symbol \315}';
-  sym.in = '{/Symbol \316}';
-  sym.notin = '{/Symbol \317}';            # Not in OpenGL
-  sym.angle = '{/Symbol \320}';
-  sym.bigtriangledown = '{/Symbol \321}';  # Not in OpenGL
-  sym.langle = '{/Symbol \341}';
-  sym.rangle = '{/Symbol \361}';
-  sym.nabla = '{/Symbol \321}';
-  sym.prod = '{/Symbol \325}';             # Not in OpenGL
-  sym.surd = '{/Symbol \326}';
-  sym.cdot = '{/Symbol \327}';
-  sym.neg = '{/Symbol \330}';
-  sym.wedge = '{/Symbol \331}';
-  sym.vee = '{/Symbol \332}';
-  sym.Leftrightarrow = '{/Symbol \333}';   # Not in OpenGL
-  sym.Leftarrow = '{/Symbol \334}';
-  sym.Uparrow = '{/Symbol \335}';          # Not in OpenGL
-  sym.Rightarrow = '{/Symbol \336}';
-  sym.Downarrow = '{/Symbol \337}';        # Not in OpenGL
-  sym.diamond = '{/Symbol \340}';          # Not in OpenGL
-  sym.copyright = '{/Symbol \343}';
-  sym.lfloor = '{/Symbol \353}';
-  sym.lceil = '{/Symbol \351}';
-  sym.rfloor = '{/Symbol \373}';
-  sym.rceil = '{/Symbol \371}';
-  sym.int = '{/Symbol \362}';
+  sym.oslash = {'{/Symbol \306}', '⊘'};
+  sym.emptyset = {'{/Symbol \306}', '∅'};
+  sym.cap = {'{/Symbol \307}', '∩'};
+  sym.cup = {'{/Symbol \310}', '∪'};
+  sym.supset = {'{/Symbol \311}', '⊃'};
+  sym.supseteq = {'{/Symbol \312}', '⊇'};
+  sym.subset = {'{/Symbol \314}', '⊂'};
+  sym.subseteq = {'{/Symbol \315}', '⊑'};
+  sym.in = {'{/Symbol \316}', '∈'};
+  sym.notin = {'{/Symbol \317}', '∋'};            # Not in OpenGL
+  sym.angle = {'{/Symbol \320}', '∠'};
+  sym.bigtriangledown = {'{/Symbol \321}', '▽'};  # Not in OpenGL
+  sym.langle = {'{/Symbol \341}', '〈'};
+  sym.rangle = {'{/Symbol \361}', '〉'};
+  sym.nabla = {'{/Symbol \321}', '∇'};
+  sym.prod = {'{/Symbol \325}', '∏'};             # Not in OpenGL
+  sym.surd = {'{/Symbol \326}', '√'};
+  sym.cdot = {'{/Symbol \327}', '⋅'};
+  sym.neg = {'{/Symbol \330}', '¬'};
+  sym.wedge = {'{/Symbol \331}', '∧'};
+  sym.vee = {'{/Symbol \332}', '∨'};
+  sym.Leftrightarrow = {'{/Symbol \333}', '⇔'};   # Not in OpenGL
+  sym.Leftarrow = {'{/Symbol \334}', '⇐'};
+  sym.Uparrow = {'{/Symbol \335}', '⇑'};          # Not in OpenGL
+  sym.Rightarrow = {'{/Symbol \336}', '⇒'};
+  sym.Downarrow = {'{/Symbol \337}', '⇓'};        # Not in OpenGL
+  sym.diamond = {'{/Symbol \340}', '⋄'};          # Not in OpenGL
+  sym.copyright = {'{/Symbol \343}', '©'};
+  sym.lfloor = {'{/Symbol \353}', '⌊'};
+  sym.lceil = {'{/Symbol \351}', '⌈'};
+  sym.rfloor = {'{/Symbol \373}', '⌋'};
+  sym.rceil = {'{/Symbol \371}', '⌉'};
+  sym.int = {'{/Symbol \362}', '∫'};
+
 endfunction
 
 function retval = __do_enhanced_option__ (enhanced, obj)
@@ -2782,7 +2792,8 @@
 
 function do_text (stream, gpterm, enhanced, obj, hax, screenpos)
 
-  [label, f, s] = __maybe_munge_text__ (enhanced, obj, "string", obj.interpreter);
+  [label, f, s] = __maybe_munge_text__ (enhanced, obj, "string", ...
+                                        obj.interpreter, gpterm);
   fontspec = create_fontspec (f, s, gpterm);
   lpos = obj.position;
   halign = obj.horizontalalignment;
@@ -2840,13 +2851,13 @@
   endif
   fprintf (stream,
            ['set label "%s" at %s %.15e,%.15e%s %s rotate by %f offset character %f,%f %s %s front %s;' "\n"],
-           undo_string_escapes (label), units, lpos(1),
-           lpos(2), zstr, halign, angle, dx_and_dy, fontspec,
-           __do_enhanced_option__ (enhanced, obj), colorspec);
+           label, units, lpos(1), lpos(2), zstr, halign, angle, dx_and_dy,
+           fontspec, __do_enhanced_option__ (enhanced, obj), colorspec);
 
 endfunction
 
 function cdata = mapcdata (cdata, mode, clim, cmap_sz)
+
   if (ndims (cdata) == 3)
     ## True Color, clamp data to 8-bit
     clim = double (clim);
@@ -2877,4 +2888,5 @@
     endif
     cdata = max (1, min (cdata, cmap_sz));
   endif
+
 endfunction
--- a/scripts/plot/util/private/__opengl_print__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/private/__opengl_print__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -100,7 +100,7 @@
         cmd_pstoedit = opts.pstoedit_cmd (opts, "fig", false);
         [~, ~, ext] = fileparts (opts.name);
         if (any (strcmpi (ext, {".ps", ".tex", "."})))
-          opts.name = opts.name(1:end-numel(ext));
+          opts.name = opts.name(1:end-numel (ext));
         endif
         opts.name = [opts.name ".ps"];
         cmd = sprintf ('%s | %s > "%s"', cmd_pstoedit, cmd_fig2dev, opts.name);
@@ -109,7 +109,7 @@
         cmd_fig2dev = opts.fig2dev_cmd (opts, "pstex_t");
         gl2ps_device{2} = "eps";
         pipeline{2} = sprintf ('%s | %s > "%s"', cmd_pstoedit,
-                               cmd_fig2dev, strrep(opts.name, ".ps", ".tex"));
+                               cmd_fig2dev, strrep (opts.name, ".ps", ".tex"));
       else
         ## Using svgconvert
         tmp = tempname ();
--- a/scripts/plot/util/private/__print_parse_opts__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/private/__print_parse_opts__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -250,7 +250,11 @@
     if (opengl_ok && strcmp (graphics_toolkit (arg_st.figure), "qt"))
       ## "opengl" renderer only does text rotations of 0°, 90°, 180°, 270°, ...
       ht = findall (arg_st.figure, "type", "text");
-      angles = [get(ht, "rotation"){:}];
+      if (isempty (ht))
+        angles = [];
+      else
+        angles = [get(ht, "rotation"){:}];
+      endif
       if (any (mod (angles, 90)))
         arg_st.renderer = "painters";
       else
@@ -424,7 +428,7 @@
     if (! (arg_st.send_to_printer || arg_st.formatted_for_printing
            || strncmp (arg_st.devopt, "pdf", 3)
            || strncmp (arg_st.devopt, "ps", 2)))
-      error ("print: the '%s' option is only valid for page formats and printers.", arg_st.resize_flag);
+      error ("print: the '%s' option is only valid for page formats and printers", arg_st.resize_flag);
     endif
   endif
 
--- a/scripts/plot/util/refresh.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/refresh.m	Thu Nov 19 13:08:00 2020 -0800
@@ -35,9 +35,7 @@
 
 function refresh (h)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isfigure (h))
       error ("refresh: H must be a valid figure handle");
     endif
--- a/scripts/plot/util/refreshdata.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/refreshdata.m	Thu Nov 19 13:08:00 2020 -0800
@@ -74,14 +74,12 @@
     endif
     if (nargin == 1)
       workspace = "base";
-    elseif (nargin == 2)
+    else
       if (! ischar (workspace)
           || ! any (strcmpi (workspace, {"base", "caller"})))
         error ('refreshdata: WORKSPACE must be "base" or "caller"');
       endif
       workspace = tolower (workspace);
-    else
-      print_usage ();
     endif
   endif
 
--- a/scripts/plot/util/rotate.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/rotate.m	Thu Nov 19 13:08:00 2020 -0800
@@ -45,7 +45,7 @@
   ## default origin due to possible differences in the auto-scaling
   ## algorithm between Octave and Matlab.
 
-  if (nargin < 3 || nargin > 4)
+  if (nargin < 3)
     print_usage ();
   endif
 
@@ -65,7 +65,7 @@
   endif
 
   if (! (isnumeric (direction) && numel (direction) == 3))
-    error ("rotate: invalid direction");
+    error ("rotate: invalid DIRECTION");
   endif
 
   if (! (isnumeric (alpha) && isscalar (alpha)))
@@ -181,11 +181,12 @@
 %! h2 = figure ("visible", "off");
 %! o2 = line ();
 %! o3 = text (0, 0, "foobar");
-%!error rotate ()
-%!error rotate (o1)
-%!error rotate (o1, [0,0,0])
+
+%!error <Invalid call> rotate ()
+%!error <Invalid call> rotate (o1)
+%!error <Invalid call> rotate (o1, [0,0,0])
 %!error <all handles must be children of the same axes object> rotate ([o1, o2], [0,0,0], 90)
-%!error <invalid direction> rotate (o1, "foo", 90)
+%!error <invalid DIRECTION> rotate (o1, "foo", 90)
 %!error <invalid rotation angle> rotate (o1, [0,0,0], "foo")
 %!error <invalid ORIGIN> rotate (o1, [0,0,0], 90, "foo")
 %!error rotate (o1, [0,0,0], 90, [0,0,0], 1)
--- a/scripts/plot/util/rotate3d.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/rotate3d.m	Thu Nov 19 13:08:00 2020 -0800
@@ -41,35 +41,31 @@
 ## @seealso{pan, zoom}
 ## @end deftypefn
 
-function rotate3d (varargin)
-
-  hfig = NaN;
-
-  nargs = nargin;
+function h = rotate3d (hfig, option)
 
-  if (nargs > 2)
-    print_usage ();
-  endif
-
-  if (nargin == 1 && nargout > 0 && isfigure (varargin{1}))
+  ## FIXME: Presumably should implement this for Matlab compatibility.
+  if (nargin == 1 && nargout > 0 && isfigure (hfig))
     error ("rotate3d: syntax 'handle = rotate3d (hfig)' not implemented");
   endif
 
-  if (nargs == 2)
-    hfig = varargin{1};
-    if (isfigure (hfig))
-      varargin(1) = [];
-      nargs -= 1;
+  if (nargin == 0)
+    hfig = gcf ();
+  else
+    if (nargin == 1)
+      option = hfig;
+      hfig = gcf ();
     else
-      error ("rotate3d: invalid figure handle HFIG");
+      if (! isfigure (hfig))
+        error ("rotate3d: invalid figure handle HFIG");
+      endif
+    endif
+
+    if (! ischar (option))
+      error ("rotate3d: OPTION must be a string");
     endif
   endif
 
-  if (isnan (hfig))
-    hfig = gcf ();
-  endif
-
-  if (nargs == 0)
+  if (nargin == 0)
     rm = get (hfig, "__rotate_mode__");
     if (strcmp (rm.Enable, "on"))
       rm.Enable = "off";
@@ -78,25 +74,17 @@
     endif
     set (hfig, "__rotate_mode__", rm);
     update_mouse_mode (hfig, rm.Enable);
-  elseif (nargs == 1)
-    arg = varargin{1};
-    if (ischar (arg))
-      switch (arg)
-        case {"on", "off"}
-          rm = get (hfig, "__rotate_mode__");
-          switch (arg)
-            case {"on", "off"}
-              rm.Enable = arg;
-              rm.Motion = "both";
-          endswitch
-          set (hfig, "__rotate_mode__", rm);
-          update_mouse_mode (hfig, arg);
-        otherwise
-          error ("rotate3d: unrecognized OPTION '%s'", arg);
-      endswitch
-    else
-      error ("rotate3d: wrong type argument '%s'", class (arg));
-    endif
+  else
+    switch (option)
+      case {"on", "off"}
+        rm = get (hfig, "__rotate_mode__");
+        rm.Enable = option;
+        rm.Motion = "both";
+        set (hfig, "__rotate_mode__", rm);
+        update_mouse_mode (hfig, option);
+      otherwise
+        error ("rotate3d: unrecognized OPTION '%s'", option);
+    endswitch
   endif
 
 endfunction
@@ -106,11 +94,10 @@
   if (strcmp (arg, "off"))
     set (hfig, "__mouse_mode__", "none");
   else
-    ## FIXME: Is there a better way other than calling these
-    ## functions to set the other mouse mode Enable fields to
-    ## "off"?
-    pan ("off");
-    zoom ("off");
+    ## FIXME: Is there a better way other than calling these functions
+    ##        to set the other mouse mode Enable fields to "off"?
+    pan (hfig, "off");
+    zoom (hfig, "off");
     set (hfig, "__mouse_mode__", "rotate");
   endif
 
--- a/scripts/plot/util/saveas.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/saveas.m	Thu Nov 19 13:08:00 2020 -0800
@@ -33,6 +33,14 @@
 ## are:
 ##
 ## @table @code
+##
+##   @item ofig
+##     Octave figure file format (default)
+##
+##   @item mfig
+##     Two files: Octave m-file @file{filename.m} containing code
+##     to open Octave figure file @file{filename.ofig}
+##
 ##   @item ps
 ##     PostScript
 ##
@@ -58,7 +66,7 @@
 ##
 ## If @var{fmt} is omitted it is extracted from the extension of
 ## @var{filename}.  The default format when there is no extension is
-## @qcode{"pdf"}.
+## @qcode{"ofig"}.
 ##
 ## @example
 ## @group
@@ -68,12 +76,12 @@
 ## @end group
 ## @end example
 ##
-## @seealso{print, hgsave, orient}
+## @seealso{print, savefig, hgsave, orient}
 ## @end deftypefn
 
 function saveas (h, filename, fmt)
 
-  if (nargin != 2 && nargin != 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -90,36 +98,60 @@
     fig = ancestor (h, "figure");
   endif
 
+  default_fmt = "ofig";
+
   if (nargin == 2)
     ## Attempt to infer format from filename
     [~, ~, ext] = fileparts (filename);
-    if (! isempty (ext))
-      fmt = ext(2:end);
-    else
-      fmt = "pdf";
+    if (isempty (ext))
+      ext = ["." default_fmt];
+      filename = [filename ext];
     endif
+    fmt = ext(2:end);
   endif
 
   if (nargin == 3)
     if (! ischar (fmt))
       error ("saveas: FMT must be a string");
+    elseif (isempty (fmt))
+      fmt = default_fmt;
     endif
     [~, ~, ext] = fileparts (filename);
     if (isempty (ext))
-      filename = [filename "." fmt];
+      ext = ["." fmt];
+      filename = [filename ext];
     endif
   endif
 
-  prt_opt = ["-d" tolower(fmt)];
+  fmt = tolower (fmt);
+
+  if (any (strcmp (fmt, {"ofig", "fig"})))
+    savefig (fig, filename);
+  elseif (any (strcmp (fmt, {"m", "mfig"})))
+    [d, n] = fileparts (filename);
+    mfilename = fullfile (d, [n ".m"]);
+    figfilename = fullfile (d, [n ".ofig"]);
+
+    savefig (fig, figfilename);
 
-  print (fig, filename, prt_opt);
+    fid = fopen (mfilename, "wt");
+    if (fid < 0)
+      error ("saveas: could not open '%s' for writing", mfilename);
+    endif
+    fprintf (fid, ['h = openfig ("' figfilename '");' "\n"]);
+    fclose (fid);
+  else
+    prt_opt = ["-d" fmt];
+
+    print (fig, filename, prt_opt);
+  endif
 
 endfunction
 
+
 ## Test input validation
-%!error saveas ()
-%!error saveas (1)
-%!error saveas (1,2,3,4)
+%!error <Invalid call> saveas ()
+%!error <Invalid call> saveas (1)
 %!error <H must be a graphics handle> saveas (Inf, "tst.pdf")
 %!error <FILENAME must be a string> saveas (0, 1)
 %!error <FMT must be a string> saveas (0, "tst.pdf", 1)
--- a/scripts/plot/util/struct2hdl.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/struct2hdl.m	Thu Nov 19 13:08:00 2020 -0800
@@ -45,12 +45,16 @@
 
 function [h, pout] = struct2hdl (s, p=[], hilev = false)
 
+  if (nargin < 1)
+    print_usage ();
+  endif
+
   fields = {"handle", "type", "children", "properties", "special"};
   partypes = {"root", "figure", "axes", "hggroup"};
-  othertypes = {"line", "patch", "surface", "image", "text"};
+  othertypes = {"line", "patch", "scatter", "surface", "image", "text"};
   alltypes = [partypes othertypes];
 
-  if (nargin > 3 || ! isstruct (s))
+  if (! isstruct (s))
     print_usage ();
   elseif (! all (isfield (s, fields)))
     print_usage ();
@@ -108,16 +112,22 @@
   ## change the mode to "manual" when the value is "auto".
   names = fieldnames (s.properties);
   n = strncmp (cellfun (@fliplr, names, "uniformoutput", false), "edom", 4);
-  n = (n | strcmp (names, "activepositionproperty"));
+  n = (n | strcmp (names, "positionconstraint"));
   names = [names(! n); names(n)];
   n_pos = find (strcmp (names, "position") | strcmp (names, "outerposition"));
   if (strcmp (s.type, "axes") && numel (n_pos) == 2)
-    if (strcmp (s.properties.activepositionproperty, "position"))
+    if (isfield (s.properties, "positionconstraint"))
+      positionconstraint = s.properties.positionconstraint;
+    else
+      ## loading old figure file before "positionconstraint" property was added
+      positionconstraint = s.properties.activepositionproperty;
+    endif
+    if (strcmp (positionconstraint, "outerposition"))
+      names{n_pos(1)} = "position";
+      names{n_pos(2)} = "outerposition";
+    else
       names{n_pos(1)} = "outerposition";
       names{n_pos(2)} = "position";
-    else
-      names{n_pos(1)} = "position";
-      names{n_pos(2)} = "outerposition";
     endif
   endif
   ## Reorder the properties with the mode properties coming last
@@ -128,7 +138,7 @@
 
   ## Translate field names for Matlab .fig files
   ## FIXME: Is it ok to do this unconditionally?
-  if isfield (s.properties, "applicationdata")
+  if (isfield (s.properties, "applicationdata"))
     s.properties.__appdata__ = s.properties.applicationdata;
     s.properties = rmfield (s.properties, "applicationdata");
   endif
@@ -150,21 +160,29 @@
       if (strcmp (s.properties.tag, "legend"))
         s.properties.tag = "";
         s.properties.userdata = [];
-        par = gcf;
+        par = gcf ();
       elseif (strcmp (s.properties.tag, "colorbar"))
         s.properties.tag = "";
         s.properties.userdata = [];
-        par = gcf;
+        par = gcf ();
       endif
     endif
-    if (isfield (s.properties, "tightinset"))
-      s.properties = rmfield (s.properties, {"tightinset"});
+    ## remove read only properties
+    ## FIXME: Remove "interactions", "layout", "legend", "toolbar", "xaxis",
+    ## "yaxis", and "zaxis" from this list once they are implemented.
+    ro_props = {"interactions", "layout", "legend", "nextseriesindex", ...
+                "tightinset", "toolbar", "xaxis", "yaxis", "zaxis"};
+    has_ro_props = cellfun (@(x) isfield (s.properties, x), ro_props);
+    if (any (has_ro_props))
+      s.properties = rmfield (s.properties, ro_props(has_ro_props));
     endif
     [h, s] = createaxes (s, p, par);
   elseif (strcmp (s.type, "line"))
     h = createline (s, par);
   elseif (strcmp (s.type, "patch"))
     [h, s] = createpatch (s, par);
+  elseif (strcmp (s.type, "scatter"))
+    [h, s] = createscatter (s, par);
   elseif (strcmp (s.type, "text"))
     if (isfield (s.properties, "extent"))
       s.properties = rmfield (s.properties, "extent");
@@ -180,7 +198,8 @@
     [h, s, p] = createhg (s, p, par, hilev);
   elseif (any (strcmp (s.type, {"uimenu", "uicontextmenu",...
                                 "uicontrol", "uipanel", "uibuttongroup",...
-                                "uitoolbar", "uipushtool", "uitable"})))
+                                "uitoolbar", "uipushtool", "uitoggletool"...
+                                "uitable"})))
     if (isfield (s.properties, "extent"))
       s.properties = rmfield (s.properties, "extent");
     endif
@@ -213,6 +232,7 @@
 endfunction
 
 function [h, sout] = createfigure (s)
+
   ## Create figure initially invisible to speed up loading.
   opts = {"visible", "off"};
   if (isfield (s.properties, "integerhandle"))  # see also bug #53342.
@@ -229,6 +249,7 @@
   endif
   addmissingprops (h, s.properties);
   sout = s;
+
 endfunction
 
 function [h, sout] = createaxes (s, p, par)
@@ -368,6 +389,24 @@
 
 endfunction
 
+function [h, sout] = createscatter (s, par)
+
+  if (isempty (s.properties.zdata))
+    ## 2D scatter
+    h = scatter (s.properties.xdata, s.properties.ydata);
+  else
+    ## 3D scatter
+    h = scatter3 (s.properties.xdata, s.properties.ydata, s.properties.zdata);
+  endif
+
+  set (h, "parent", par);
+  s.properties = rmfield (s.properties,
+                          {"xdata", "ydata", "zdata"});
+  addmissingprops (h, s.properties);
+  sout = s;
+
+endfunction
+
 function h = createtext (s, par)
   h = text ("parent", par);
   addmissingprops (h, s.properties);
--- a/scripts/plot/util/subplot.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/subplot.m	Thu Nov 19 13:08:00 2020 -0800
@@ -238,7 +238,7 @@
     set (cf, "units", "pixels");
 
     ## FIXME: At the moment we force gnuplot to use the aligned mode
-    ##        which will set "activepositionproperty" to "position".
+    ##        which will set "positionconstraint" to "innerposition".
     ##        This can yield to text overlap between labels and titles.
     ##        See bug #31610.
     if (strcmp (get (cf, "__graphics_toolkit__"), "gnuplot"))
@@ -328,7 +328,7 @@
         set (hsubplot, varargin{:});
       endif
     else
-      pval = [{"activepositionproperty", "position", ...
+      pval = [{"positionconstraint", "innerposition", ...
                "position", pos, "looseinset", li} varargin];
       if (! make_subplot)
         hsubplot = axes (pval{:});
@@ -434,7 +434,7 @@
 
 endfunction
 
-function subplot_align (h, d, rmupdate = false)
+function subplot_align (h, ~, rmupdate = false)
   persistent updating = false;
 
   if (! updating)
@@ -445,7 +445,7 @@
         rmappdata (h, "__subplotposition__");
         rmappdata (h, "__subplotouterposition__");
       endif
-      return
+      return;
     endif
 
     unwind_protect
@@ -460,7 +460,7 @@
         do_align = ! cellfun (@isempty, pos);
         pos = cell2mat (pos(do_align));
       else
-        return
+        return;
       endif
       hsubplots = children(do_align);
 
@@ -475,7 +475,7 @@
         hsubplots(! do_align) = [];
         pos(! do_align,:) = [];
       else
-        return
+        return;
       endif
 
       ## Reset outerpositions to their default value
@@ -485,7 +485,7 @@
       endif
       for ii = 1:numel (hsubplots)
         set (hsubplots(ii), "outerposition", opos(ii,:), ...
-             "activepositionproperty", "position");
+             "positionconstraint", "innerposition");
       endfor
 
       ## Compare current positions to default and compute the new ones
--- a/scripts/plot/util/zoom.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/plot/util/zoom.m	Thu Nov 19 13:08:00 2020 -0800
@@ -64,33 +64,27 @@
 ## Eventually we need to also support these features:
 ## @deftypefnx {} {zoom_object_handle =} zoom (@var{hfig})
 
-function zoom (varargin)
+function h = zoom (hfig, option)
 
-  nargs = nargin;
-  if (nargs > 2)
-    print_usage ();
-  endif
-
-  if (nargs == 1 && nargout > 0 && isfigure (varargin{1}))
+  ## FIXME: Presumably should implement this for Matlab compatibility.
+  if (nargin == 1 && nargout > 0 && isfigure (hfig))
     error ("zoom: syntax 'handle = zoom (hfig)' not implemented");
   endif
 
-  hfig = NaN;
-  if (nargs == 2)
-    hfig = varargin{1};
-    if (isfigure (hfig))
-      varargin(1) = [];
-      nargs -= 1;
+  if (nargin == 0)
+    hfig = gcf ();
+  else
+    if (nargin == 1)
+      option = hfig;
+      hfig = gcf ();
     else
-      error ("zoom: invalid figure handle HFIG");
+      if (! isfigure (hfig))
+        error ("zoom: invalid figure handle HFIG");
+      endif
     endif
   endif
 
-  if (isnan (hfig))
-    hfig = gcf ();
-  endif
-
-  if (nargs == 0)
+  if (nargin == 0)
     zm = get (hfig, "__zoom_mode__");
     if (strcmp (zm.Enable, "on"))
       zm.Enable = "off";
@@ -99,10 +93,9 @@
     endif
     set (hfig, "__zoom_mode__", zm);
     update_mouse_mode (hfig, zm.Enable);
-  elseif (nargs == 1)
-    arg = varargin{1};
-    if (isnumeric (arg))
-      factor = arg;
+  else
+    if (isnumeric (option))
+      factor = option;
       switch (numel (factor))
         case 2
           xfactor = factor(1);
@@ -110,10 +103,10 @@
         case 1
           xfactor = yfactor = factor;
         otherwise
-          error ("zoom: invalid FACTOR");
+          error ("zoom: FACTOR must be a 1- or 2-element vector");
       endswitch
-      if (xfactor < 0 || yfactor < 0)
-        error ("zoom: FACTOR must be greater than 1");
+      if (xfactor <= 0 || yfactor <= 0)
+        error ("zoom: FACTOR must be greater than 0");
       elseif (xfactor == 1 && yfactor == 1)
         return;
       endif
@@ -132,13 +125,13 @@
         endif
         __zoom__ (cax, mode, factor);
       endif
-    elseif (ischar (arg))
-      switch (arg)
+    elseif (ischar (option))
+      switch (option)
         case {"on", "off", "xon", "yon"}
           zm = get (hfig, "__zoom_mode__");
-          switch (arg)
+          switch (option)
             case {"on", "off"}
-              zm.Enable = arg;
+              zm.Enable = option;
               zm.Motion = "both";
             case "xon"
               zm.Enable = "on";
@@ -148,7 +141,7 @@
               zm.Motion = "vertical";
           endswitch
           set (hfig, "__zoom_mode__", zm);
-          update_mouse_mode (hfig, arg);
+          update_mouse_mode (hfig, option);
         case "out"
           cax = get (hfig, "currentaxes");
           if (! isempty (cax))
@@ -160,10 +153,10 @@
             __zoom__ (cax, "reset");
           endif
         otherwise
-          error ("zoom: unrecognized OPTION '%s'", arg);
+          error ("zoom: unrecognized OPTION '%s'", option);
       endswitch
     else
-      error ("zoom: wrong type argument '%s'", class (arg));
+      error ("zoom: OPTION must be a number or a string");
     endif
   endif
 
@@ -176,8 +169,8 @@
   else
     ## FIXME: Is there a better way other than calling these functions
     ##        to set the other mouse mode Enable fields to "off"?
-    pan ("off");
-    rotate3d ("off");
+    pan (hfig, "off");
+    rotate3d (hfig, "off");
     set (hfig, "__mouse_mode__", "zoom");
   endif
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/polynomial/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/polynomial/compan.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/polynomial/compan.m	Thu Nov 19 13:08:00 2020 -0800
@@ -63,7 +63,7 @@
 
 function A = compan (c)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/polynomial/conv.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/polynomial/conv.m	Thu Nov 19 13:08:00 2020 -0800
@@ -54,7 +54,7 @@
 
 function y = conv (a, b, shape = "full")
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -128,8 +128,7 @@
 
 
 ## Test input validation
-%!error conv (1)
-%!error conv (1,2,3,4)
+%!error <Invalid call> conv (1)
 %!error <A and B must be vectors> conv ([1, 2; 3, 4], 3)
 %!error <A and B must be vectors> conv (3, [1, 2; 3, 4])
 %!error <SHAPE argument must be> conv (2, 3, "INVALID_SHAPE")
--- a/scripts/polynomial/deconv.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/polynomial/deconv.m	Thu Nov 19 13:08:00 2020 -0800
@@ -80,6 +80,7 @@
 
 endfunction
 
+
 %!test
 %! [b, r] = deconv ([3, 6, 9, 9], [1, 2, 3]);
 %! assert (b, [3, 0]);
@@ -117,22 +118,22 @@
 %! y = (10:-1:1);
 %! a = (4:-1:1);
 %! [b, r] = deconv (y, a);
-%! assert (conv (a, b) + r, y, eps)
+%! assert (conv (a, b) + r, y, eps);
 
 %!test <*51221>
 %! a = [1.92306958582241e+15, 3.20449986572221e+24, 1.34271290136344e+32, ...
 %!     2.32739765751038e+38];
 %! b = [7.33727670161595e+27, 1.05919311870816e+36, 4.56169848520627e+42];
 %! [div, rem] = deconv (a, b);
-%! assert (rem, [0, 0, -2.89443678763879e+32  -1.58695290534499e+39], -10*eps)
+%! assert (rem, [0, 0, -2.89443678763879e+32  -1.58695290534499e+39], -10*eps);
 %! a(2) = 3.204499865722215e+24;
 %! [div, rem] = deconv (a, b);
-%! assert (rem, [0, 0, -2.89443678763879e+32  -1.58695290534499e+39], -10*eps)
+%! assert (rem, [0, 0, -2.89443678763879e+32  -1.58695290534499e+39], -10*eps);
 
 %!test
 %! [b, r] = deconv ([1, 1], 1);
-%! assert (r, [0, 0])
+%! assert (r, [0, 0]);
 
 %!test
 %! [b, r] = deconv ([1; 1], 1);
-%! assert (r, [0; 0])
+%! assert (r, [0; 0]);
--- a/scripts/polynomial/mkpp.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/polynomial/mkpp.m	Thu Nov 19 13:08:00 2020 -0800
@@ -56,30 +56,26 @@
 ## @seealso{unmkpp, ppval, spline, pchip, ppder, ppint, ppjumps}
 ## @end deftypefn
 
-function pp = mkpp (x, P, d)
+function pp = mkpp (breaks, coefs, d)
 
-  ## check number of arguments
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
-  ## check x
-  if (length (x) < 2)
-    error ("mkpp: at least one interval is needed");
-  endif
-
-  if (! isvector (x))
-    error ("mkpp: x must be a vector");
+  ## Check BREAKS
+  if (! isvector (breaks))
+    error ("mkpp: BREAKS must be a vector");
+  elseif (length (breaks) < 2)
+    error ("mkpp: BREAKS must have at least one interval");
   endif
 
-  len = length (x) - 1;
-  dP = length (size (P));
+  len = length (breaks) - 1;
 
   pp = struct ("form", "pp",
-               "breaks", x(:).',
+               "breaks", breaks(:).',
                "coefs", [],
                "pieces", len,
-               "order", prod (size (P)) / len,
+               "order", prod (size (coefs)) / len,
                "dim", 1);
 
   if (nargin == 3)
@@ -88,7 +84,7 @@
   endif
 
   dim_vec = [pp.pieces * prod(pp.dim), pp.order];
-  pp.coefs = reshape (P, dim_vec);
+  pp.coefs = reshape (coefs, dim_vec);
 
 endfunction
 
--- a/scripts/polynomial/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/polynomial/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -6,6 +6,7 @@
   %reldir%/private/__splinefit__.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/compan.m \
   %reldir%/conv.m \
   %reldir%/deconv.m \
--- a/scripts/polynomial/mpoles.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/polynomial/mpoles.m	Thu Nov 19 13:08:00 2020 -0800
@@ -57,7 +57,7 @@
 
 function [multp, indx] = mpoles (p, tol, reorder)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/polynomial/padecoef.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/polynomial/padecoef.m	Thu Nov 19 13:08:00 2020 -0800
@@ -91,7 +91,7 @@
 
 function [num, den] = padecoef (T, N = 1)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -163,7 +163,7 @@
 %! x = A \ b';
 %! k = N : -1 : 0;
 %! d_exp = [flipud(x(N + 2 : 2 * N + 1)); 1]';
-%! n_exp = flipud(x(1 : N + 1))';
+%! n_exp = flipud (x(1 : N + 1))';
 %! n_exp ./= d_exp(1);
 %! d_exp ./= d_exp(1);
 %! [n_obs, d_obs] = padecoef (T, N);
@@ -173,8 +173,7 @@
 ## PadeApproximant[Exp[-x * T], {x, 0, {n, n}}]
 
 ## Test input validation
-%!error padecoef ()
-%!error padecoef (1,2,3)
+%!error <Invalid call> padecoef ()
 %!error <T must be a non-negative scalar> padecoef ([1,2])
 %!error <T must be a non-negative scalar> padecoef ({1})
 %!error <T must be a non-negative scalar> padecoef (-1)
--- a/scripts/polynomial/pchip.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/polynomial/pchip.m	Thu Nov 19 13:08:00 2020 -0800
@@ -75,7 +75,7 @@
 
 function ret = pchip (x, y, xi)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -177,5 +177,5 @@
 %!assert (size (yi2), [3,2,5,4])
 %!assert (squeeze (yi2(1,2,3,:)), [1/sqrt(2); 0; -1/sqrt(2);-1], 1e-14)
 
-%!error (pchip (1,2))
-%!error (pchip (1,2,3))
+%!error pchip (1,2)
+%!error pchip (1,2,3)
--- a/scripts/polynomial/poly.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/polynomial/poly.m	Thu Nov 19 13:08:00 2020 -0800
@@ -57,7 +57,7 @@
 
 function y = poly (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -112,6 +112,5 @@
 %! y = poly (x);
 %! assert (y, [1 + 0i, -9 - 3i, 25 + 24i, -17 - 57i, -12 + 36i]);
 
-%!error poly ()
-%!error poly (1,2)
+%!error <Invalid call> poly ()
 %!error poly ([1, 2, 3; 4, 5, 6])
--- a/scripts/polynomial/polyder.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/polynomial/polyder.m	Thu Nov 19 13:08:00 2020 -0800
@@ -41,57 +41,57 @@
 
 function [q, d] = polyder (p, a)
 
-  if (nargin == 1 || nargin == 2)
-    if (! isvector (p))
+  if (nargin < 1)
+    print_usage ();
+  endif
+
+  if (! isvector (p))
+    error ("polyder: argument must be a vector");
+  endif
+  if (nargin == 2)
+    if (! isvector (a))
       error ("polyder: argument must be a vector");
     endif
-    if (nargin == 2)
-      if (! isvector (a))
-        error ("polyder: argument must be a vector");
-      endif
-      if (nargout == 1)
-        ## derivative of p*a returns a single polynomial
-        q = polyder (conv (p, a));
+    if (nargout == 1)
+      ## derivative of p*a returns a single polynomial
+      q = polyder (conv (p, a));
+    else
+      ## derivative of p/a returns numerator and denominator
+      d = conv (a, a);
+      if (numel (p) == 1)
+        q = -p * polyder (a);
+      elseif (numel (a) == 1)
+        q = a * polyder (p);
       else
-        ## derivative of p/a returns numerator and denominator
-        d = conv (a, a);
-        if (numel (p) == 1)
-          q = -p * polyder (a);
-        elseif (numel (a) == 1)
-          q = a * polyder (p);
-        else
-          q = conv (polyder (p), a) - conv (p, polyder (a));
-          q = polyreduce (q);
-        endif
-
-        ## remove common factors from numerator and denominator
-        x = polygcd (q, d);
-        if (length (x) != 1)
-          q = deconv (q, x);
-          d = deconv (d, x);
-        endif
-
-        ## move all the gain into the numerator
-        q /= d(1);
-        d /= d(1);
-      endif
-    else
-      lp = numel (p);
-      if (lp == 1)
-        q = 0;
-        return;
-      elseif (lp == 0)
-        q = [];
-        return;
+        q = conv (polyder (p), a) - conv (p, polyder (a));
+        q = polyreduce (q);
       endif
 
-      ## Force P to be a row vector.
-      p = p(:).';
+      ## remove common factors from numerator and denominator
+      x = polygcd (q, d);
+      if (length (x) != 1)
+        q = deconv (q, x);
+        d = deconv (d, x);
+      endif
 
-      q = p(1:(lp-1)) .* [(lp-1):-1:1];
+      ## move all the gain into the numerator
+      q /= d(1);
+      d /= d(1);
     endif
   else
-    print_usage ();
+    lp = numel (p);
+    if (lp == 1)
+      q = 0;
+      return;
+    elseif (lp == 0)
+      q = [];
+      return;
+    endif
+
+    ## Force P to be a row vector.
+    p = p(:).';
+
+    q = p(1:(lp-1)) .* [(lp-1):-1:1];
   endif
 
 endfunction
--- a/scripts/polynomial/polyeig.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/polynomial/polyeig.m	Thu Nov 19 13:08:00 2020 -0800
@@ -49,7 +49,7 @@
 
 function [z, v] = polyeig (varargin)
 
-  if (nargin < 1 || nargout > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -105,8 +105,7 @@
 %! assert (norm (d), 0.0);
 
 ## Test input validation
-%!error polyeig ()
-%!error [a,b,c] = polyeig (1)
+%!error <Invalid call> polyeig ()
 %!error <coefficients must be square matrices> polyeig (ones (3,2))
 %!error <coefficients must have the same dimensions>
 %! polyeig (ones (3,3), ones (2,2))
--- a/scripts/polynomial/polyfit.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/polynomial/polyfit.m	Thu Nov 19 13:08:00 2020 -0800
@@ -27,25 +27,33 @@
 ## @deftypefn  {} {@var{p} =} polyfit (@var{x}, @var{y}, @var{n})
 ## @deftypefnx {} {[@var{p}, @var{s}] =} polyfit (@var{x}, @var{y}, @var{n})
 ## @deftypefnx {} {[@var{p}, @var{s}, @var{mu}] =} polyfit (@var{x}, @var{y}, @var{n})
-## Return the coefficients of a polynomial @var{p}(@var{x}) of degree
-## @var{n} that minimizes the least-squares-error of the fit to the points
-## @code{[@var{x}, @var{y}]}.
+## Return the coefficients of a polynomial @var{p}(@var{x}) of degree @var{n}
+## that minimizes the least-squares-error of the fit to the points
+## @code{[@var{x}(:), @var{y}(:)]}.
 ##
-## If @var{n} is a logical vector, it is used as a mask to selectively force
-## the corresponding polynomial coefficients to be used or ignored.
+## @var{n} is typically an integer @geq{} 0 specifying the degree of the
+## approximating polynomial.  If @var{n} is a logical vector, it is used as a
+## mask to selectively force the corresponding polynomial coefficients to be
+## used or ignored.
 ##
-## The polynomial coefficients are returned in a row vector.
+## The polynomial coefficients are returned in the row vector @var{p}.  The
+## output @var{p} may be directly used with @code{polyval} to estimate values
+## using the fitted polynomial.
 ##
 ## The optional output @var{s} is a structure containing the following fields:
 ##
 ## @table @samp
-## @item R
-## Triangular factor R from the QR@tie{}decomposition.
+##
+## @item yf
+## The values of the polynomial for each value of @var{x}.
 ##
 ## @item X
 ## The @nospell{Vandermonde} matrix used to compute the polynomial
 ## coefficients.
 ##
+## @item R
+## Triangular factor R from the QR@tie{}decomposition.
+##
 ## @item C
 ## The unscaled covariance matrix, formally equal to the inverse of
 ## @var{x'}*@var{x}, but computed in a way minimizing roundoff error
@@ -56,121 +64,158 @@
 ##
 ## @item normr
 ## The norm of the residuals.
-##
-## @item yf
-## The values of the polynomial for each value of @var{x}.
 ## @end table
 ##
-## The second output may be used by @code{polyval} to calculate the
-## statistical error limits of the predicted values.  In particular, the
-## standard deviation of @var{p} coefficients is given by
+## The second output may be used by @code{polyval} to calculate the statistical
+## error limits of the predicted values.  In particular, the standard deviation
+## of @var{p} coefficients is given by
 ##
-## @code{sqrt (diag (s.C)/s.df)*s.normr}.
+## @code{sqrt (diag (@var{s.C})/@var{s.df}) * @var{s.normr}}.
 ##
-## When the third output, @var{mu}, is present the coefficients, @var{p}, are
-## associated with a polynomial in
+## When the third output, @var{mu}, is present the original data is centered
+## and scaled which can improve the numerical stability of the fit.  The
+## coefficients @var{p} are associated with a polynomial in
 ##
 ## @code{@var{xhat} = (@var{x} - @var{mu}(1)) / @var{mu}(2)} @*
 ## where @var{mu}(1) = mean (@var{x}), and @var{mu}(2) = std (@var{x}).
 ##
-## This linear transformation of @var{x} improves the numerical stability of
-## the fit.
+## Example 1 : logical @var{n} and integer @var{n}
+##
+## @example
+## @group
+## f = @@(x) x.^2 + 5;   # data-generating function
+## x = 0:5;
+## y = f (x);
+## ## Fit data to polynomial A*x^3 + B*x^1
+## p = polyfit (x, y, logical ([1, 0, 1, 0]))
+## @result{} p = [ 0.0680, 0, 4.2444, 0 ]
+## ## Fit data to polynomial using all terms up to x^3
+## p = polyfit (x, y, 3)
+## @result{} p = [ -4.9608e-17, 1.0000e+00, -3.3813e-15, 5.0000e+00 ]
+## @end group
+## @end example
+##
 ## @seealso{polyval, polyaffine, roots, vander, zscore}
 ## @end deftypefn
 
 function [p, s, mu] = polyfit (x, y, n)
 
-  if (nargin < 3 || nargin > 4)
+  if (nargin < 3)
     print_usage ();
   endif
 
+  y_is_row_vector = isrow (y);
+
+  ## Reshape x & y into column vectors.
+  x = x(:);
+  y = y(:);
+
+  nx = numel (x);
+  ny = numel (y);
+  if (nx != ny)
+    error ("polyfit: X and Y must have the same number of points");
+  endif
+
   if (nargout > 2)
-    ## Normalized the x values.
+    ## Center and scale the x values.
     mu = [mean(x), std(x)];
     x = (x - mu(1)) / mu(2);
   endif
 
-  if (! size_equal (x, y))
-    error ("polyfit: X and Y must be vectors of the same size");
-  endif
-
+  ## n is the polynomial degree (an input, or deduced from the polymask size)
+  ## m is the effective number of coefficients.
   if (islogical (n))
-    polymask = n;
-    ## n is the polynomial degree as given the polymask size; m is the
-    ## effective number of used coefficients.
-    n = length (polymask) - 1; m = sum (polymask) - 1;
+    polymask = n(:).';          # force to row vector
+    n = numel (polymask) - 1;
+    m = sum (polymask) - 1;
+    pad_output = true;
   else
     if (! (isscalar (n) && n >= 0 && ! isinf (n) && n == fix (n)))
       error ("polyfit: N must be a non-negative integer");
     endif
-    polymask = logical (ones (1, n+1)); m = n;
+    polymask = true (1, n+1);
+    m = n;
+    pad_output = false;
   endif
 
-  y_is_row_vector = (rows (y) == 1);
-
-  ## Reshape x & y into column vectors.
-  l = numel (x);
-  x = x(:);
-  y = y(:);
+  if (m >= nx)
+    warning ("polyfit: degree of polynomial N is >= number of data points; solution is not unique");
+    m = nx;
+    pad_output = true;
+    ## Keep the lowest m entries in polymask
+    idx = find (polymask);
+    idx((end-m+1):end) = [];
+    polymask(idx) = false;
+  endif
 
   ## Construct the Vandermonde matrix.
-  v = vander (x, n+1);
+  X = vander (x, n+1);
+  v = X(:, polymask);
 
   ## Solve by QR decomposition.
-  [q, r, k] = qr (v(:, polymask), 0);
+  [q, r, k] = qr (v, 0);
   p = r \ (q' * y);
   p(k) = p;
 
-  if (n != m)
-    q = p; p = zeros (n+1, 1);
-    p(polymask) = q;
-  endif
-
-  if (nargout > 1)
+  if (isargout (2))
     yf = v*p;
-
     if (y_is_row_vector)
       s.yf = yf.';
     else
       s.yf = yf;
     endif
-    s.X = v;
+
+    s.X = X;
 
-    ## r.'*r is positive definite if X(:, polymask) is of full rank.
-    ## Invert it by cholinv to avoid taking the square root of squared
-    ## quantities.  If cholinv fails, then X(:, polymask) is rank deficient
-    ## and not invertible.
+    ## r.'*r is positive definite if matrix v is of full rank.  Invert it by
+    ## cholinv to avoid taking the square root of squared quantities.
+    ## If cholinv fails, then v is rank deficient and not invertible.
     try
       C = cholinv (r.'*r)(k, k);
     catch
-      C = NaN (m+1, m+1);
+      C = NaN (m, m);
     end_try_catch
 
-    if (n != m)
-      ## fill matrices if required
+    if (pad_output)
       s.X(:, ! polymask) = 0;
-      s.R = zeros (n+1, n+1); s.R(polymask, polymask) = r;
-      s.C = zeros (n+1, n+1); s.C(polymask, polymask) = C;
+      s.R = zeros (rows (r), n+1); s.R(:, polymask) = r;
+      s.C = zeros (rows (C), n+1); s.C(:, polymask) = C;
     else
       s.R = r;
       s.C = C;
     endif
-    s.df = l - m - 1;
+
+    s.df = max (0, nx - m - 1);
     s.normr = norm (yf - y);
   endif
 
-  ## Return a row vector.
-  p = p.';
+  if (pad_output)
+    ## Zero pad output
+    q = p;
+    p = zeros (n+1, 1);
+    p(polymask) = q;
+  endif
+  p = p.';  # Return a row vector.
 
 endfunction
 
 
 %!shared x
 %! x = [-2, -1, 0, 1, 2];
-%!assert (polyfit (x, x.^2+x+1, 2), [1, 1, 1], sqrt (eps))
-%!assert (polyfit (x, x.^2+x+1, 3), [0, 1, 1, 1], sqrt (eps))
-%!fail ("polyfit (x, x.^2+x+1)")
-%!fail ("polyfit (x, x.^2+x+1, [])")
+
+%!assert (polyfit (x, 3*x.^2 + 2*x + 1, 2), [3, 2, 1], 10*eps)
+%!assert (polyfit (x, 3*x.^2 + 2*x + 1, logical ([1 1 1])), [3, 2, 1], 10*eps)
+%!assert (polyfit (x, x.^2 + 2*x + 3, 3), [0, 1, 2, 3], 10*eps)
+%!assert (polyfit (x, x.^2 + 2*x + 3, logical ([0 1 1 1])), [0 1 2 3], 10*eps)
+
+## Test logical input N
+%!test
+%! x = [0:5];
+%! y = 3*x.^3 + 2*x.^2 + 4;
+%! [p, s] = polyfit (x, y, logical ([1, 0, 1, 1]));
+%! assert (p(2), 0);
+%! assert (all (p([1, 3, 4])));
+%! assert (s.df, 3);
 
 ## Test difficult case where scaling is really needed.  This example
 ## demonstrates the rather poor result which occurs when the dependent
@@ -188,25 +233,29 @@
 %! assert (s2.normr < s1.normr);
 
 %!test
-%! x = 1:4;
-%! p0 = [1i, 0, 2i, 4];
-%! y0 = polyval (p0, x);
-%! p = polyfit (x, y0, numel (p0) - 1);
-%! assert (p, p0, 1000*eps);
-
-%!test
 %! warning ("off", "Octave:nearly-singular-matrix", "local");
 %! x = 1000 + (-5:5);
 %! xn = (x - mean (x)) / std (x);
 %! pn = ones (1,5);
 %! y = polyval (pn, xn);
-%! [p, s, mu] = polyfit (x, y, numel (pn) - 1);
-%! [p2, s2] = polyfit (x, y, numel (pn) - 1);
+%! n = numel (pn) - 1;
+%! [p, s, mu] = polyfit (x, y, n);
+%! [p2, s2] = polyfit (x, y, n);
 %! assert (p, pn, s.normr);
 %! assert (s.yf, y, s.normr);
 %! assert (mu, [mean(x), std(x)]);
 %! assert (s.normr/s2.normr < sqrt (eps));
 
+## Complex polynomials
+%!test
+%! x = 1:4;
+%! p0 = [1i, 0, 2i, 4];
+%! y = polyval (p0, x);
+%! n = numel (p0) - 1;
+%! p = polyfit (x, y, n);
+%! assert (p, p0, 1000*eps);
+
+## Matrix input
 %!test
 %! x = [1, 2, 3; 4, 5, 6];
 %! y = [0, 0, 1; 1, 0, 0];
@@ -214,4 +263,88 @@
 %! expected = [0, 1, -14, 65, -112, 60] / 12;
 %! assert (p, expected, sqrt (eps));
 
-%!error <vectors of the same size> polyfit ([1, 2; 3, 4], [1, 2, 3, 4], 2)
+## Orientation of output
+%!test
+%! x = 0:5;
+%! y = x.^4 + 2*x + 5;
+%! [p, s] = polyfit (x, y, 3);
+%! assert (isrow (s.yf));
+%! [p, s] = polyfit (x, y.', 3);
+%! assert (iscolumn (s.yf));
+
+## Insufficient data for fit
+%!test
+%! x = [1, 2];
+%! y = [3, 4];
+%! ## Disable warnings entirely because there is not a specific ID to disable.
+%! wstate = warning ();
+%! unwind_protect
+%!   warning ("off", "all");
+%!   p0 = polyfit (x, y, 4);
+%!   [p1, s, mu] = polyfit (x, y, 4);
+%! unwind_protect_cleanup
+%!   warning (wstate);
+%! end_unwind_protect
+%! assert (p0, [0, 0, 0, 1, 2], 10*eps);
+%! assert (p1, [0, 0, 0, sqrt(2)/2, 3.5], 10*eps);
+%! assert (size (s.X), [2, 5]);
+%! assert (s.X(:,1:3), zeros (2,3));
+%! assert (size (s.R), [2, 5]);
+%! assert (s.R(:,1:3), zeros (2,3));
+%! assert (size (s.C), [2, 5]);
+%! assert (s.C(:,1:3), zeros (2,3));
+%! assert (s.df, 0);
+%! assert (mu, [1.5, sqrt(2)/2]);
+
+%!test
+%! x = [1, 2, 3];
+%! y = 2*x + 1;
+%! ## Disable warnings entirely because there is not a specific ID to disable.
+%! wstate = warning ();
+%! unwind_protect
+%!   warning ("off", "all");
+%!   p0 = polyfit (x, y, logical ([1, 1, 1, 0 1]));
+%!   [p1, s, mu] = polyfit (x, y, logical ([1, 1, 1, 0 1]));
+%! unwind_protect_cleanup
+%!   warning (wstate);
+%! end_unwind_protect
+%! assert (p0, [0, -2/11, 12/11, 0, 23/11], 10*eps);
+%! assert (p1, [0, 2, 0, 0, 5], 10*eps);
+%! assert (size (s.X), [3, 5]);
+%! assert (s.X(:,[1,4]), zeros (3,2));
+%! assert (size (s.R), [3, 5]);
+%! assert (s.R(:,[1,4]), zeros (3,2));
+%! assert (size (s.C), [3, 5]);
+%! assert (s.C(:,[1,4]), zeros (3,2));
+%! assert (s.df, 0);
+%! assert (mu, [2, 1]);
+
+%!test <*57964>
+%! ## Disable warnings entirely because there is not a specific ID to disable.
+%! wstate = warning ();
+%! unwind_protect
+%!   warning ("off", "all");
+%!   [p, s] = polyfit ([1,2], [3,4], 2);
+%! unwind_protect_cleanup
+%!   warning (wstate);
+%! end_unwind_protect
+%! assert (size (p), [1, 3]);
+%! assert (size (s.X), [2, 3]);
+%! assert (s.X(:,1), [0; 0]);
+%! assert (size (s.R), [2, 3]);
+%! assert (s.R(:,1), [0; 0]);
+%! assert (size (s.C), [2, 3]);
+%! assert (s.C(:,1), [0; 0]);
+
+## Test input validation
+%!error <Invalid call> polyfit ()
+%!error <Invalid call> polyfit (1)
+%!error <Invalid call> polyfit (1,2)
+%!error <X and Y must have the same number of points> polyfit ([1, 2], 1, 1)
+%!error <X and Y must have the same number of points> polyfit (1, [1, 2], 1)
+%!error <N must be a non-negative integer> polyfit (1, 2, [1,2])
+%!error <N must be a non-negative integer> polyfit (1, 2, -1)
+%!error <N must be a non-negative integer> polyfit (1, 2, Inf)
+%!error <N must be a non-negative integer> polyfit (1, 2, 1.5)
+%!test <*57964>
+%! fail ("p = polyfit ([1,2], [3,4], 4)", "warning", "solution is not unique");
--- a/scripts/polynomial/polygcd.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/polynomial/polygcd.m	Thu Nov 19 13:08:00 2020 -0800
@@ -53,39 +53,42 @@
 
 function x = polygcd (b, a, tol)
 
-  if (nargin == 2 || nargin == 3)
-    if (nargin == 2)
-      if (isa (a, "single") || isa (b, "single"))
-        tol = sqrt (eps ("single"));
-      else
-        tol = sqrt (eps);
-      endif
+  if (nargin < 2)
+    print_usage ();
+  endif
+
+  if (nargin == 2)
+    if (isa (a, "single") || isa (b, "single"))
+      tol = sqrt (eps ("single"));
+    else
+      tol = sqrt (eps);
     endif
-    if (length (a) == 1 || length (b) == 1)
-      if (a == 0)
-        x = b;
-      elseif (b == 0)
-        x = a;
-      else
-        x = 1;
-      endif
+  endif
+  ## FIXME: No input validation of tol if it was user-supplied
+
+
+  if (length (a) == 1 || length (b) == 1)
+    if (a == 0)
+      x = b;
+    elseif (b == 0)
+      x = a;
     else
-      a /= a(1);
-      while (1)
-        [d, r] = deconv (b, a);
-        nz = find (abs (r) > tol);
-        if (isempty (nz))
-          x = a;
-          break;
-        else
-          r = r(nz(1):length(r));
-        endif
-        b = a;
-        a = r / r(1);
-      endwhile
+      x = 1;
     endif
   else
-    print_usage ();
+    a /= a(1);
+    while (1)
+      [d, r] = deconv (b, a);
+      nz = find (abs (r) > tol);
+      if (isempty (nz))
+        x = a;
+        break;
+      else
+        r = r(nz(1):length (r));
+      endif
+      b = a;
+      a = r / r(1);
+    endwhile
   endif
 
 endfunction
--- a/scripts/polynomial/polyint.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/polynomial/polyint.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,7 +36,7 @@
 
 function retval = polyint (p, k)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -79,5 +79,5 @@
 %! B = [length(A):-1:1];
 %! assert (polyint (A), [1./B, 0]);
 
-%!error polyint ()
+%!error <Invalid call> polyint ()
 %!error polyint (ones (2,2))
--- a/scripts/polynomial/polyout.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/polynomial/polyout.m	Thu Nov 19 13:08:00 2020 -0800
@@ -49,7 +49,7 @@
 
 function y = polyout (c, x)
 
-  if (nargin < 1) || (nargin > 2) || (nargout < 0) || (nargout > 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/polynomial/polyreduce.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/polynomial/polyreduce.m	Thu Nov 19 13:08:00 2020 -0800
@@ -32,7 +32,7 @@
 
 function p = polyreduce (c)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   elseif (! isvector (c) || isempty (c))
     error ("polyreduce: C must be a non-empty vector");
@@ -54,7 +54,6 @@
 %!assert (polyreduce ([1, 0, 3]), [1, 0, 3])
 %!assert (polyreduce ([0, 0, 0]), 0)
 
-%!error polyreduce ()
-%!error polyreduce (1, 2)
+%!error <Invalid call> polyreduce ()
 %!error <C must be a non-empty vector> polyreduce ([1, 2; 3, 4])
 %!error <C must be a non-empty vector> polyreduce ([])
--- a/scripts/polynomial/polyval.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/polynomial/polyval.m	Thu Nov 19 13:08:00 2020 -0800
@@ -48,7 +48,7 @@
 
 function [y, dy] = polyval (p, x, s = [], mu)
 
-  if (nargin < 2 || nargin > 4 || (nargout == 2 && nargin < 3))
+  if (nargin < 2 || (nargout == 2 && nargin < 3))
     print_usage ();
   endif
 
@@ -175,10 +175,9 @@
 %!assert (class (polyval ([], single ([]))), "single")
 
 ## Test input validation
-%!error polyval ()
-%!error polyval (1)
-%!error polyval (1,2,3,4,5)
-%!error [y, dy] = polyval (1, 2)
+%!error <Invalid call> polyval ()
+%!error <Invalid call> polyval (1)
+%!error <Invalid call> [y, dy] = polyval (1, 2)
 %!error <P must be a numeric floating point vector> polyval ({1, 0}, 0:10)
 %!error <P must be a numeric floating point vector> polyval (int8 ([1]), 0:10)
 %!error <P must be a numeric floating point vector> polyval ([1,0;0,1], 0:10)
--- a/scripts/polynomial/ppder.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/polynomial/ppder.m	Thu Nov 19 13:08:00 2020 -0800
@@ -35,7 +35,7 @@
 
 function ppd = ppder (pp, m = 1)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/polynomial/ppint.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/polynomial/ppint.m	Thu Nov 19 13:08:00 2020 -0800
@@ -34,7 +34,7 @@
 
 function ppi = ppint (pp, c)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
   if (! (isstruct (pp) && strcmp (pp.form, "pp")))
--- a/scripts/polynomial/ppjumps.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/polynomial/ppjumps.m	Thu Nov 19 13:08:00 2020 -0800
@@ -34,7 +34,7 @@
 
 function jumps = ppjumps (pp)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/polynomial/ppval.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/polynomial/ppval.m	Thu Nov 19 13:08:00 2020 -0800
@@ -61,7 +61,7 @@
   P = reshape (P, [d, n * k]);
   P = shiftdim (P, nd);
   P = reshape (P, [n, k, d]);
-  Pidx = P(idx(:), :);  # 2D matrix size: x = coefs*prod(d), y = prod(sxi)
+  Pidx = P(idx(:), :);  # 2D matrix size: x = coefs*prod (d), y = prod (sxi)
 
   if (isvector (xi))
     Pidx = reshape (Pidx, [xn, k, d]);
@@ -139,9 +139,8 @@
 %! assert (ppval (pp, [breaks',breaks']), ret);
 
 ## Test input validation
-%!error ppval ()
-%!error ppval (1)
-%!error ppval (1,2,3)
+%!error <Invalid call> ppval ()
+%!error <Invalid call> ppval (1)
 %!error <argument must be a pp-form structure> ppval (1,2)
 %!error <argument must be a pp-form structure> ppval (struct ("a", 1), 2)
 %!error <argument must be a pp-form structure> ppval (struct ("form", "ab"), 2)
--- a/scripts/polynomial/private/__splinefit__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/polynomial/private/__splinefit__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -334,7 +334,7 @@
 
 % Return
 if isempty(constr)
-    return
+    return;
 end
 
 % Unpack constraints
--- a/scripts/polynomial/residue.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/polynomial/residue.m	Thu Nov 19 13:08:00 2020 -0800
@@ -297,13 +297,13 @@
     pn = 1;
     for j = 1:n - 1
       pn = conv (pn, [1, -p(j)]);
-    end
+    endfor
     for j = n + 1:numel (p)
       pn = conv (pn, [1, -p(j)]);
-    end
+    endfor
     for j = 1:e(n) - 1
       pn = deconv (pn, p1);
-    end
+    endfor
     pn = r(n) * pn;
     pnum += prepad (pn, N+1, 0, 2);
   endfor
--- a/scripts/polynomial/roots.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/polynomial/roots.m	Thu Nov 19 13:08:00 2020 -0800
@@ -84,7 +84,7 @@
 
 function r = roots (c)
 
-  if (nargin != 1 || (! isvector (c) && ! isempty (c)))
+  if (nargin < 1 || (! isvector (c) && ! isempty (c)))
     print_usage ();
   elseif (any (! isfinite (c)))
     error ("roots: inputs must not contain Inf or NaN");
@@ -135,8 +135,7 @@
 %!assert (roots ([1e-200, -1e200, 1]), 1e-200)
 %!assert (roots ([1e-200, -1e200 * 1i, 1]), -1e-200 * 1i)
 
-%!error roots ()
-%!error roots (1,2)
+%!error <Invalid call> roots ()
 %!error roots ([1, 2; 3, 4])
 %!error <inputs must not contain Inf or NaN> roots ([1 Inf 1])
 %!error <inputs must not contain Inf or NaN> roots ([1 NaN 1])
--- a/scripts/polynomial/spline.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/polynomial/spline.m	Thu Nov 19 13:08:00 2020 -0800
@@ -228,7 +228,7 @@
 %! x = 0:10; y = sin (x);
 %! xspline = 0:0.1:10;  yspline = spline (x,y,xspline);
 %! title ("spline fit to points from sin (x)");
-%! plot (xspline,sin(xspline),"r", xspline,yspline,"g-", x,y,"b+");
+%! plot (xspline,sin (xspline),"r", xspline,yspline,"g-", x,y,"b+");
 %! legend ("original", "interpolation", "interpolation points");
 %! %--------------------------------------------------------
 %! % confirm that interpolated function matches the original
--- a/scripts/polynomial/unmkpp.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/polynomial/unmkpp.m	Thu Nov 19 13:08:00 2020 -0800
@@ -29,7 +29,7 @@
 ## Extract the components of a piecewise polynomial structure @var{pp}.
 ##
 ## This function is the inverse of @code{mkpp}: it extracts the inputs to
-## @code{mkpp} needed to create the piecewise polynomial structure @var{PP}.
+## @code{mkpp} needed to create the piecewise polynomial structure @var{pp}.
 ## The code below makes this relation explicit:
 ##
 ## @example
@@ -74,7 +74,7 @@
 
 function [x, P, n, k, d] = unmkpp (pp)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
   if (! (isstruct (pp) && isfield (pp, "form") && strcmp (pp.form, "pp")))
@@ -101,8 +101,7 @@
 %! assert (d, 1);
 
 ## Test input validation
-%!error unmkpp ()
-%!error unmkpp (1,2)
+%!error <Invalid call> unmkpp ()
 %!error <piecewise polynomial structure> unmkpp (1)
 %!error <piecewise polynomial structure> unmkpp (struct ("field1", "pp"))
 %!error <piecewise polynomial structure> unmkpp (struct ("form", "not_a_pp"))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/prefs/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/prefs/addpref.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/prefs/addpref.m	Thu Nov 19 13:08:00 2020 -0800
@@ -109,9 +109,9 @@
 %!   endif
 %! end_unwind_protect
 
-%!error addpref ()
-%!error addpref (1)
-%!error addpref (1,2)
-%!error addpref (1,2,3,4)
+## Test input validation
+%!error <Invalid call> addpref ()
+%!error <Invalid call> addpref (1)
+%!error <Invalid call> addpref (1,2)
 %!error <GROUP must be a string> addpref (1, "pref1", 2)
 %!error <PREF must be a string> addpref ("group1", 1, 2)
--- a/scripts/prefs/getpref.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/prefs/getpref.m	Thu Nov 19 13:08:00 2020 -0800
@@ -55,10 +55,6 @@
 
 function retval = getpref (group, pref, default)
 
-  if (nargin > 3)
-    print_usage ();
-  endif
-
   if (nargin == 0)
     retval = loadprefs ();
   elseif (nargin == 1)
@@ -151,9 +147,7 @@
 %!
 %! unwind_protect_cleanup
 %!   unlink (fullfile (tmp_home, ".octave_prefs"));
-%!   if (isfolder (tmp_home))
-%!     rmdir (tmp_home);
-%!   endif
+%!   sts = rmdir (tmp_home);
 %!   if (isempty (HOME))
 %!     unsetenv ("HOME");
 %!   else
@@ -161,6 +155,5 @@
 %!   endif
 %! end_unwind_protect
 
-%!error getpref (1,2,3,4)
 %!error <GROUP must be a string> getpref (1)
 %!error <PREF must be a string> getpref ("group1", 1, 2)
--- a/scripts/prefs/ispref.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/prefs/ispref.m	Thu Nov 19 13:08:00 2020 -0800
@@ -41,7 +41,7 @@
 
 function retval = ispref (group, pref = "")
 
-  if (nargin == 0 || nargin > 2)
+  if (nargin == 0)
     print_usage ();
   endif
 
@@ -98,7 +98,6 @@
 %!   endif
 %! end_unwind_protect
 
-%!error ispref ()
-%!error ispref (1,2,3)
+%!error <Invalid call> ispref ()
 %!error <GROUP must be a string> ispref (1, "pref1")
 %!error <PREF must be a string> ispref ("group1", 1)
--- a/scripts/prefs/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/prefs/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -8,6 +8,7 @@
   %reldir%/private/saveprefs.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/addpref.m \
   %reldir%/getpref.m \
   %reldir%/ispref.m \
--- a/scripts/prefs/rmpref.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/prefs/rmpref.m	Thu Nov 19 13:08:00 2020 -0800
@@ -42,7 +42,7 @@
 
 function rmpref (group, pref)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   elseif (! ischar (group))
     error ("rmpref: GROUP must be a string");
@@ -113,7 +113,6 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error rmpref ()
-%!error rmpref (1,2,3)
+%!error <Invalid call> rmpref ()
 %!error <GROUP must be a string> rmpref (1)
 %!error <PREF must be a string> rmpref ("group1", 1)
--- a/scripts/prefs/setpref.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/prefs/setpref.m	Thu Nov 19 13:08:00 2020 -0800
@@ -96,9 +96,7 @@
 %!         "size mismatch for PREF and VAL");
 %! unwind_protect_cleanup
 %!   unlink (fullfile (tmp_home, ".octave_prefs"));
-%!   if (isfolder (tmp_home))
-%!     rmdir (tmp_home);
-%!   endif
+%!   sts = rmdir (tmp_home);
 %!   if (isempty (HOME))
 %!     unsetenv ("HOME");
 %!   else
@@ -106,9 +104,9 @@
 %!   endif
 %! end_unwind_protect
 
-%!error setpref ()
-%!error setpref (1)
-%!error setpref (1,2)
-%!error setpref (1,2,3,4)
+## Test input validation
+%!error <Invalid call> setpref ()
+%!error <Invalid call> setpref (1)
+%!error <Invalid call> setpref (1,2)
 %!error <GROUP must be a string> setpref (1, "pref1", 2)
 %!error <PREF must be a string> setpref ("group1", 1, 2)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/profiler/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/profiler/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/profiler/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/profexplore.m \
   %reldir%/profexport.m \
   %reldir%/profile.m \
--- a/scripts/profiler/profexplore.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/profiler/profexplore.m	Thu Nov 19 13:08:00 2020 -0800
@@ -41,7 +41,7 @@
 
   if (nargin == 0)
     data = profile ("info");
-  elseif (nargin != 1)
+  elseif (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/profiler/profexport.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/profiler/profexport.m	Thu Nov 19 13:08:00 2020 -0800
@@ -47,7 +47,7 @@
 ## Built-in profiler.
 function profexport (dir, name = "", data)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -77,7 +77,7 @@
   endif
 
   if (! copyfile (__dataFilename ("style.css"), dir))
-    error ("profexport: failed to copy data file to directory '%s'", dir)
+    error ("profexport: failed to copy data file to directory '%s'", dir);
   endif
 
   if (isempty (name))
@@ -207,18 +207,18 @@
   template = __readTemplate ("hierarchical.html");
   entryTemplate = __readTemplate ("hierarchical_entry.html");
 
-  % Fill in basic data and parent breadcrumbs.
+  ## Fill in basic data and parent breadcrumbs.
   res = template;
   res = strrep (res, "%title", name);
   parentsStr = __hierarchicalParents (parents);
   res = strrep (res, "%parents", parentsStr);
 
-  % Set this page's counter and update parents struct with it.
+  ## Set this page's counter and update parents struct with it.
   mine = cnt++;
   parents{end}.cnt = mine;
   file = sprintf ("%s/hierarchy-%d.html", dir, mine);
 
-  % Sort children by time.
+  ## Sort children by time.
   times = -[ children.TotalTime ];
   [~, p] = sort (times);
   children = children(p);
@@ -314,7 +314,7 @@
 %! open (fullfile (dir, "index.html"));
 
 ## Test input validation
-%!error profexport ()
+%!error <Invalid call> profexport ()
 %!error profexport (1)
 %!error profexport (1, 2, 3, 4)
 %!error <DIR must be a string> profexport (5)
--- a/scripts/profiler/profile.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/profiler/profile.m	Thu Nov 19 13:08:00 2020 -0800
@@ -68,7 +68,7 @@
 ## Built-in profiler.
 function retval = profile (option)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -151,6 +151,6 @@
 %! assert (fieldnames (hier), {"Index"; "SelfTime"; "TotalTime"; "NumCalls"; "Children"});
 
 ## Test input validation
-%!error profile ()
+%!error <Invalid call> profile ()
 %!error profile ("on", 2)
 %!error profile ("INVALID_OPTION")
--- a/scripts/profiler/profshow.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/profiler/profshow.m	Thu Nov 19 13:08:00 2020 -0800
@@ -46,10 +46,6 @@
 ## Built-in profiler.
 function profshow (data, n = 20)
 
-  if (nargin > 2)
-    print_usage ();
-  endif
-
   if (nargin == 0)
     data = profile ("info");
   elseif (nargin == 1 && ! isstruct (data))
@@ -113,7 +109,7 @@
 %! profile off;
 %! profshow (profile ("info"), 5);
 
-%!error profshow (1, 2, 3)
+## Test input validation
 %!error <N must be a positive integer> profshow (struct (), ones (2))
 %!error <N must be a positive integer> profshow (struct (), 1+i)
 %!error <N must be a positive integer> profshow (struct (), -1)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/set/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/set/ismember.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/set/ismember.m	Thu Nov 19 13:08:00 2020 -0800
@@ -92,7 +92,7 @@
       s_idx = zeros (size (real_argout{2}));
       s_idx(tf) = min (real_argout{2}(tf), imag_argout{2}(tf));
     endif
-    return
+    return;
   endif
 
   ## lookup() does not handle logical values
@@ -294,7 +294,7 @@
 %! assert (s_idx, 2);
 %!
 %! tf = ismember ([5, 4-3j, 3+4j], 5);
-%! assert (tf, logical ([1, 0, 0]))
+%! assert (tf, logical ([1, 0, 0]));
 %! [~, s_idx] = ismember ([5, 4-3j, 3+4j], 5);
 %! assert (s_idx, [1, 0, 0]);
 %!
@@ -303,8 +303,8 @@
 %! assert (s_idx, 1);
 
 ## Test input validation
-%!error ismember ()
-%!error ismember (1)
-%!error ismember (1,2,3,4)
+%!error <Invalid call> ismember ()
+%!error <Invalid call> ismember (1)
+%!error <Invalid call> ismember (1,2,3,4)
 %!error <"stable" or "sorted" are not valid options> ismember (1,2, "sorted")
 %!error <"stable" or "sorted" are not valid options> ismember (1,2, "stable")
--- a/scripts/set/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/set/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -6,6 +6,7 @@
   %reldir%/private/validsetargs.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/intersect.m \
   %reldir%/ismember.m \
   %reldir%/powerset.m \
--- a/scripts/set/powerset.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/set/powerset.m	Thu Nov 19 13:08:00 2020 -0800
@@ -40,7 +40,7 @@
 
 function p = powerset (a, byrows_arg)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -113,8 +113,7 @@
 %!assert (powerset([]), {});  # always return a cell array
 
 ## Test input validation
-%!error powerset ()
-%!error powerset (1,2,3)
+%!error <Invalid call> powerset ()
 %!error <second argument must be "rows"> powerset (1, "cols")
 %!error <"rows" not valid for cell arrays> powerset ({1}, "rows")
 %!error <cell arrays can only be used for character> powerset ({1})
--- a/scripts/set/union.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/set/union.m	Thu Nov 19 13:08:00 2020 -0800
@@ -91,7 +91,7 @@
       na = rows (a);
     else
       na = numel (a);
-    end
+    endif
     ia = idx(idx <= na);
     ib = idx(idx > na) - na;
   endif
@@ -195,12 +195,12 @@
 %!error <cells not supported with "rows"> union ({"a"}, {"b"}, "rows","legacy")
 %!error <A and B must be arrays or cell arrays> union (@sin, 1, "rows")
 %!error <A and B must be arrays or cell arrays> union (@sin,1,"rows","legacy")
-%!error <A and B must be 2-dimensional matrices> union (rand(2,2,2), 1, "rows")
-%!error <A and B must be 2-dimensional matrices> union (1, rand(2,2,2), "rows")
+%!error <A and B must be 2-dimensional matrices> union (rand (2,2,2), 1, "rows")
+%!error <A and B must be 2-dimensional matrices> union (1, rand (2,2,2), "rows")
 %!error <A and B must be 2-dimensional matrices>
-%! union (rand(2,2,2), 1, "rows", "legacy");
+%! union (rand (2,2,2), 1, "rows", "legacy");
 %!error <A and B must be 2-dimensional matrices>
-%! union (1, rand(2,2,2), "rows", "legacy");
+%! union (1, rand (2,2,2), "rows", "legacy");
 %!error <number of columns in A and B must match> union ([1 2], 1, "rows")
 %!error <number of columns in A and B must match> union (1, [1 2], "rows")
 %!error <number of columns in A and B must match>
--- a/scripts/set/unique.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/set/unique.m	Thu Nov 19 13:08:00 2020 -0800
@@ -354,7 +354,7 @@
 %! assert (j, [4; 1; 4; 3; 2]);
 
 ## Test input validation
-%!error unique ()
+%!error <Invalid call> unique ()
 %!error <X must be an array or cell array of strings> unique ({1})
 %!error <options must be strings> unique (1, 2)
 %!error <cannot specify both "first" and "last"> unique (1, "first", "last")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/signal/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/signal/__parse_movargs__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/__parse_movargs__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -24,10 +24,12 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn {} {@var{args} =} __parse_movargs__ (@var{varargin})
+## @deftypefn {} {@var{args} =} __parse_movargs__ (@var{caller}, @var{varargin})
 ##
 ## Parse arguments for movXXX functions before passing to @code{movfun}.
 ##
+## The input @var{caller} is a string with the name of the calling function
+## and is used to personalize any error messages.
 ## @seealso{movfun}
 ## @end deftypefn
 
@@ -57,7 +59,6 @@
     else
       error ("Octave:invalid-input-arg",
              [caller ": invalid input at position %d"], i);
-      args(end+1) = arg;
     endif
 
     i += 1;  # Advance to next element
--- a/scripts/signal/arch_fit.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/arch_fit.m	Thu Nov 19 13:08:00 2020 -0800
@@ -58,7 +58,7 @@
 
 function [a, b] = arch_fit (y, x, p, iter, gamma, a0, b0)
 
-  if (nargin < 3 || nargin == 6 || nargin > 7)
+  if (nargin < 3 || nargin == 6)
     print_usage ();
   endif
 
--- a/scripts/signal/arch_rnd.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/arch_rnd.m	Thu Nov 19 13:08:00 2020 -0800
@@ -83,13 +83,13 @@
   y = zeros (t, 1);
 
   h(1) = a(1);
-  e(1) = sqrt (h(1)) * randn;
+  e(1) = sqrt (h(1)) * randn ();
   y(1) = b(1) + e(1);
 
   for t = 2:m
     ta   = min ([t, la]);
     h(t) = a(1) + a(2:ta) * e(t-ta+1:t-1).^2;
-    e(t) = sqrt (h(t)) * randn;
+    e(t) = sqrt (h(t)) * randn ();
     tb   = min ([t, lb]);
     y(t) = b(1) + b(2:tb) * y(t-tb+1:t-1) + e(t);
   endfor
@@ -97,7 +97,7 @@
   if (t > m)
     for t = m+1:t
       h(t) = a(1) + a(2:la) * e(t-la+1:t-1).^2;
-      e(t) = sqrt (h(t)) * randn;
+      e(t) = sqrt (h(t)) * randn ();
       y(t) = b(1) + b(2:lb) * y(t-tb+1:t-1) + e(t);
     endfor
   endif
--- a/scripts/signal/arma_rnd.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/arma_rnd.m	Thu Nov 19 13:08:00 2020 -0800
@@ -47,15 +47,9 @@
 ## is omitted, @var{n} = 100 is used.
 ## @end deftypefn
 
-function x = arma_rnd (a, b, v, t, n)
+function x = arma_rnd (a, b, v, t, n = 100)
 
-  if (nargin == 4)
-    n = 100;
-  elseif (nargin == 5)
-    if (! isscalar (n))
-      error ("arma_rnd: N must be a scalar");
-    endif
-  else
+  if (nargin < 4)
     print_usage ();
   endif
 
@@ -67,6 +61,10 @@
     error ("arma_rnd: T must be a scalar");
   endif
 
+  if (! isscalar (n))
+    error ("arma_rnd: N must be a scalar");
+  endif
+
   ar = length (a);
   br = length (b);
 
--- a/scripts/signal/autoreg_matrix.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/autoreg_matrix.m	Thu Nov 19 13:08:00 2020 -0800
@@ -63,6 +63,6 @@
 %! B(:,1) = 1;
 %! assert (autoreg_matrix (A,K), B);
 
-%!error autoreg_matrix ()
-%!error autoreg_matrix (1)
+%!error <Invalid call> autoreg_matrix ()
+%!error <Invalid call> autoreg_matrix (1)
 %!error autoreg_matrix (ones (4,1), 5)
--- a/scripts/signal/bartlett.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/bartlett.m	Thu Nov 19 13:08:00 2020 -0800
@@ -35,7 +35,7 @@
 
 function c = bartlett (m)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -63,7 +63,7 @@
 %! A = bartlett (N);
 %! assert (A(ceil (N/2)), 1);
 
-%!error bartlett ()
+%!error <Invalid call> bartlett ()
 %!error bartlett (0.5)
 %!error bartlett (-1)
 %!error bartlett (ones (1,4))
--- a/scripts/signal/blackman.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/blackman.m	Thu Nov 19 13:08:00 2020 -0800
@@ -42,7 +42,7 @@
 
 function c = blackman (m, opt)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -90,7 +90,7 @@
 %! A = blackman (N, "periodic");
 %! assert (A(N/2 + 1), 1, 1e-6);
 
-%!error blackman ()
+%!error <Invalid call> blackman ()
 %!error blackman (0.5)
 %!error blackman (-1)
 %!error blackman (ones (1,4))
--- a/scripts/signal/detrend.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/detrend.m	Thu Nov 19 13:08:00 2020 -0800
@@ -42,7 +42,7 @@
 
 function y = detrend (x, p = 1)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -101,8 +101,7 @@
 %! assert (abs (y(:)) < 20*eps);
 
 ## Test input validation
-%!error detrend ()
-%!error detrend (1, 2, 3)
+%!error <Invalid call> detrend ()
 %!error detrend ("a")
 %!error detrend (true)
 %!error detrend (1, "invalid")
--- a/scripts/signal/diffpara.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/diffpara.m	Thu Nov 19 13:08:00 2020 -0800
@@ -46,7 +46,7 @@
 
 function [d, dd] = diffpara (x, a, b)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/signal/fftconv.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/fftconv.m	Thu Nov 19 13:08:00 2020 -0800
@@ -40,7 +40,7 @@
 
 function c = fftconv (x, y, n)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -102,8 +102,7 @@
 %! assert (size (conv (b,a)), [1, numel(a)+numel(b)-1]);
 
 ## Test input validation
-%!error fftconv (1)
-%!error fftconv (1,2,3,4)
+%!error <Invalid call> fftconv (1)
 %!error fftconv ([1, 2; 3, 4], 3)
 %!error fftconv (2, [])
 %!error fftconv ([1,1], [2,2] , [3, 4])
--- a/scripts/signal/fftfilt.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/fftfilt.m	Thu Nov 19 13:08:00 2020 -0800
@@ -47,7 +47,7 @@
   ## of two larger than N and length(b).  This could result in length
   ## one blocks, but if the user knows better ...
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -187,8 +187,7 @@
 %! assert (y0, y, 55*eps);
 
 ## Test input validation
-%!error fftfilt (1)
-%!error fftfilt (1, 2, 3, 4)
+%!error <Invalid call> fftfilt (1)
 %!error fftfilt (ones (2), 1)
 %!error fftfilt (2, ones (3,3,3))
 %!error fftfilt (2, 1, ones (2))
--- a/scripts/signal/fftshift.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/fftshift.m	Thu Nov 19 13:08:00 2020 -0800
@@ -51,7 +51,7 @@
 
 function retval = fftshift (x, dim)
 
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -151,7 +151,6 @@
 %! assert (fftshift (y), x);
 
 ## Test input validation
-%!error fftshift ()
-%!error fftshift (1, 2, 3)
+%!error <Invalid call> fftshift ()
 %!error fftshift (0:3, -1)
 %!error fftshift (0:3, 0:3)
--- a/scripts/signal/filter2.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/filter2.m	Thu Nov 19 13:08:00 2020 -0800
@@ -49,7 +49,7 @@
 
 function y = filter2 (b, x, shape)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
   if (nargin < 3)
--- a/scripts/signal/freqz.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/freqz.m	Thu Nov 19 13:08:00 2020 -0800
@@ -82,7 +82,7 @@
 
 function [h_r, f_r] = freqz (b, a, n, region, Fs)
 
-  if (nargin < 1 || nargin > 5)
+  if (nargin < 1)
     print_usage ();
   elseif (nargin == 1)
     ## Response of an FIR filter.
--- a/scripts/signal/freqz_plot.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/freqz_plot.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,7 +36,7 @@
 
 function freqz_plot (w, h, freq_norm = false)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
--- a/scripts/signal/hamming.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/hamming.m	Thu Nov 19 13:08:00 2020 -0800
@@ -41,7 +41,7 @@
 
 function c = hamming (m, opt)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -87,7 +87,7 @@
 %! A = hamming (N, "periodic");
 %! assert (A(N/2 + 1), 1);
 
-%!error hamming ()
+%!error <Invalid call> hamming ()
 %!error hamming (0.5)
 %!error hamming (-1)
 %!error hamming (ones (1,4))
--- a/scripts/signal/hanning.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/hanning.m	Thu Nov 19 13:08:00 2020 -0800
@@ -41,7 +41,7 @@
 
 function c = hanning (m, opt)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -87,7 +87,7 @@
 %! A = hanning (N, "periodic");
 %! assert (A(N/2 + 1), 1);
 
-%!error hanning ()
+%!error <Invalid call> hanning ()
 %!error hanning (0.5)
 %!error hanning (-1)
 %!error hanning (ones (1,4))
--- a/scripts/signal/hurst.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/hurst.m	Thu Nov 19 13:08:00 2020 -0800
@@ -33,7 +33,7 @@
 
 function H = hurst (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/signal/ifftshift.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/ifftshift.m	Thu Nov 19 13:08:00 2020 -0800
@@ -35,7 +35,7 @@
 
 function retval = ifftshift (x, dim)
 
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -134,7 +134,6 @@
 %! assert (ifftshift (y), x);
 
 ## Test input validation
-%!error ifftshift ()
-%!error ifftshift (1, 2, 3)
+%!error <Invalid call> ifftshift ()
 %!error ifftshift (0:3, -1)
 %!error ifftshift (0:3, 0:3)
--- a/scripts/signal/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -9,6 +9,7 @@
   %reldir%/private/triangle_sw.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/__parse_movargs__.m \
   %reldir%/arch_fit.m \
   %reldir%/arch_rnd.m \
--- a/scripts/signal/movfun.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/movfun.m	Thu Nov 19 13:08:00 2020 -0800
@@ -311,6 +311,7 @@
 ## Apply "shrink" boundary conditions
 ## Function is not applied to any window elements outside the original data.
 function y = shrink_bc (fcn, x, idxp, win, wlen, odim)
+
   N   = length (x);
   idx = idxp + win;
   tf  = (idx > 0) & (idx <= N);  # idx inside boundaries
@@ -324,11 +325,12 @@
     k      = idx(tf(:,i),i);
     y(i,:) = fcn (x(k));
   endfor
+
 endfunction
 
 ## Apply replacement value boundary conditions
 ## Window is padded at beginning and end with user-specified value.
-function y = replaceval_bc (fcn, x, idxp, win, wlen)
+function y = replaceval_bc (fcn, x, idxp, win, wlen, ~)
 
   persistent substitute;
 
@@ -359,7 +361,7 @@
 ## Apply "same" boundary conditions
 ## 'y' values outside window are replaced by value of 'x' at the window
 ## boundary.
-function y = same_bc (fcn, x, idxp, win)
+function y = same_bc (fcn, x, idxp, win, ~, ~)
   idx          = idxp + win;
   idx(idx < 1) = 1;
   N            = length (x);
@@ -370,7 +372,7 @@
 ## Apply "periodic" boundary conditions
 ## Window wraps around.  Window values outside data array are replaced with
 ## data from the other end of the array.
-function y = periodic_bc (fcn, x, idxp, win)
+function y = periodic_bc (fcn, x, idxp, win, ~, ~)
   N       = length (x);
   idx     = idxp + win;
   tf      = idx < 1;
@@ -600,12 +602,12 @@
 %!assert (size( movfun (@(x) [min(x), max(x)], cumsum (ones (10,5),2), 3)),
 %!        [10 5 2])
 ## outdim > dim
-%!error (movfun (@(x) [min(x), max(x)], (1:10).', 3, "Outdim", 3))
+%!error movfun (@(x) [min(x), max(x)], (1:10).', 3, "Outdim", 3)
 
 ## Test input validation
-%!error movfun ()
-%!error movfun (@min)
-%!error movfun (@min, 1)
+%!error <Invalid call> movfun ()
+%!error <Invalid call> movfun (@min)
+%!error <Invalid call> movfun (@min, 1)
 %!error <WLEN must be .* array of integers> movfun (@min, 1, {1})
 %!error <WLEN must be .* array of integers .= 0> movfun (@min, 1, -1)
 %!error <WLEN must be .* array of integers> movfun (@min, 1, 1.5)
--- a/scripts/signal/movslice.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/movslice.m	Thu Nov 19 13:08:00 2020 -0800
@@ -94,9 +94,8 @@
 ## FIXME: Need functional BIST tests
 
 ## Test input validation
-%!error movslice ()
-%!error movslice (1)
-%!error movslice (1,2,3)
+%!error <Invalid call> movslice ()
+%!error <Invalid call> movslice (1)
 %!error <N must be a positive integer> movslice ([1 2], 1)
 %!error <N must be a positive integer> movslice (0, 1)
 %!error <WLEN must be .* array of integers> movslice (1, {1})
--- a/scripts/signal/periodogram.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/periodogram.m	Thu Nov 19 13:08:00 2020 -0800
@@ -210,8 +210,8 @@
 
 
 ## Test input validation
-%!error periodogram ()
-%!error periodogram (1,2,3,4,5,6)
+%!error <Invalid call> periodogram ()
+%!error <Invalid call> periodogram (1,2,3,4,5,6)
 %!error <X must be a real or complex vector> periodogram (ones (2,2))
 %!error <WIN must be a vector.*same length> periodogram (1:5, ones (2,2))
 %!error <WIN must be a vector.*same length> periodogram (1:5, 1:6)
--- a/scripts/signal/sinc.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/sinc.m	Thu Nov 19 13:08:00 2020 -0800
@@ -38,7 +38,7 @@
 
 function result = sinc (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -58,4 +58,5 @@
 %!assert (sinc (1), 0,1e-6)
 %!assert (sinc (1/2), 2/pi, 1e-6)
 
-%!error sinc()
+## Test input validation
+%!error <Invalid call> sinc ()
--- a/scripts/signal/sinetone.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/sinetone.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,7 +36,7 @@
 
 function retval = sinetone (freq, rate = 8000, sec = 1, ampl = 64)
 
-  if (nargin < 1 || nargin > 4)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/signal/sinewave.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/sinewave.m	Thu Nov 19 13:08:00 2020 -0800
@@ -33,19 +33,21 @@
 ## @seealso{sinetone}
 ## @end deftypefn
 
-function x = sinewave (m, n, d)
+function x = sinewave (m, n, d = 0)
 
-  if (nargin > 0 && nargin < 4)
-    if (nargin < 3)
-      d = 0;
-    endif
-    if (nargin < 2)
-      n = m;
-    endif
-    x = sin (((1 : m) + d - 1) * 2 * pi / n);
-  else
+  if (nargin < 1)
     print_usage ();
   endif
+    
+  ## FIXME: No input validation of M, N, or D
+  if (nargin < 2)
+    n = m;
+  endif
+  if (nargin < 3)
+    d = 0;
+  endif
+
+  x = sin (((1 : m) + d - 1) * 2 * pi / n);
 
 endfunction
 
@@ -58,4 +60,4 @@
 %!assert (sinewave (1), sinewave (1, 1,0))
 %!assert (sinewave (3, 4), sinewave (3, 4, 0))
 
-%!error sinewave ()
+%!error <Invalid call> sinewave ()
--- a/scripts/signal/spectral_adf.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/spectral_adf.m	Thu Nov 19 13:08:00 2020 -0800
@@ -41,7 +41,7 @@
 
 function retval = spectral_adf (c, win, b)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -74,7 +74,6 @@
 
 
 ## Test input validation
-%!error spectral_adf ()
-%!error spectral_adf (1, 2, 3, 4)
-%!error spectral_adf (1, 2)
-%!error spectral_adf (1, "invalid")
+%!error <Invalid call> spectral_adf ()
+%!error <WIN must be a string> spectral_adf (1, 2)
+%!error <unable to find function for @invalid_lw> spectral_adf (1, "invalid")
--- a/scripts/signal/spectral_xdf.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/spectral_xdf.m	Thu Nov 19 13:08:00 2020 -0800
@@ -41,7 +41,7 @@
 
 function retval = spectral_xdf (x, win, b)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -76,7 +76,6 @@
 
 
 ## Test input validation
-%!error spectral_xdf ()
-%!error spectral_xdf (1, 2, 3, 4)
-%!error spectral_xdf (1, 2)
-%!error spectral_xdf (1, "invalid")
+%!error <Invalid call> spectral_xdf ()
+%!error <WIN must be a string> spectral_xdf (1, 2)
+%!error <unable to find function for @invalid_sw> spectral_xdf (1, "invalid")
--- a/scripts/signal/spencer.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/spencer.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function retval = spencer (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/signal/stft.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/stft.m	Thu Nov 19 13:08:00 2020 -0800
@@ -66,7 +66,7 @@
 
 function [y, c] = stft (x, win_size = 80, inc = 24, num_coef = 64, win_type = 1)
 
-  if (nargin < 1 || nargin > 5)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/signal/unwrap.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/unwrap.m	Thu Nov 19 13:08:00 2020 -0800
@@ -39,7 +39,7 @@
 
 function retval = unwrap (x, tol, dim)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -152,6 +152,5 @@
 %! assert (diff (unwrap (B), 1) < 2*pi, true (1, length (B)-1));
 
 ## Test input validation
-%!error unwrap ()
-%!error unwrap (1,2,3,4)
+%!error <Invalid call> unwrap ()
 %!error unwrap ("foo")
--- a/scripts/signal/yulewalker.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/signal/yulewalker.m	Thu Nov 19 13:08:00 2020 -0800
@@ -34,7 +34,7 @@
 
 function [a, v] = yulewalker (c)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/sparse/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/sparse/bicg.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/bicg.m	Thu Nov 19 13:08:00 2020 -0800
@@ -236,7 +236,7 @@
   endif
   norm_b = norm (b, 2);
 
-  if (norm_b == 0)  # the only (only iff det(A) == 0) solution is x = 0
+  if (norm_b == 0)  # the only (only iff det (A) == 0) solution is x = 0
     if (nargout < 2)
       printf ("The right hand side vector is all zero so bicg\n")
       printf ("returned an all zero solution without iterating.\n")
@@ -258,7 +258,7 @@
   resvec(1) = norm (r0, 2);
 
   try
-    warning ("error", "Octave:singular-matrix", "local")
+    warning ("error", "Octave:singular-matrix", "local");
     prec_r0 = M1fun (r0, "notransp", varargin{:});  # r0 preconditioned
     prec_s0 = s0;
     prec_r0 = M2fun (prec_r0, "notransp", varargin{:});
@@ -276,7 +276,7 @@
     alpha = (s0' * prec_r0);
     if (abs (prod_qv) <= eps * abs (alpha))
       flag = 4;
-      break
+      break;
     endif
     alpha ./= prod_qv;
     x += alpha * p;
--- a/scripts/sparse/bicgstab.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/bicgstab.m	Thu Nov 19 13:08:00 2020 -0800
@@ -213,14 +213,14 @@
   ## Check consistency and  type of A, M1, M2
   [Afun, M1fun, M2fun] =  __alltohandles__ (A, b, M1, M2, "bicgstab");
 
-  # Check if input tol are empty (set them to default if necessary)
+  ## Check if input tol are empty (set them to default if necessary)
   [tol, maxit, x0] = __default__input__ ({1e-06, min(rows(b), 20), ...
-                    zeros(rows(b), 1)}, tol, maxit, x0);
+                    zeros(rows (b), 1)}, tol, maxit, x0);
 
   norm_b = norm (b, 2);
   if (norm_b == 0)
     if (nargout < 2)
-      printf("The right hand side vector is all zero so bicgstab \n")
+      printf ("The right hand side vector is all zero so bicgstab \n")
       printf ("returned an all zero solution without iterating.\n")
     endif
     x_min = zeros (numel (b), 1);
@@ -228,7 +228,7 @@
     flag = 0;
     resvec = 0;
     relres = 0;
-    return
+    return;
   endif
 
   ## Double maxit to mind also the "half iterations"
@@ -248,7 +248,7 @@
 
   ## To check if the preconditioners are singular or they have some NaN
   try
-    warning("error", "Octave:singular-matrix", "local");
+    warning ("error", "Octave:singular-matrix", "local");
     p_hat = feval (M1fun, p, varargin{:});
     p_hat = feval (M2fun, p_hat, varargin{:});
   catch
@@ -270,7 +270,7 @@
     if (resvec (iter + 1) <= real_tol) # reached the tol
       x_min = x;
       iter_min = iter;
-      break
+      break;
     elseif (resvec (iter + 1) <= resvec (iter_min + 1)) # Found min residual
       x_min = x;
       iter_min = iter;
@@ -293,7 +293,7 @@
     endif
     if (norm (x - x_pr) <= norm (x) * eps)
       flag = 3;
-      break
+      break;
     endif
     x_pr = x;
     rho_2 = rho_1;
@@ -309,7 +309,7 @@
   endwhile
   resvec = resvec (1:iter+1,1);
 
-  relres = resvec (iter_min + 1) / norm_b; ## I set the relative residual
+  relres = resvec (iter_min + 1) / norm_b;  # I set the relative residual
   iter /=  2;
   iter_min /= 2;
 
--- a/scripts/sparse/cgs.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/cgs.m	Thu Nov 19 13:08:00 2020 -0800
@@ -199,12 +199,12 @@
   [Afun, M1fun, M2fun] = __alltohandles__ (A, b, M1, M2, "cgs");
 
   [tol, maxit, x0] = __default__input__ ({1e-06, min( rows(b), 20), ...
-                                          zeros(size(b))}, tol, maxit, x0);
+                                          zeros(size (b))}, tol, maxit, x0);
 
   norm_b = norm (b, 2);
   if (norm_b == 0)
     if (nargout < 2)
-      printf("The right hand side vector is all zero so cgs \n")
+      printf ("The right hand side vector is all zero so cgs \n")
       printf ("returned an all zero solution without iterating.\n")
     endif
     x_min = zeros (numel (b), 1);
@@ -212,7 +212,7 @@
     flag = 0;
     resvec = 0;
     relres = 0;
-    return
+    return;
   endif
 
   resvec = zeros (maxit, 1); # Preallocation of resvec
@@ -229,7 +229,7 @@
   rho_1 = rr' * r0;
 
   try
-    warning ("error","Octave:singular-matrix","local")
+    warning ("error","Octave:singular-matrix","local");
     p_hat = feval (M1fun, p, varargin{:});
     p_hat = feval (M2fun, p_hat, varargin {:});
   catch
@@ -252,7 +252,7 @@
     r0 -= alpha* feval (Afun, u_hat, varargin{:});
     iter += 1;
     resvec (iter + 1) = norm (r0, 2);
-    if (norm (x - x_pr, 2) <= norm(x, 2) * eps) # Stagnation
+    if (norm (x - x_pr, 2) <= norm (x, 2) * eps) # Stagnation
       flag = 3;
       break;
     endif
@@ -379,7 +379,7 @@
 %! M1_fun = @(z) M1 \ z;
 %! M2_fun = @(z) M2 \ z;
 %! [x, flag] = cgs (A,b);
-%! assert(flag, 0);
+%! assert (flag, 0);
 %! [x, flag] = cgs (A, b, [], maxit, M1, M2);
 %! assert (flag, 0);
 %! [x, flag] = cgs (A, b, [], maxit, M1_fun, M2_fun);
--- a/scripts/sparse/colperm.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/colperm.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,7 +36,7 @@
 
 function p = colperm (s)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/sparse/eigs.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/eigs.m	Thu Nov 19 13:08:00 2020 -0800
@@ -787,7 +787,7 @@
 %! B = toeplitz (sparse ([1, 1], [1, 2], [2, 1], 1, 10));
 %! [v, d] = eigs (A, B, 4, "lm");
 %! for i = 1:4
-%!   assert (A * v(:,i), d(i, i) * B * v(:,i), 1e-12)
+%!   assert (A * v(:,i), d(i, i) * B * v(:,i), 1e-12);
 %! endfor
 %! ddiag = diag (d);
 %! [ddiag, idx] = sort (ddiag);
@@ -887,7 +887,7 @@
 %! opts.cholB = true;
 %! [v, d] = eigs (A, R, 4, "lm", opts);
 %! for i = 1:4
-%!   assert (A * v(:,i), d(i, i) * B * v(:,i), 1e-12)
+%!   assert (A * v(:,i), d(i, i) * B * v(:,i), 1e-12);
 %! endfor
 %!testif HAVE_ARPACK, HAVE_UMFPACK
 %! A = toeplitz (sparse (1:10));
@@ -897,7 +897,7 @@
 %! opts.permB = permB;
 %! [v, d] = eigs (A, R, 4, "lm", opts);
 %! for i = 1:4
-%!   assert (A * v(:,i), d(i, i) * B * v(:,i), 1e-12)
+%!   assert (A * v(:,i), d(i, i) * B * v(:,i), 1e-12);
 %! endfor
 
 
@@ -1292,7 +1292,7 @@
 %! A(1, 1) = 0;
 %! A(1, 9) = 1;
 %! [V, L] = eigs (A, 4, -1);
-%! assert (!any (isnan (diag (L))));
+%! assert (! any (isnan (diag (L))));
 %! assert (any (abs (diag (L)) <= 2 * eps));
 %!testif HAVE_ARPACK
 %! A = diag (ones (9, 1), 1);
@@ -1488,11 +1488,11 @@
 %! i_A = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
 %! j_A = [1, 2, 3, 4, 5, 6, 7,  8, 9, 10];
 %! v_A = [1, 2i, 3, 4i, 5, 6i, 7, 8, 9, 10i];
-%! A = sparse(i_A, j_A, v_A);
+%! A = sparse (i_A, j_A, v_A);
 %! i_B = [1,2, 3, 4, 5, 6, 7, 8, 9, 10];
 %! j_B = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
 %! v_B = [3, 10i, 1, 8i, 7, 6i, 5, 4i, 9, 7i];
-%! B = sparse(i_B, j_B, v_B); # not SPD
+%! B = sparse (i_B, j_B, v_B); # not SPD
 %! [Evectors, Evalues] = eigs(A, B, 5, "SM"); # call_eig is true
 %! ResidualVectors = A * Evectors - B * Evectors * Evalues;
 %! RelativeErrors = norm (ResidualVectors, "columns") ./ ...
--- a/scripts/sparse/etreeplot.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/etreeplot.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,10 +36,15 @@
 
 function etreeplot (A, varargin)
 
-  if (nargin < 1)
+  if (nargin < 1 || nargin > 3)
     print_usage ();
   endif
 
   treeplot (etree (A+A'), varargin{:});
 
 endfunction
+
+
+## Test input validation
+%!error <Invalid call> etreeplot ()
+%!error <Invalid call> etreeplot (1,2,3,4)
--- a/scripts/sparse/gmres.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/gmres.m	Thu Nov 19 13:08:00 2020 -0800
@@ -258,9 +258,9 @@
   size_b = rows (b);
 
   if (tol >= 1)
-    warning("Input tol is bigger than 1. \n Try to use a smaller tolerance.");
+    warning ("Input tol is bigger than 1. \n Try to use a smaller tolerance.");
   elseif (tol <= eps / 2)
-    warning("Input tol may not be achievable by gmres. \n Try to use a bigger tolerance.");
+    warning ("Input tol may not be achievable by gmres. \n Try to use a bigger tolerance.");
   endif
 
   ## This big "if block" is to set maxit and restart in the proper way
@@ -270,7 +270,7 @@
     maxit = 1;
     max_iter_number = min (size_b, 10);
   elseif (restart <= 0) || (maxit <= 0)
-    error ("gmres: MAXIT and RESTART must be positive integers")
+    error ("gmres: MAXIT and RESTART must be positive integers");
   elseif (restart < size_b) && (empty_maxit)
     maxit = min (size_b / restart, 10);
     max_iter_number = maxit * restart;
@@ -278,7 +278,7 @@
     maxit = 1;
     max_iter_number = min (size_b, 10);
   elseif (restart > size_b) && (empty_maxit)
-    warning ("RESTART is %d but it should be bounded by SIZE(A,2).\n Setting restart to %d. \n", restart, size_b)
+    warning ("RESTART is %d but it should be bounded by SIZE(A,2).\n Setting restart to %d. \n", restart, size_b);
     restart = size_b;
     maxit = 1;
     max_iter_number = restart;
@@ -290,8 +290,8 @@
     restart = size_b;
     maxit = size_b;
     max_iter_number = size_b;
-  elseif (restart > size_b) && (!empty_maxit)
-    warning ("RESTART is %d but it should be bounded by SIZE(A,2).\n Setting restart to %d. \n", restart, size_b)
+  elseif (restart > size_b) && (! empty_maxit)
+    warning ("RESTART is %d but it should be bounded by SIZE(A,2).\n Setting restart to %d. \n", restart, size_b);
     restart = size_b;
     max_iter_number = restart * maxit;
   elseif (restart == size_b) && (maxit <= size_b)
@@ -303,14 +303,14 @@
   prec_b_norm = norm (b, 2);
   if (prec_b_norm == 0)
     if (nargout < 2)
-      printf("The right hand side vector is all zero so gmres\nreturned an all zero solution without iterating.\n")
+      printf ("The right hand side vector is all zero so gmres\nreturned an all zero solution without iterating.\n")
     endif
     x_min = b;
     flag = 0;
     relres = 0;
     resvec = 0;
     it = [0, 0];
-    return
+    return;
   endif
 
   ## gmres: function handle case
@@ -324,14 +324,14 @@
   iter_min = 0; # iteration with minimum residual
   outer_it = 1; # number of outer iterations
   restart_it  =  1; # number of inner iterations
-  it = zeros(1, 2);
+  it = zeros (1, 2);
   resvec = zeros (max_iter_number + 1, 1);
   flag = 1; # Default flag is maximum # of iterations exceeded
 
   ## begin loop
   u = feval (Afun, x_old, varargin{:});
   try
-    warning("error", "Octave:singular-matrix", "local")
+    warning ("error", "Octave:singular-matrix", "local");
     prec_res = feval (M1fun, b - u, varargin{:}); # M1*(b-u)
     prec_res = feval (M2fun, prec_res, varargin{:});
     presn = norm (prec_res, 2);
@@ -401,22 +401,22 @@
   if ((nargout < 2) && (restart != size_b)) # restart applied
     switch (flag)
       case {0} # gmres converged
-        printf ("gmres(%d) converged at outer iteration %d (inner iteration %d) ",restart, it (1), it (2));
+        printf ("gmres (%d) converged at outer iteration %d (inner iteration %d) ",restart, it (1), it (2));
         printf ("to a solution with relative residual %d \n", relres);
       case {1} # max number of iteration reached
-        printf ("gmres(%d) stopped at outer iteration %d (inner iteration %d) ", restart, outer_it, restart_it-1);
+        printf ("gmres (%d) stopped at outer iteration %d (inner iteration %d) ", restart, outer_it, restart_it-1);
         printf ("without converging to the desired tolerance %d ", tol);
         printf ("because the maximum number of iterations was reached \n");
         printf ("The iterated returned (number %d(%d)) ", it(1), it(2));
         printf ("has relative residual %d \n", relres);
       case {2} # preconditioner singular
-        printf ("gmres(%d) stopped at outer iteration %d (inner iteration %d) ",restart, outer_it, restart_it-1);
+        printf ("gmres (%d) stopped at outer iteration %d (inner iteration %d) ",restart, outer_it, restart_it-1);
         printf ("without converging to the desired tolerance %d ", tol);
         printf ("because the preconditioner matrix is singular \n");
         printf ("The iterated returned (number %d(%d)) ", it(1), it(2));
         printf ("has relative residual %d \n", relres);
       case {3} # stagnation
-        printf ("gmres(%d) stopped at outer iteration %d (inner iteration %d) ", restart, outer_it, restart_it - 1);
+        printf ("gmres (%d) stopped at outer iteration %d (inner iteration %d) ", restart, outer_it, restart_it - 1);
         printf ("without converging to the desired tolerance %d", tol);
         printf ("because it stagnates. \n");
         printf ("The iterated returned (number %d(%d)) ", it(1), it(2));
@@ -447,8 +447,10 @@
         printf ("has relative residual %d \n", relres);
     endswitch
   endif
+
 endfunction
 
+
 %!demo
 %! dim = 20;
 %! A = spdiags ([-ones(dim,1) 2*ones(dim,1) ones(dim,1)], [-1:1], dim, dim);
@@ -539,7 +541,7 @@
 %! [x, flag] = gmres (A, b, 10, 1e-10, dim, @(x) x ./ diag (A), [], b);
 %! assert (x, A\b, 1e-9*norm (x, Inf));
 %! [x, flag] = gmres (A, b, dim, 1e-10, 1e4, @(x) diag (diag (A)) \ x, [], b);
-%! assert(x, A\b, 1e-7*norm (x, Inf));
+%! assert (x, A\b, 1e-7*norm (x, Inf));
 
 %!test
 %! dim = 100;
@@ -564,14 +566,14 @@
 %! b = sum (A, 2);
 %! [x, flag] = gmres(A, b, [], [], 5);
 %! assert (flag, 0);
-%! assert (x, ones (5, 1), -1e-06)
+%! assert (x, ones (5, 1), -1e-06);
 
 %!test
 %! ## Maximum number of iteration reached
 %! A = hilb (100);
 %! b = sum (A, 2);
 %! [x, flag, relres, iter] = gmres (A, b, [], 1e-14);
-%! assert(flag, 1);
+%! assert (flag, 1);
 
 %!test
 %! ## gmres recognizes that the preconditioner matrix is singular
@@ -580,56 +582,56 @@
 %! I = eye (3);
 %! M = [1 0 0; 0 1 0; 0 0 0]; # the last row is zero
 %! [x, flag] = gmres(@(y) AA * y, bb, [], [], [], @(y) M \ y, @(y) y);
-%! assert (flag, 2)
+%! assert (flag, 2);
 
 %!test
 %! A = rand (4);
 %! A = A' * A;
 %! [x, flag] = gmres (A, zeros (4, 1), [], [], [], [], [], ones (4, 1));
-%! assert (x, zeros (4, 1))
+%! assert (x, zeros (4, 1));
 
 %!test
 %! A = rand (4);
 %! b = zeros (4, 1);
 %! [x, flag, relres, iter] = gmres (A, b);
-%! assert (relres, 0)
+%! assert (relres, 0);
 
 %!test
 %! A = toeplitz (sparse ([2, 1, 0, 0, 0]), sparse ([2, -1, 0, 0, 0]));
 %! b = A * ones (5, 1);
 %! [x, flag, relres, iter] = gmres (A, b, [], [], [], [], [], ...
 %! ones (5, 1) + 1e-8);
-%! assert (iter, [0, 0])
+%! assert (iter, [0, 0]);
 
 %!test
 %! A = rand (20);
 %! b = A * ones (20, 1);
 %! [x, flag, relres, iter, resvec] = gmres (A, b, [], [], 1);
-%! assert (iter, [1, 1])
+%! assert (iter, [1, 1]);
 
 %!test
 %! A = hilb (20);
 %! b = A * ones (20, 1);
 %! [x, flag, relres, iter, resvec] = gmres (A, b ,5, 1e-14);
-%! assert (iter, [4, 5])
+%! assert (iter, [4, 5]);
 
 %!test
 %! A = single (1);
 %! b = 1;
 %! [x, flag] = gmres (A, b);
-%! assert (class (x), "single")
+%! assert (class (x), "single");
 
 %!test
 %! A = 1;
 %! b = single (1);
 %! [x, flag] = gmres (A, b);
-%! assert (class (x), "single")
+%! assert (class (x), "single");
 
 %!test
 %! A = single (1);
 %! b = single (1);
 %! [x, flag] = gmres (A, b);
-%! assert (class (x), "single")
+%! assert (class (x), "single");
 
 %!test
 %!function y = Afun (x)
@@ -637,11 +639,11 @@
 %!   y = A * x;
 %!endfunction
 %! [x, flag] = gmres ("Afun", [1; 2; 2; 3]);
-%! assert (x, ones(4, 1), 1e-6)
+%! assert (x, ones (4, 1), 1e-6);
 
 %!test # preconditioned residual
 %! A = toeplitz (sparse ([2, 1, 0, 0, 0]), sparse ([2, -1, 0, 0, 0]));
 %! b = sum (A, 2);
 %! M = magic (5);
 %! [x, flag, relres] = gmres (A, b, [], [], 2, M);
-%! assert (relres, norm (M \ (b - A * x)) / norm (M \ b), 8 * eps)
+%! assert (relres, norm (M \ (b - A * x)) / norm (M \ b), 8 * eps);
--- a/scripts/sparse/gplot.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/gplot.m	Thu Nov 19 13:08:00 2020 -0800
@@ -40,7 +40,7 @@
 
 function [x, y] = gplot (A, xy, line_style)
 
-  if (nargin < 2 || nargin > 3 || nargout > 2)
+  if (nargin < 2)
     print_usage ();
   endif
 
--- a/scripts/sparse/ichol.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/ichol.m	Thu Nov 19 13:08:00 2020 -0800
@@ -160,7 +160,7 @@
 
 function L = ichol (A, opts = struct ())
 
-  if (nargin < 1 || nargin > 2 || nargout > 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -169,7 +169,7 @@
   endif
 
   if (! isstruct (opts))
-    error ("ichol: OPTS must be a structure.");
+    error ("ichol: OPTS must be a structure");
   endif
 
   ## If A is empty then return empty L for Matlab compatibility
--- a/scripts/sparse/ilu.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/ilu.m	Thu Nov 19 13:08:00 2020 -0800
@@ -168,7 +168,7 @@
 
 function [L, U, P] = ilu (A, opts = struct ())
 
-  if (nargin < 1 || nargin > 2 || (nargout > 3))
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -177,7 +177,7 @@
   endif
 
   if (! isstruct (opts))
-    error ("ilu: OPTS must be a structure.");
+    error ("ilu: OPTS must be a structure");
   endif
 
   ## If A is empty then return empty L, U and P for Matlab compatibility
@@ -507,7 +507,7 @@
 %! A = sparse (magic (4));
 %! opts.type = "ilutp";
 %! [L, U] = ilu (A, opts);
-%! assert (L * U, A, eps)
+%! assert (L * U, A, eps);
 
 ## Tests for input validation
 %!shared A_tiny, opts
--- a/scripts/sparse/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -8,6 +8,7 @@
   %reldir%/private/__sprand__.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/bicg.m \
   %reldir%/bicgstab.m \
   %reldir%/cgs.m \
--- a/scripts/sparse/nonzeros.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/nonzeros.m	Thu Nov 19 13:08:00 2020 -0800
@@ -31,7 +31,7 @@
 
 function v = nonzeros (A)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -52,5 +52,4 @@
 %!assert (nonzeros (sparse ([1,2,3,0])), [1;2;3])
 
 ## Test input validation
-%!error nonzeros ()
-%!error nonzeros (1, 2)
+%!error <Invalid call> nonzeros ()
--- a/scripts/sparse/pcg.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/pcg.m	Thu Nov 19 13:08:00 2020 -0800
@@ -284,7 +284,7 @@
   b_norm = norm (b);
   if (b_norm == 0)
      if (n_arg_out < 2)
-       printf("The right hand side vector is all zero so pcg \n");
+       printf ("The right hand side vector is all zero so pcg \n");
        printf ("returned an all zero solution without iterating.\n");
      endif
      x_min = b;
@@ -293,7 +293,7 @@
      resvec = 0;
      iter_min = 0;
      eigest = [NaN, NaN];
-     return
+     return;
   endif
 
   x = x_pr = x_min = x0;
@@ -319,7 +319,7 @@
   while (resvec(iter-1,1) > tol * b_norm && iter < maxit)
     if (iter == 2) # Check whether M1 or M2 are singular
       try
-        warning ("error","Octave:singular-matrix","local")
+        warning ("error","Octave:singular-matrix","local");
         z = feval (M1fun, r, varargin{:});
         z = feval (M2fun, z, varargin{:});
       catch
@@ -395,7 +395,7 @@
       endif
     else
       eigest = [NaN, NaN];
-      warning ('pcg: eigenvalue estimate failed: matrix not positive definite?')
+      warning ('pcg: eigenvalue estimate failed: matrix not positive definite?');
     endif
     resvec(iter - 1, 2) = sqrt (r' * z);
     resvec  = resvec (1:(iter-1), :);
@@ -454,6 +454,7 @@
         printf ("has relative residual %d \n", relres);
     endswitch
   endif
+
 endfunction
 
 
--- a/scripts/sparse/pcr.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/pcr.m	Thu Nov 19 13:08:00 2020 -0800
@@ -334,7 +334,7 @@
 %! printf ("The solution relative error is %g\n", norm (x-X) / norm (X));
 %! clf;
 %! title ("Convergence history");
-%! xlabel ("Iteration"); ylabel ("log(||b-Ax||/||b||)");
+%! xlabel ("Iteration"); ylabel ("log (||b-Ax||/||b||)");
 %! semilogy ([0:iter], resvec/resvec(1), "o-g;relative residual;");
 
 %!demo
@@ -354,13 +354,13 @@
 %! endif
 %! clf;
 %! title ("Convergence history");
-%! xlabel ("Iteration"); ylabel ("log(||b-Ax||)");
+%! xlabel ("Iteration"); ylabel ("log (||b-Ax||)");
 %! semilogy ([0:iter], resvec, "o-g;absolute residual;");
 
 %!demo
 %! ## Full output from PCR
 %! ## We use an indefinite matrix based on the 1-D Laplacian matrix for A,
-%! ## and here we have cond(A) = O(N^2)
+%! ## and here we have cond (A) = O(N^2)
 %! ## That's the reason we need some preconditioner; here we take
 %! ## a very simple and not powerful Jacobi preconditioner,
 %! ## which is the diagonal of A.
@@ -383,7 +383,7 @@
 %! [x, flag, relres, iter, resvec] = pcr (A,b,[],maxit);
 %! clf;
 %! title ("Convergence history");
-%! xlabel ("Iteration"); ylabel ("log(||b-Ax||)");
+%! xlabel ("Iteration"); ylabel ("log (||b-Ax||)");
 %! semilogy ([0:iter], resvec, "o-g;NO preconditioning: absolute residual;");
 %!
 %! pause (1);
@@ -445,7 +445,7 @@
 %! b = ones (N,1);
 %! X = A \ b;  # X is the true solution
 %! [x, flag, relres, iter] = pcr (A,b,[],[],A,b);
-%! assert (norm (x-X) / norm(X) < 1e-6);
+%! assert (norm (x-X) / norm (X) < 1e-6);
 %! assert (relres < 1e-6);
 %! assert (flag, 0);
 %! assert (iter, 1); # should converge in one iteration
--- a/scripts/sparse/private/__alltohandles__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/private/__alltohandles__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -64,47 +64,65 @@
      Afun = A;
   elseif (ischar (A))
     Afun = str2func (A);
-  elseif (!isnumeric (A) || !issquare (A))
-    error([solver_name, ": A must be a square matrix or a function handle"])
+  elseif (! isnumeric (A) || ! issquare (A))
+    error ([solver_name, ": A must be a square matrix or a function handle"]);
   else
     A_is_numeric = true;
     if (size (A, 2) != size (b, 1))
-      error ("__alltohandles__: dimension of b is not consistent with A")
+      error ("__alltohandles__: dimension of B is not consistent with A");
     endif
   endif
 
   ## Check M1 and sets its type
   if (isempty (M1)) # M1 empty, set to identity function
-      M1fun = @(x) x;
+    switch (solver_name)
+      case {"pcg", "gmres", "bicgstab", "cgs", "tfqmr"}
+        ## methods which do not require the transpose
+        M1fun = @(x) x;
+      case {"bicg"}
+        ## methods which do require the transpose
+        M1fun = @(x, ~) x;
+      otherwise
+        error (["__alltohandles__: unknown method: ", solver_name]);
+    endswitch
   else # M1 not empty
     if (is_function_handle (M1))
       M1fun = M1;
     elseif (ischar (M1))
       M1fun = str2func (M1);
-    elseif (!isnumeric (M1) || !issquare (M1))
-      error([solver_name, ": M1 must be a square matrix or a function handle"])
+    elseif (! isnumeric (M1) || ! issquare (M1))
+      error ([solver_name, ": M1 must be a square matrix or a function handle"]);
     else
       M1_is_numeric = true;
     endif
   endif
 
   if (isempty (M2)) # M2 empty, then I set is to the identity function
-    M2fun = @(x) x;
+    switch (solver_name)
+      case {"pcg", "gmres", "bicgstab", "cgs", "tfqmr"}
+        ## methods which do not require the transpose
+        M2fun = @(x) x;
+      case {"bicg"}
+        ## methods which do require the transpose
+        M2fun = @(x, ~) x;
+      otherwise
+        error (["__alltohandles__: unknown method: ", solver_name]);
+    endswitch
   else # M2 not empty
     if (is_function_handle (M2))
       M2fun = M2;
     elseif (ischar (M2))
       M2fun = str2func (M2);
-    elseif (!isnumeric (M2) || !issquare (M2))
-      error([solver_name, ": M2 must be a square matrix or a function handle"])
+    elseif (! isnumeric (M2) || ! issquare (M2))
+      error ([solver_name, ": M2 must be a square matrix or a function handle"]);
     else
       M2_is_numeric = true;
     endif
   endif
 
-  switch solver_name
+  switch (solver_name)
     case {"pcg", "gmres", "bicgstab", "cgs", "tfqmr"}
-      # methods which do not require the transpose
+      ## methods which do not require the transpose
       if (A_is_numeric)
         Afun = @(x) A * x;
       endif
@@ -115,7 +133,7 @@
         M2fun = @(x) M2 \ x;
       endif
     case {"bicg"}
-      # methods which do require the transpose
+      ## methods which do require the transpose
       if (A_is_numeric)
         Afun = @(x, trans) A_sub (A, x, trans);
       endif
@@ -128,6 +146,7 @@
     otherwise
       error (["__alltohandles__: unknown method: ", solver_name]);
   endswitch
+
 endfunction
 
 function y = A_sub (A, x, trans)
--- a/scripts/sparse/private/__default__input__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/private/__default__input__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -34,31 +34,39 @@
 ## @item @var{def_val} is a cell array that contains the values to use
 ## as default.
 ##
-## @item @var{varargin} are the input arguments
+## @item @var{varargin} are the input arguments.
 ## @end itemize
 ##
 ## The output arguments are:
 ##
 ## @itemize @minus
-## @item @var{varargout} all input arguments completed with default
-## values for empty or omitted parameters.
+## @item @var{varargout} are the input arguments where any empty or omitted
+## parameters have been replaced with default values.
 ##
 ## @end itemize
 ##
 ## @end deftypefn
 
-
-function [varargout] = __default__input__ (def_val, varargin)
+function varargout = __default__input__ (def_val, varargin)
 
-  m = length (def_val);
-  n = length (varargin);
+  m = numel (def_val);
+  n = numel (varargin);
+  count = min (m, n);
 
-  for i = 1:m
-    if (n < i || isempty (varargin{i}))
+  ## Check for missing values in input and replace with default value.
+  for i = 1:count
+    if (isempty (varargin{i}))
       varargout{i} = def_val{i};
     else
       varargout{i} = varargin{i};
     endif
   endfor
 
+  ## Copy any remaining items to output
+  if (n < m)
+    varargout(n+1:m) = def_val(n+1:m);
+  elseif (m < n)
+    varargout(m+1:n) = varargin(m+1:n);
+  endif
+
 endfunction
--- a/scripts/sparse/private/__sprand__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/private/__sprand__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -117,7 +117,7 @@
       else
         ## Only the min (m, n) greater singular values from rc vector are used.
         if (length (rc) > min (m,n))
-          rc = rc(1:min(m, n));
+          rc = rc(1:min (m, n));
         endif
         S = sparse (diag (sort (rc, "descend"), m, n));
       endif
--- a/scripts/sparse/qmr.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/qmr.m	Thu Nov 19 13:08:00 2020 -0800
@@ -206,13 +206,13 @@
       vt = pt - beta1 * v;
 
       y = M1m1x (vt);
-      rho1 = norm(y);
+      rho1 = norm (y);
       wt = Atx (q) - beta1 * w;
       z = M2tm1x (wt);
 
-      xi1 = norm(z);
-      theta1 = rho1 / (gamma0 * abs(beta1));
-      gamma1 = 1 / sqrt(1 + theta1^2);   # If gamma1 == 0, method fails.
+      xi1 = norm (z);
+      theta1 = rho1 / (gamma0 * abs (beta1));
+      gamma1 = 1 / sqrt (1 + theta1^2);   # If gamma1 == 0, method fails.
       eta1 = -eta0 * rho0 * gamma1^2 / (beta1 * gamma0^2);
 
       if (iter == 1)
@@ -267,7 +267,7 @@
       printf ("to a solution with relative residual %e\n", res1);
     endif
   else
-    print_usage();
+    print_usage ();
   endif
 
 endfunction
--- a/scripts/sparse/spconvert.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/spconvert.m	Thu Nov 19 13:08:00 2020 -0800
@@ -37,7 +37,7 @@
 
 function s = spconvert (m)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -73,8 +73,7 @@
 %! assert (size (spconvert ([1, 1, 3; 5, 15, 0])), [5, 15]);
 
 ## Test input validation
-%!error spconvert ()
-%!error spconvert (1, 2)
+%!error <Invalid call> spconvert ()
 %!error spconvert ({[1 2 3]})
 %!error spconvert ([1 2])
 %!error spconvert ([1 2 3i])
--- a/scripts/sparse/spdiags.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/spdiags.m	Thu Nov 19 13:08:00 2020 -0800
@@ -64,7 +64,7 @@
 
 function [B, d] = spdiags (v, d, m, n)
 
-  if (nargin < 1 || nargin > 4)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -178,5 +178,4 @@
 %!assert (spdiags ([0.5 -1 0.5], 0:2, 1, 1), sparse (0.5))
 
 ## Test input validation
-%!error spdiags ()
-%!error spdiags (1,2,3,4,5)
+%!error <Invalid call> spdiags ()
--- a/scripts/sparse/spones.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/spones.m	Thu Nov 19 13:08:00 2020 -0800
@@ -33,7 +33,7 @@
 
 function r = spones (S)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/sparse/sprand.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/sprand.m	Thu Nov 19 13:08:00 2020 -0800
@@ -49,9 +49,9 @@
 
 function s = sprand (m, n, d, rc)
 
-  if (nargin == 1 )
+  if (nargin == 1)
     s = __sprand__ (m, @rand);
-  elseif ( nargin == 3)
+  elseif (nargin == 3)
     s = __sprand__ (m, n, d, "sprand", @rand);
   elseif (nargin == 4)
     s = __sprand__ (m, n, d, rc, "sprand", @rand);
@@ -99,9 +99,8 @@
 %!assert (size (sprand (3, 0, 0.5)), [3, 0])
 
 ## Test input validation
-%!error sprand ()
-%!error sprand (1, 2)
-%!error sprand (1, 2, 3, 4)
+%!error <Invalid call> sprand ()
+%!error <Invalid call> sprand (1, 2)
 %!error <M must be a non-negative integer> sprand (-1, -1, 0.5)
 %!error <M must be a non-negative integer> sprand (ones (3), 3, 0.5)
 %!error <M must be a non-negative integer> sprand (3.5, 3, 0.5)
--- a/scripts/sparse/sprandn.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/sprandn.m	Thu Nov 19 13:08:00 2020 -0800
@@ -49,9 +49,9 @@
 
 function s = sprandn (m, n, d, rc)
 
-  if (nargin == 1 )
+  if (nargin == 1)
     s = __sprand__ (m, @randn);
-  elseif ( nargin == 3)
+  elseif (nargin == 3)
     s = __sprand__ (m, n, d, "sprandn", @randn);
   elseif (nargin == 4)
     s = __sprand__ (m, n, d, rc, "sprandn", @randn);
@@ -98,9 +98,8 @@
 %!assert (size (sprandn (3, 0, 0.5)), [3, 0])
 
 ## Test input validation
-%!error sprandn ()
-%!error sprandn (1, 2)
-%!error sprandn (1, 2, 3, 4)
+%!error <Invalid call> sprandn ()
+%!error <Invalid call> sprandn (1, 2)
 %!error <M must be a non-negative integer> sprand (-1, -1, 0.5)
 %!error <M must be a non-negative integer> sprandn (ones (3), 3, 0.5)
 %!error <M must be a non-negative integer> sprandn (3.5, 3, 0.5)
--- a/scripts/sparse/sprandsym.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/sprandsym.m	Thu Nov 19 13:08:00 2020 -0800
@@ -39,7 +39,7 @@
 
 function S = sprandsym (n, d)
 
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -181,8 +181,7 @@
 %!assert (size (sprandsym (0, 0.5)), [0, 0])
 
 ## Test input validation
-%!error sprandsym ()
-%!error sprandsym (1, 2, 3)
+%!error <Invalid call> sprandsym ()
 %!error sprandsym (ones (3), 0.5)
 %!error sprandsym (3.5, 0.5)
 %!error sprandsym (-1, 0.5)
--- a/scripts/sparse/spstats.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/spstats.m	Thu Nov 19 13:08:00 2020 -0800
@@ -40,7 +40,7 @@
 
 function [count, mean, var] = spstats (S, j)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/sparse/spy.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/spy.m	Thu Nov 19 13:08:00 2020 -0800
@@ -29,17 +29,17 @@
 ## @deftypefnx {} {} spy (@dots{}, @var{line_spec})
 ## Plot the sparsity pattern of the sparse matrix @var{x}.
 ##
-## If the argument @var{markersize} is given as a scalar value, it is used to
-## determine the point size in the plot.
+## If the optional numeric argument @var{markersize} is given, it determines
+## the size of the markers used in the plot.
 ##
-## If the string @var{line_spec} is given it is passed to @code{plot} and
-## determines the appearance of the plot.
+## If the optional string @var{line_spec} is given it is passed to @code{plot}
+## and determines the appearance of the plot.
 ## @seealso{plot, gplot}
 ## @end deftypefn
 
 function spy (x, varargin)
 
-  if (nargin < 1)
+  if (nargin < 1 || nargin > 3)
     print_usage ();
   endif
 
@@ -49,21 +49,22 @@
   else
     line_spec = ".";
   endif
-  for i = 1:length (varargin)
-    if (ischar (varargin{i}))
-      if (length (varargin{i}) == 1)
-        line_spec = [line_spec, varargin{i}];
+  for arg = varargin
+    arg = arg{1};
+    if (ischar (arg))
+      if (numel (arg) == 1)
+        line_spec = [line_spec, arg];
       else
-        line_spec = varargin{i};
+        line_spec = arg;
       endif
-    elseif (isscalar (varargin{i}))
-      markersize = varargin{i};
+    elseif (isreal (arg) && isscalar (arg))
+      markersize = arg;
     else
       error ("spy: expected markersize or linespec");
     endif
   endfor
 
-  [i, j, s] = find (x);
+  [i, j] = find (x);
   [m, n] = size (x);
 
   if (isnan (markersize))
@@ -73,6 +74,7 @@
   endif
 
   axis ([0, n+1, 0, m+1], "ij");
+  xlabel (sprintf ("nnz = %d", nnz (x)));
 
 endfunction
 
@@ -81,5 +83,6 @@
 %! clf;
 %! spy (sprand (10,10, 0.2));
 
-## Mark graphical function as tested by demo block
-%!assert (1)
+## Test input validation
+%!error <Invalid call> spy ()
+%!error <Invalid call> spy (1,2,3,4)
--- a/scripts/sparse/svds.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/svds.m	Thu Nov 19 13:08:00 2020 -0800
@@ -102,7 +102,7 @@
 
   persistent root2 = sqrt (2);
 
-  if (nargin < 1 || nargin > 4)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/sparse/tfqmr.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/tfqmr.m	Thu Nov 19 13:08:00 2020 -0800
@@ -217,7 +217,7 @@
   norm_b = norm (b, 2);
   if (norm_b == 0)
     if (nargout < 2)
-      printf("The right hand side vector is all zero so tfqmr \n")
+      printf ("The right hand side vector is all zero so tfqmr \n")
       printf ("returned an all zero solution without iterating.\n")
     endif
     x_min = zeros (numel (b), 1);
@@ -225,7 +225,7 @@
     flag = 0;
     resvec = 0;
     relres = 0;
-    return
+    return;
   endif
 
   x = x_pr = x_min = x0;
@@ -242,7 +242,7 @@
   it = 1;
 
   try
-    warning("error", "Octave:singular-matrix", "local");
+    warning ("error", "Octave:singular-matrix", "local");
     u_hat = feval (M1fun, u, varargin{:});
     u_hat = feval (M2fun, u_hat, varargin{:});
     v = feval (Afun, u_hat, varargin{:});
@@ -257,7 +257,7 @@
         ## Essentially the next iteration doesn't change x,
         ## and the iter after this will have a division by zero
         flag = 4;
-        break
+        break;
       endif
       alpha = rho_1 / v_r;
       u_1 = u - alpha * v;  # u at the after iteration
@@ -279,7 +279,7 @@
         ## Essentially the next iteration doesn't change x,
         ## and the iter after this will have a division by zero
         flag = 4;
-        break
+        break;
       endif
       beta = rho_1 / rho_2;
       u_1 = w + beta * u; # u at the after iteration
@@ -298,7 +298,7 @@
     endif
     if (norm (x_pr - x) <= norm (x) * eps)
       flag = 3; # Stagnation
-      break
+      break;
     endif
     x_pr = x;
     it = -it;
@@ -306,8 +306,8 @@
   resvec = resvec (1: (iter + 1));
 
   relres = resvec (iter_min + 1) / norm (b);
-  iter_min = floor(iter_min / 2); # compatibility, since it
-                                  # makes two times the effective iterations
+  iter_min = floor (iter_min / 2); # compatibility, since it
+                                   # makes two times the effective iterations
 
   if (relres <= tol)
     flag = 0;
@@ -344,7 +344,10 @@
         printf ("has relative residual %e\n", relres);
     endswitch
   endif
+
 endfunction
+
+
 %!test
 %! ## Check that all type of inputs work
 %! A = toeplitz (sparse ([2, 1, 0, 0, 0]), sparse ([2, -1, 0, 0, 0]));
@@ -428,46 +431,46 @@
 %! A (1,50) = 10000;
 %! b = ones (50,1);
 %! [x, flag, relres, iter, resvec] = tfqmr (A, b, [], 100);
-%! assert (flag, 0)
-%! assert (x, A \ b, 1e-05)
+%! assert (flag, 0);
+%! assert (x, A \ b, 1e-05);
 %! ## Detects a singular preconditioner
 %! M = ones (50);
 %! M(1, 1) = 0;
 %! [x, flag] = tfqmr (A, b, [], 100, M);
-%! assert (flag, 2)
+%! assert (flag, 2);
 
 %!test
 %! A = single (1);
 %! b = 1;
 %! [x, flag] = tfqmr (A, b);
-%! assert (class (x), "single")
+%! assert (class (x), "single");
 
 %!test
 %! A = 1;
 %! b = single (1);
 %! [x, flag] = tfqmr (A, b);
-%! assert (class (x), "single")
+%! assert (class (x), "single");
 
 %!test
 %! A = single (1);
 %! b = single (1);
 %! [x, flag] = tfqmr (A, b);
-%! assert (class (x), "single")
+%! assert (class (x), "single");
 
 %!test
 %!function y = Afun (x)
-%!   A = toeplitz ([2, 1, 0, 0], [2, -1, 0, 0]);
-%!   y = A * x;
+%!  A = toeplitz ([2, 1, 0, 0], [2, -1, 0, 0]);
+%!  y = A * x;
 %!endfunction
 %! [x, flag] = tfqmr ("Afun", [1; 2; 2; 3]);
-%! assert (x, ones(4, 1), 1e-6)
+%! assert (x, ones (4, 1), 1e-6);
 
 %!test # unpreconditioned residual
 %! A = toeplitz (sparse ([2, 1, 0, 0, 0]), sparse ([2, -1, 0, 0, 0]));
 %! b = sum (A, 2);
 %! M = magic (5);
 %! [x, flag, relres] = tfqmr (A, b, [], 3, M);
-%! assert (relres, norm (b - A * x) / norm (b), 8 * eps)
+%! assert (relres, norm (b - A * x) / norm (b), 8 * eps);
 
 %!demo # simplest use
 %! n = 20;
--- a/scripts/sparse/treelayout.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/treelayout.m	Thu Nov 19 13:08:00 2020 -0800
@@ -40,7 +40,7 @@
 function [x_coordinate, y_coordinate, height, s] = ...
                                                  treelayout (tree, permutation)
 
-  if (nargin < 1 || nargin > 2 || nargout > 4)
+  if (nargin < 1)
     print_usage ();
   elseif (! isvector (tree) || rows (tree) != 1 || ! isnumeric (tree)
           || any (tree > length (tree)) || any (tree < 0))
@@ -72,7 +72,7 @@
 
       if (hare < i)
         ## This part of graph was checked before.
-        break
+        break;
       endif
 
       tortoise = tree(tortoise);
--- a/scripts/sparse/treeplot.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/sparse/treeplot.m	Thu Nov 19 13:08:00 2020 -0800
@@ -40,7 +40,7 @@
 
 function treeplot (tree, node_style = "ko", edge_style = "r")
 
-  if (nargin < 1 || nargin > 3 || nargout > 0)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/specfun/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/specfun/beta.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/specfun/beta.m	Thu Nov 19 13:08:00 2020 -0800
@@ -43,8 +43,8 @@
 ##
 ## The Beta function can grow quite large and it is often more useful to work
 ## with the logarithm of the output rather than the function directly.
-## @xref{XREFbetaln,,betaln}, for computing the logarithm of the Beta function
-## in an efficient manner.
+## @xref{XREFbetaln,,@code{betaln}}, for computing the logarithm of the Beta
+## function in an efficient manner.
 ## @seealso{betaln, betainc, betaincinv}
 ## @end deftypefn
 
@@ -88,9 +88,8 @@
 %! assert (zeros (size (a)), beta (a, -a), tol);
 %! assert (zeros (size (a)), beta (-a, a), tol);
 
-%!error beta ()
-%!error beta (1)
-%!error beta (1,2,3)
+%!error <Invalid call> beta ()
+%!error <Invalid call> beta (1)
 %!error <A and B must be real> beta (1i, 2)
 %!error <A and B must be real> beta (2, 1i)
 %!error <A and B must have consistent sizes> beta ([1 2], [1 2 3])
--- a/scripts/specfun/betainc.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/specfun/betainc.m	Thu Nov 19 13:08:00 2020 -0800
@@ -9,7 +9,7 @@
 ##
 ## Octave is free software: you can redistribute it and/or modify it
 ## under the terms of the GNU General Public License as published by
-## the Free Software Foundation; either version 3 of the License, or
+## the Free Software Foundation, either version 3 of the License, or
 ## (at your option) any later version.
 ##
 ## Octave is distributed in the hope that it will be useful, but
@@ -74,7 +74,7 @@
 
 function y = betainc (x, a, b, tail = "lower")
 
-  if (nargin < 3 || nargin > 4)
+  if (nargin < 3)
     print_usage ();
   endif
 
@@ -205,12 +205,12 @@
 %! y_ex = [0.999999999999989; 0.999999999999992; 0.999999999999995];
 %! assert (y, y_ex, -1e-14);
 
-%!assert (betainc (0.001, 20, 30), 2.750687665855991e-47, -3e-14);
-%!assert (betainc (0.0001, 20, 30), 2.819953178893307e-67, -7e-14);
-%!assert <*54383> (betainc (0.99, 20, 30, "upper"), 1.5671643161872703e-47, -7e-14);
-%!assert (betainc (0.999, 20, 30, "upper"), 1.850806276141535e-77, -7e-14);
-%!assert (betainc (0.5, 200, 300), 0.9999964565197356, -1e-15);
-%!assert (betainc (0.5, 200, 300, "upper"), 3.54348026439253e-06, -3e-13);
+%!assert (betainc (0.001, 20, 30), 2.750687665855991e-47, -3e-14)
+%!assert (betainc (0.0001, 20, 30), 2.819953178893307e-67, -7e-14)
+%!assert <*54383> (betainc (0.99, 20, 30, "upper"), 1.5671643161872703e-47, -7e-14)
+%!assert (betainc (0.999, 20, 30, "upper"), 1.850806276141535e-77, -7e-14)
+%!assert (betainc (0.5, 200, 300), 0.9999964565197356, -1e-15)
+%!assert (betainc (0.5, 200, 300, "upper"), 3.54348026439253e-06, -3e-13)
 
 ## Test trivial values
 %!test
@@ -223,10 +223,9 @@
 %! assert (betainc (0.5, 1, Inf), NaN);
 
 ## Test input validation
-%!error betainc ()
-%!error betainc (1)
-%!error betainc (1,2)
-%!error betainc (1,2,3,4,5)
+%!error <Invalid call> betainc ()
+%!error <Invalid call> betainc (1)
+%!error <Invalid call> betainc (1,2)
 %!error <must be of common size or scalars> betainc (ones (2,2), ones (1,2), 1)
 %!error <all inputs must be real> betainc (0.5i, 1, 2)
 %!error <all inputs must be real> betainc (0, 1i, 1)
--- a/scripts/specfun/betaincinv.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/specfun/betaincinv.m	Thu Nov 19 13:08:00 2020 -0800
@@ -84,7 +84,7 @@
 
 function x = betaincinv (y, a, b, tail = "lower")
 
-  if (nargin < 3 || nargin > 4)
+  if (nargin < 3)
     print_usage ();
   endif
 
@@ -155,7 +155,7 @@
     x(y == 0) = 1;
     x(y == 1) = 0;
   else
-    error ("betaincinv: invalid value for TAIL")
+    error ("betaincinv: invalid value for TAIL");
   endif
 
   ## Special values have been already computed.
@@ -207,6 +207,7 @@
 
 ## subfunctions: Bisection and Newton Methods
 function xc = bisection_method (F, xl, xr, a, b, y, maxit)
+
   F_l = F (xl, a, b, y);
   F_r = F (xr, a, b, y);
   for it = 1:maxit
@@ -222,12 +223,14 @@
     F_r(flag_r) = F_c(flag_r);
     F_l(flag_c) = F_r(flag_c) = 0;
   endfor
+
 endfunction
 
 function x = newton_method (F, JF, x0, a, b, y, tol, maxit);
+
   l = numel (y);
   res = -F (x0, a, b, y) ./ JF (x0, a, b);
-  todo = (abs(res) >= tol * abs (x0));
+  todo = (abs (res) >= tol * abs (x0));
   x = x0;
   it = 0;
   while (any (todo) && (it < maxit))
@@ -235,9 +238,10 @@
     x(todo) += res(todo);
     res(todo) = -F(x(todo), a(todo), b(todo), y(todo)) ...
                 ./ JF (x(todo), a(todo), b(todo));
-    todo = (abs(res) >= tol * abs (x));
+    todo = (abs (res) >= tol * abs (x));
   endwhile
   x += res;
+
 endfunction
 
 
@@ -279,10 +283,9 @@
 %!assert (class (betaincinv (single (0.5), int8 (1), 1)), "single")
 
 ## Test input validation
-%!error betaincinv ()
-%!error betaincinv (1)
-%!error betaincinv (1,2)
-%!error betaincinv (1,2,3,4,5)
+%!error <Invalid call> betaincinv ()
+%!error <Invalid call> betaincinv (1)
+%!error <Invalid call> betaincinv (1,2)
 %!error <must be of common size or scalars>
 %! betaincinv (ones (2,2), ones (1,2), 1);
 %!error <all inputs must be real> betaincinv (0.5i, 1, 2)
--- a/scripts/specfun/betaln.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/specfun/betaln.m	Thu Nov 19 13:08:00 2020 -0800
@@ -68,9 +68,8 @@
 %!assert (betaln (3,4), log (beta (3,4)), eps)
 
 ## Test input validation
-%!error betaln ()
-%!error betaln (1)
-%!error betaln (1,2,3)
+%!error <Invalid call> betaln ()
+%!error <Invalid call> betaln (1)
 %!error <A and B must be real> betaln (1i, 2)
 %!error <A and B must be real> betaln (2, 1i)
 %!error <A and B must have consistent sizes> betaln ([1 2], [1 2 3])
--- a/scripts/specfun/cosint.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/specfun/cosint.m	Thu Nov 19 13:08:00 2020 -0800
@@ -76,7 +76,7 @@
 
 function y = cosint (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -96,7 +96,7 @@
     x = complex (real (x)(:), imag (x)(:));
   else
     x = x(:);
-  end
+  endif
 
   ## Initialize the result
   y = zeros (size (x), class (x));
@@ -106,7 +106,7 @@
 
   ## Special values
   y(x == Inf) = 0;
-  y((x == -Inf) & !signbit (imag (x))) = 1i * pi;
+  y((x == -Inf) & ! signbit (imag (x))) = 1i * pi;
   y((x == -Inf) &  signbit (imag (x))) = -1i * pi;
 
   todo(isinf (x)) = false;
@@ -136,11 +136,11 @@
     xx = complex (real (x)(todo), imag (x)(todo));
   else
     xx = x(todo);
-  end
+  endif
   ssum = - xx .^ 2 / 4; # First term of the series expansion
   ## FIXME: This is way more precision than a double value can hold.
   gma = 0.57721566490153286060651209008; # Euler gamma constant
-  yy = gma + log (complex (xx)) + ssum;  # log(complex(...) handles signed zero
+  yy = gma + log (complex (xx)) + ssum;  # log (complex (...) handles signed zero
   flag_sum = true (nnz (todo), 1);
   it = 0;
   maxit = 300;
@@ -161,7 +161,7 @@
 endfunction
 
 
-%!assert (cosint (1.1), 0.38487337742465081550, 2 * eps);
+%!assert (cosint (1.1), 0.38487337742465081550, 2 * eps)
 
 %!test
 %! x = [2, 3, pi; exp(1), 5, 6];
@@ -267,6 +267,5 @@
 %#!test <*52953>
 
 ## Test input validation
-%!error cosint ()
-%!error cosint (1,2)
+%!error <Invalid call> cosint ()
 %!error <X must be numeric> cosint ("1")
--- a/scripts/specfun/ellipke.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/specfun/ellipke.m	Thu Nov 19 13:08:00 2020 -0800
@@ -90,7 +90,7 @@
 
 function [k, e] = ellipke (m, tol = [])
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -219,8 +219,7 @@
 %! assert (e, e_exp, 8*eps (e_exp));
 
 ## Test input validation
-%!error ellipke ()
-%!error ellipke (1,2,3)
+%!error <Invalid call> ellipke ()
 %!error <M must be real> ellipke (1i)
 %!error <M must be .= 1> ellipke (2)
 %!error <TOL must be a real scalar . 0> ellipke (1, i)
--- a/scripts/specfun/expint.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/specfun/expint.m	Thu Nov 19 13:08:00 2020 -0800
@@ -96,7 +96,7 @@
 
 function E1 = expint (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -273,6 +273,5 @@
 %!assert (! isreal (expint (-1)))
 
 ## Test input validation
-%!error expint ()
-%!error expint (1,2)
+%!error <Invalid call> expint ()
 %!error <X must be numeric> expint ("1")
--- a/scripts/specfun/factor.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/specfun/factor.m	Thu Nov 19 13:08:00 2020 -0800
@@ -43,7 +43,7 @@
 
 function [pf, n] = factor (q)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -120,8 +120,7 @@
 %! assert (n, double (3));
 
 ## Test input validation
-%!error factor ()
-%!error factor (1,2)
+%!error <Invalid call> factor ()
 %!error <Q must be a real non-negative integer> factor (6i)
 %!error <Q must be a real non-negative integer> factor ([1,2])
 %!error <Q must be a real non-negative integer> factor (1.5)
--- a/scripts/specfun/factorial.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/specfun/factorial.m	Thu Nov 19 13:08:00 2020 -0800
@@ -41,7 +41,7 @@
 
 function x = factorial (n)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   elseif (! isreal (n) || any (n(:) < 0 | n(:) != fix (n(:))))
     error ("factorial: all N must be real non-negative integers");
@@ -53,9 +53,9 @@
   ## This doesn't seem particularly worth copying--for example uint8 would
   ## saturate for n > 5.  If desired, however, the following code could be
   ## uncommented.
-  # if (! isfloat (x))
-  #   x = cast (x, class (n));
-  # endif
+  ## if (! isfloat (x))
+  ##   x = cast (x, class (n));
+  ## endif
 
 endfunction
 
@@ -65,8 +65,7 @@
 %!assert (factorial (70), exp (sum (log (1:70))), -128*eps)
 %!assert (factorial (0), 1)
 
-%!error factorial ()
-%!error factorial (1,2)
+%!error <Invalid call> factorial ()
 %!error <must be real non-negative integers> factorial (2i)
 %!error <must be real non-negative integers> factorial (-3)
 %!error <must be real non-negative integers> factorial (5.5)
--- a/scripts/specfun/gammainc.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/specfun/gammainc.m	Thu Nov 19 13:08:00 2020 -0800
@@ -9,7 +9,7 @@
 ##
 ## Octave is free software: you can redistribute it and/or modify it
 ## under the terms of the GNU General Public License as published by
-## the Free Software Foundation; either version 3 of the License, or
+## the Free Software Foundation, either version 3 of the License, or
 ## (at your option) any later version.
 ##
 ## Octave is distributed in the hope that it will be useful, but
@@ -95,7 +95,7 @@
 
 function y = gammainc (x, a, tail = "lower")
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -299,6 +299,7 @@
 
 ## a == 1.
 function y = gammainc_a1 (x, tail)
+
   if (strcmp (tail, "lower"))
     if (abs (x) < 1/2)
       y = - expm1 (-x);
@@ -316,12 +317,14 @@
   else
     y = 1 ./ x;
   endif
+
 endfunction
 
 ## positive integer a; exp (x) and a! both under 1/eps
 ## uses closed-form expressions for nonnegative integer a
 ## -- http://mathworld.wolfram.com/IncompleteGammaFunction.html.
 function y = gammainc_an (x, a, tail)
+
   y = t = ones (size (x), class (x));
   i = 1;
   while (any (a(:) > i))
@@ -339,12 +342,14 @@
   elseif (strcmp (tail, "scaledupper"))
     y .*= exp (-x) ./ D(x, a);
   endif
+
 endfunction
 
 ## x + 0.25 < a | x < 0 | abs(x) < 1.
 ## Numerical Recipes in Fortran 77 (6.2.5)
 ## series
 function y = gammainc_s (x, a, tail)
+
   if (strcmp (tail, "scaledlower") || strcmp (tail, "scaledupper"))
     y = ones (size (x), class (x));
     term = x ./ (a + 1);
@@ -367,6 +372,7 @@
   elseif (strcmp (tail, "scaledupper"))
     y = 1 ./ D (x,a) - y;
   endif
+
 endfunction
 
 ## x positive and large relative to a
@@ -375,6 +381,7 @@
 ## Lentz's algorithm
 ## __gammainc__ in libinterp/corefcn/__gammainc__.cc
 function y = gammainc_l (x, a, tail)
+
   y = __gammainc__ (x, a);
   if (strcmp (tail,  "lower"))
     y = 1 - y .* D (x, a);
@@ -383,6 +390,7 @@
   elseif (strcmp (tail, "scaledlower"))
     y = 1 ./ D (x, a) - y;
   endif
+
 endfunction
 
 ## Compute exp(-x)*x^a/Gamma(a+1) in a stable way for x and a large.
@@ -391,6 +399,7 @@
 ## SIAM J. Sci. Stat. Comput., 7(3), 1986
 ## which quotes Section 5, Abramowitz&Stegun 6.1.40, 6.1.41.
 function y = D (x, a)
+
   athresh = 10;  # FIXME: can this be better tuned?
   y = zeros (size (x), class (x));
 
@@ -430,7 +439,7 @@
   endif
 
   ii = (x < 0) & (a == fix (a));
-  if (any(ii))  # remove spurious imaginary part.
+  if (any (ii))  # remove spurious imaginary part.
     y(ii) = real (y(ii));
   endif
 
@@ -478,9 +487,9 @@
 %!        -2.9582761911890713293e7-1i * 9.612022339061679758e6, -30*eps)
 %!assert (gammainc (-10, 10, "upper"), -3.112658165341493126871616e7, ...
 %!        -2*eps)
-%!assert (gammainc (-10, 10, "scaledlower"), 0.5128019364747265, -1e-14);
-%!assert (gammainc (-10, 10, "scaledupper"), -0.5128019200000000, -1e-14);
-%!assert (gammainc (200, 201, "upper"), 0.518794309678684497, -2 * eps);
+%!assert (gammainc (-10, 10, "scaledlower"), 0.5128019364747265, -1e-14)
+%!assert (gammainc (-10, 10, "scaledupper"), -0.5128019200000000, -1e-14)
+%!assert (gammainc (200, 201, "upper"), 0.518794309678684497, -2 * eps)
 %!assert (gammainc (200, 201, "scaledupper"),
 %!        18.4904360746560462660798514, -eps)
 ## Here we are very good (no D (x,a)) involved
@@ -566,9 +575,8 @@
 %!assert (class (gammainc (1, int8 (0.5))) == "double")
 
 ## Test input validation
-%!error gammainc ()
-%!error gammainc (1)
-%!error gammainc (1,2,3,4)
+%!error <Invalid call> gammainc ()
+%!error <Invalid call> gammainc (1)
 %!error <must be of common size or scalars> gammainc ([0, 0],[0; 0])
 %!error <must be of common size or scalars> gammainc ([1 2 3], [1 2])
 %!error <all inputs must be real> gammainc (2+i, 1)
--- a/scripts/specfun/gammaincinv.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/specfun/gammaincinv.m	Thu Nov 19 13:08:00 2020 -0800
@@ -9,7 +9,7 @@
 ##
 ## Octave is free software: you can redistribute it and/or modify it
 ## under the terms of the GNU General Public License as published by
-## the Free Software Foundation; either version 3 of the License, or
+## the Free Software Foundation, either version 3 of the License, or
 ## (at your option) any later version.
 ##
 ## Octave is distributed in the hope that it will be useful, but
@@ -87,7 +87,7 @@
 
 function x = gammaincinv (y, a, tail = "lower")
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -148,7 +148,7 @@
     q = y;
     p = 1 - q;
   else
-    error ("gammaincinv: invalid value for TAIL")
+    error ("gammaincinv: invalid value for TAIL");
   endif
 
   todo = (a != 1) & (y != 0) & (y != 1);
@@ -256,6 +256,7 @@
 
 ## subfunction: Newton's Method
 function x = newton_method (F, JF, y, a, x0, tol, maxit);
+
   l = numel (y);
   res = -F (y, a, x0) ./ JF (a, x0);
   todo = (abs (res) >= tol * abs (x0));
@@ -267,6 +268,7 @@
     todo = (abs (res) >= tol * abs (x));
   endwhile
   x += res;
+
 endfunction
 
 
@@ -312,9 +314,8 @@
 %!assert (class (gammaincinv (single (0.5), int8 (1))), "single")
 
 ## Test input validation
-%!error gammaincinv ()
-%!error gammaincinv (1)
-%!error gammaincinv (1, 2, 3, 4)
+%!error <Invalid call> gammaincinv ()
+%!error <Invalid call> gammaincinv (1)
 %!error <must be of common size or scalars>
 %! gammaincinv (ones (2,2), ones (1,2), 1);
 %!error <all inputs must be real> gammaincinv (0.5i, 1)
--- a/scripts/specfun/isprime.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/specfun/isprime.m	Thu Nov 19 13:08:00 2020 -0800
@@ -69,7 +69,7 @@
 
 function t = isprime (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   elseif (any (fix (x) != x))
     error ("isprime: X contains non-integer entries");
@@ -173,7 +173,6 @@
 %!assert (isprime (magic (3)), logical ([0, 0, 0; 1, 1, 1; 0, 0, 1]))
 
 ## Test input validation
-%!error isprime ()
-%!error isprime (1, 2)
+%!error <Invalid call> isprime ()
 %!error <X contains non-integer entries> isprime (0.5i)
 %!error <X contains non-integer entries> isprime (0.5)
--- a/scripts/specfun/lcm.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/specfun/lcm.m	Thu Nov 19 13:08:00 2020 -0800
@@ -58,7 +58,8 @@
 
 %!assert (lcm (3, 5, 7, 15), 105)
 
-%!error lcm ()
-%!error lcm (1)
+## Test input validation
+%!error <Invalid call> lcm ()
+%!error <Invalid call> lcm (1)
 %!error <same size or scalar> lcm ([1 2], [1 2 3])
 %!error <arguments must be numeric> lcm ([1 2], {1 2})
--- a/scripts/specfun/legendre.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/specfun/legendre.m	Thu Nov 19 13:08:00 2020 -0800
@@ -167,7 +167,7 @@
 
   persistent warned_overflow = false;
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -311,9 +311,8 @@
 %! assert (result, expected);
 
 ## Test input validation
-%!error legendre ()
-%!error legendre (1)
-%!error legendre (1,2,3,4)
+%!error <Invalid call> legendre ()
+%!error <Invalid call> legendre (1)
 %!error <must be a real non-negative integer> legendre (i, [-1, 0, 1])
 %!error <must be a real non-negative integer> legendre ([1, 2], [-1, 0, 1])
 %!error <must be a real non-negative integer> legendre (-1, [-1, 0, 1])
--- a/scripts/specfun/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/specfun/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/beta.m \
   %reldir%/betainc.m \
   %reldir%/betaincinv.m \
--- a/scripts/specfun/nchoosek.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/specfun/nchoosek.m	Thu Nov 19 13:08:00 2020 -0800
@@ -149,9 +149,8 @@
 %!assert (size (nchoosek (1:5,0)), [1 0])
 
 ## Test input validation
-%!error nchoosek ()
-%!error nchoosek (1)
-%!error nchoosek (1,2,3)
+%!error <Invalid call> nchoosek ()
+%!error <Invalid call> nchoosek (1)
 
 %!error nchoosek (100, 2i)
 %!error nchoosek (100, [2 3])
--- a/scripts/specfun/nthroot.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/specfun/nthroot.m	Thu Nov 19 13:08:00 2020 -0800
@@ -106,9 +106,8 @@
 %! assert (lastwarn (), warnmsg);
 
 ## Test input validation
-%!error nthroot ()
-%!error nthroot (1)
-%!error nthroot (1,2,3)
+%!error <Invalid call> nthroot ()
+%!error <Invalid call> nthroot (1)
 %!error <X must not contain complex values> nthroot (1+j, 2)
 %!error <N must be a real nonzero scalar> nthroot (1, i)
 %!error <N must be a real nonzero scalar> nthroot (1, [1 2])
--- a/scripts/specfun/perms.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/specfun/perms.m	Thu Nov 19 13:08:00 2020 -0800
@@ -58,7 +58,7 @@
 
 function A = perms (v)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -123,8 +123,7 @@
 %!assert (unique (perms (1:5)(:))', 1:5)
 %!assert (perms (int8 (1:4)), int8 (perms (1:4)))
 
-%!error perms ()
-%!error perms (1, 2)
+%!error <Invalid call> perms ()
 
 ## Should work for any array type, such as cells and structs, and not
 ## only for numeric data.
@@ -161,5 +160,5 @@
 %!test <*52432>
 %! s = struct ();
 %! s(1) = [];
-%! assert (perms (reshape (s, 0, 0)), reshape (s, 1, 0))
-%! assert (perms (reshape (s, 0, 1)), reshape (s, 1, 0))
+%! assert (perms (reshape (s, 0, 0)), reshape (s, 1, 0));
+%! assert (perms (reshape (s, 0, 1)), reshape (s, 1, 0));
--- a/scripts/specfun/pow2.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/specfun/pow2.m	Thu Nov 19 13:08:00 2020 -0800
@@ -47,12 +47,14 @@
 
 function y = pow2 (f, e)
 
+  if (nargin < 1)
+    print_usage ();
+  endif
+
   if (nargin == 1)
     y = 2 .^ f;
-  elseif (nargin == 2)
+  else
     y = f .* (2 .^ e);
-  else
-    print_usage ();
   endif
 
 endfunction
@@ -69,5 +71,4 @@
 %! z = x .* (2 .^ y);
 %! assert (pow2 (x,y), z, sqrt (eps));
 
-%!error pow2 ()
-%!error pow2 (1,2,3)
+%!error <Invalid call> pow2 ()
--- a/scripts/specfun/primes.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/specfun/primes.m	Thu Nov 19 13:08:00 2020 -0800
@@ -47,7 +47,7 @@
 
 function p = primes (n)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -108,7 +108,6 @@
 %!assert (class (primes (single (10))), "single")
 %!assert (class (primes (uint8 (10))), "uint8")
 
-%!error primes ()
-%!error primes (1, 2)
+%!error <Invalid call> primes ()
 %!error <N must be a numeric scalar> primes ("1")
 %!error <N must be a numeric scalar> primes (ones (2,2))
--- a/scripts/specfun/reallog.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/specfun/reallog.m	Thu Nov 19 13:08:00 2020 -0800
@@ -34,7 +34,7 @@
 
 function y = reallog (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   elseif (iscomplex (x) || any (x(:) < 0))
     error ("reallog: produced complex result");
@@ -50,7 +50,6 @@
 %! x = rand (10, 10);
 %! assert (reallog (x), log (x));
 
-%!error reallog ()
-%!error reallog (1,2)
+%!error <Invalid call> reallog ()
 %!error <produced complex result> reallog (2i)
 %!error <produced complex result> reallog (-1)
--- a/scripts/specfun/realpow.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/specfun/realpow.m	Thu Nov 19 13:08:00 2020 -0800
@@ -54,7 +54,6 @@
 %! assert (x.^y, realpow (x,y));
 %!assert <47775> (realpow (1i,2), -1)
 
-%!error realpow ()
-%!error realpow (1)
-%!error realpow (1,2,3)
+%!error <Invalid call> realpow ()
+%!error <Invalid call> realpow (1)
 %!error <produced complex result> realpow (-1, 1/2)
--- a/scripts/specfun/realsqrt.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/specfun/realsqrt.m	Thu Nov 19 13:08:00 2020 -0800
@@ -34,7 +34,7 @@
 
 function y = realsqrt (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   elseif (iscomplex (x) || any (x(:) < 0))
     error ("realsqrt: produced complex result");
@@ -50,6 +50,5 @@
 %! x = rand (10, 10);
 %! assert (realsqrt (x), sqrt (x));
 
-%!error realsqrt ()
-%!error realsqrt (1,2)
+%!error <Invalid call> realsqrt ()
 %!error <produced complex result> realsqrt (-1)
--- a/scripts/specfun/sinint.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/specfun/sinint.m	Thu Nov 19 13:08:00 2020 -0800
@@ -54,7 +54,7 @@
 
 function y = sinint (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -75,7 +75,7 @@
     x = complex (real (x)(:), imag (x)(:));
   else
     x = x(:);
-  end
+  endif
 
   ## Initialize the result
   y = zeros (size (x), class (x));
@@ -202,14 +202,13 @@
 %!      -0.000099999999944461111128 + 0.99999999833338888972e-6*1i
 %!      -1.5386156269726011209 - 0.053969388020443786229*1i ];
 %! B = sinint (x);
-%! assert (A, B, -3*eps)
+%! assert (A, B, -3*eps);
 %! B = sinint (single (x));
-%! assert (A, B, -3*eps ("single"))
+%! assert (A, B, -3*eps ("single"));
 
 ## FIXME: Need a test for bug #52953
 %#!test <*52953>
 
 ## Test input validation
-%!error sinint ()
-%!error sinint (1,2)
+%!error <Invalid call> sinint ()
 %!error <X must be numeric> sinint ("1")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/special-matrix/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/special-matrix/gallery.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/special-matrix/gallery.m	Thu Nov 19 13:08:00 2020 -0800
@@ -413,12 +413,12 @@
 ## uniformdata) by Nicholas J. Higham <Nicholas.J.Higham@manchester.ac.uk>
 ## Adapted for Octave and into single gallery function by Carnë Draug
 
-function [varargout] = gallery (name, varargin)
+function varargout = gallery (name, varargin)
 
   if (nargin < 1)
     print_usage ();
   elseif (! ischar (name))
-    error ("gallery: NAME must be a string.");
+    error ("gallery: NAME must be a string");
   endif
 
   ## NOTE: there isn't a lot of input check in the individual functions
@@ -439,7 +439,7 @@
 
   switch (tolower (name))
     case "binomial"
-      error ("gallery: matrix %s not implemented.", name);
+      error ("gallery: matrix %s not implemented", name);
     case "cauchy"     , [varargout{1:n_out}] = cauchy      (varargin{:});
     case "chebspec"   , [varargout{1:n_out}] = chebspec    (varargin{:});
     case "chebvand"   , [varargout{1:n_out}] = chebvand    (varargin{:});
@@ -470,7 +470,7 @@
     case "lauchli"    , [varargout{1:n_out}] = lauchli     (varargin{:});
     case "lehmer"     , [varargout{1:n_out}] = lehmer      (varargin{:});
     case "leslie"
-      error ("gallery: matrix %s not implemented.", name);
+      error ("gallery: matrix %s not implemented", name);
     case "lesp"       , [varargout{1:n_out}] = lesp        (varargin{:});
     case "lotkin"     , [varargout{1:n_out}] = lotkin      (varargin{:});
     case "minij"      , [varargout{1:n_out}] = minij       (varargin{:});
@@ -483,19 +483,19 @@
     case "poisson"    , [varargout{1:n_out}] = poisson     (varargin{:});
     case "prolate"    , [varargout{1:n_out}] = prolate     (varargin{:});
     case "randcolu"
-      error ("gallery: matrix %s not implemented.", name);
+      error ("gallery: matrix %s not implemented", name);
     case "randcorr"
-      error ("gallery: matrix %s not implemented.", name);
+      error ("gallery: matrix %s not implemented", name);
     case "randhess"    , [varargout{1:n_out}] = randhess    (varargin{:});
     case "randjorth"
-      error ("gallery: matrix %s not implemented.", name);
+      error ("gallery: matrix %s not implemented", name);
     case "rando"       , [varargout{1:n_out}] = rando       (varargin{:});
     case "randsvd"     , [varargout{1:n_out}] = randsvd     (varargin{:});
     case "redheff"     , [varargout{1:n_out}] = redheff     (varargin{:});
     case "riemann"     , [varargout{1:n_out}] = riemann     (varargin{:});
     case "ris"         , [varargout{1:n_out}] = ris         (varargin{:});
     case "sampling"
-      error ("gallery: matrix %s not implemented.", name);
+      error ("gallery: matrix %s not implemented", name);
     case "smoke"       , [varargout{1:n_out}] = smoke       (varargin{:});
     case "toeppd"      , [varargout{1:n_out}] = toeppd      (varargin{:});
     case "toeppen"     , [varargout{1:n_out}] = toeppen     (varargin{:});
@@ -534,11 +534,11 @@
   ##     pp. 279-313, 1962. (States the totally positive property on p. 295.)
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 or 2 arguments are required for cauchy matrix.");
+    error ("gallery: 1 or 2 arguments are required for cauchy matrix");
   elseif (! isnumeric (x))
-    error ("gallery: X must be numeric for cauchy matrix.");
+    error ("gallery: X must be numeric for cauchy matrix");
   elseif (nargin == 2 && ! isnumeric (y))
-    error ("gallery: Y must be numeric for cauchy matrix.");
+    error ("gallery: Y must be numeric for cauchy matrix");
   endif
 
   n = numel (x);
@@ -548,7 +548,7 @@
   elseif (n > 1 && isvector (x))
     ## do nothing
   else
-    error ("gallery: X be an integer or a vector for cauchy matrix.");
+    error ("gallery: X be an integer or a vector for cauchy matrix");
   endif
 
   if (nargin == 1)
@@ -559,7 +559,7 @@
   x = x(:);
   y = y(:);
   if (numel (x) != numel (y))
-    error ("gallery: X and Y must be vectors of same length for cauchy matrix.");
+    error ("gallery: X and Y must be vectors of same length for cauchy matrix");
   endif
 
   C = 1 ./ (x .+ y.');
@@ -586,11 +586,11 @@
   ##      derivative, SIAM J. Sci. Stat. Comput., 9 (1988), pp. 1050-1057.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for chebspec matrix.");
+    error ("gallery: 1 to 2 arguments are required for chebspec matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for chebspec matrix.");
+    error ("gallery: N must be an integer for chebspec matrix");
   elseif (! isnumeric (k) || ! isscalar (k))
-    error ("gallery: K must be a scalar for chebspec matrix.");
+    error ("gallery: K must be a scalar for chebspec matrix");
   endif
 
   ## k = 1 case obtained from k = 0 case with one bigger n.
@@ -598,7 +598,7 @@
     case (0), # do nothing
     case (1), n = n + 1;
     otherwise
-      error ("gallery: K should be either 0 or 1 for chebspec matrix.");
+      error ("gallery: K should be either 0 or 1 for chebspec matrix");
   endswitch
 
   n -= 1;
@@ -648,7 +648,7 @@
   ##     pp. 23-41.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 or 2 arguments are required for chebvand matrix.");
+    error ("gallery: 1 or 2 arguments are required for chebvand matrix");
   endif
 
   ## because the order of the arguments changes if nargin is 1 or 2 ...
@@ -659,7 +659,7 @@
 
   n = numel (p);
   if (! isnumeric (p))
-    error ("gallery: P must be numeric for chebvand matrix.");
+    error ("gallery: P must be numeric for chebvand matrix");
   elseif (isscalar (p) && fix (p) == p)
     n = p;
     p = linspace (0, 1, n);
@@ -671,7 +671,7 @@
   if (nargin == 1)
     m = n;
   elseif (! isnumeric (m) || ! isscalar (m))
-    error ("gallery: M must be a scalar for chebvand matrix.");
+    error ("gallery: M must be a scalar for chebvand matrix");
   endif
 
   C = ones (m, n);
@@ -699,13 +699,13 @@
   ##      Hessenberg matrices, SIAM Review, 13 (1971), pp. 220-221.
 
   if (nargin < 1 || nargin > 3)
-    error ("gallery: 1 to 3 arguments are required for chow matrix.");
+    error ("gallery: 1 to 3 arguments are required for chow matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for chow matrix.");
+    error ("gallery: N must be an integer for chow matrix");
   elseif (! isnumeric (alpha) || ! isscalar (alpha))
-    error ("gallery: ALPHA must be a scalar for chow matrix.");
+    error ("gallery: ALPHA must be a scalar for chow matrix");
   elseif (! isnumeric (delta) || ! isscalar (delta))
-    error ("gallery: DELTA must be a scalar for chow matrix.");
+    error ("gallery: DELTA must be a scalar for chow matrix");
   endif
 
   A = toeplitz (alpha.^(1:n), [alpha 1 zeros(1, n-2)]) + delta * eye (n);
@@ -727,9 +727,9 @@
   ##   P.J. Davis, Circulant Matrices, John Wiley, 1977.
 
   if (nargin != 1)
-    error ("gallery: 1 argument is required for circul matrix.");
+    error ("gallery: 1 argument is required for circul matrix");
   elseif (! isnumeric (v))
-    error ("gallery: V must be numeric for circul matrix.");
+    error ("gallery: V must be numeric for circul matrix");
   endif
 
   n = numel (v);
@@ -739,7 +739,7 @@
   elseif (n > 1 && isvector (v))
     ## do nothing
   else
-    error ("gallery: X must be a scalar or a vector for circul matrix.");
+    error ("gallery: X must be a scalar or a vector for circul matrix");
   endif
 
   v = v(:).';   # Make sure v is a row vector
@@ -772,11 +772,11 @@
   ##      Linear Algebra and Appl., 150 (1991), pp. 341-360.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 or 2 arguments are required for clement matrix.");
+    error ("gallery: 1 or 2 arguments are required for clement matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for clement matrix.");
+    error ("gallery: N must be an integer for clement matrix");
   elseif (! isnumeric (k) || ! isscalar (k))
-    error ("gallery: K must be a numeric scalar for clement matrix.");
+    error ("gallery: K must be a numeric scalar for clement matrix");
   endif
 
   n -= 1;
@@ -789,7 +789,7 @@
     y = sqrt (x.*z);
     A = diag (y, -1) + diag (y, 1);
   else
-    error ("gallery: K must have a value of 0 or 1 for clement matrix.");
+    error ("gallery: K must have a value of 0 or 1 for clement matrix");
   endif
 endfunction
 
@@ -808,11 +808,11 @@
   ##   triangular matrices, SIAM Review, 29 (1987), pp. 575-596.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 or 2 arguments are required for compar matrix.");
+    error ("gallery: 1 or 2 arguments are required for compar matrix");
   elseif (! isnumeric (A) || ndims (A) != 2)
-    error ("gallery: A must be a 2-D matrix for compar matrix.");
+    error ("gallery: A must be a 2-D matrix for compar matrix");
   elseif (! isnumeric (k) || ! isscalar (k))
-    error ("gallery: K must be a numeric scalar for compar matrix.");
+    error ("gallery: K must be a numeric scalar for compar matrix");
   endif
 
   [m, n] = size (A);
@@ -840,7 +840,7 @@
     if (all (A == triu (A))), C = triu (C); endif
 
   else
-    error ("gallery: K must have a value of 0 or 1 for compar matrix.");
+    error ("gallery: K must have a value of 0 or 1 for compar matrix");
   endif
 
 endfunction
@@ -869,13 +869,13 @@
   ##      (Algorithm 674), ACM Trans. Math. Soft., 14 (1988), pp. 381-396.
 
   if (nargin < 1 || nargin > 3)
-    error ("gallery: 1 to 3 arguments are required for condex matrix.");
+    error ("gallery: 1 to 3 arguments are required for condex matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for condex matrix.");
+    error ("gallery: N must be an integer for condex matrix");
   elseif (! isnumeric (k) || ! isscalar (k))
-    error ("gallery: K must be a numeric scalar for condex matrix.");
+    error ("gallery: K must be a numeric scalar for condex matrix");
   elseif (! isnumeric (theta) || ! isscalar (theta))
-    error ("gallery: THETA must be a numeric scalar for condex matrix.");
+    error ("gallery: THETA must be a numeric scalar for condex matrix");
   endif
 
   if (k == 1)       # Cline and Rew (1983), Example B.
@@ -905,7 +905,7 @@
     A = eye (n) + theta*P;
 
   else
-    error ("gallery: unknown estimator K '%d' for condex matrix.", k);
+    error ("gallery: unknown estimator K '%d' for condex matrix", k);
   endif
 
   ## Pad out with identity as necessary.
@@ -929,11 +929,11 @@
   ##   elimination: see NA Digest Volume 89, Issue 3 (January 22, 1989).
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 or 2 arguments are required for cycol matrix.");
+    error ("gallery: 1 or 2 arguments are required for cycol matrix");
   elseif (! isnumeric (n) || all (numel (n) != [1 2]) || fix (n) != n)
-    error ("gallery: N must be a 1 or 2 element integer for cycol matrix.");
+    error ("gallery: N must be a 1 or 2 element integer for cycol matrix");
   elseif (! isnumeric (k) || ! isscalar (k))
-    error ("gallery: K must be a scalar for cycol matrix.");
+    error ("gallery: K must be a scalar for cycol matrix");
   endif
 
   ## Parameter n specifies dimension: m-by-n
@@ -964,11 +964,11 @@
   ##   pp. 271-283.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 or 2 arguments are required for dorr matrix.");
+    error ("gallery: 1 or 2 arguments are required for dorr matrix");
   elseif (! isscalar (n) || ! isnumeric (n) || fix (n) != n)
-    error ("gallery: N must be an integer for dorr matrix.");
+    error ("gallery: N must be an integer for dorr matrix");
   elseif (! isscalar (theta) || ! isnumeric (theta))
-    error ("gallery: THETA must be a numeric scalar for dorr matrix.");
+    error ("gallery: THETA must be a numeric scalar for dorr matrix");
   endif
 
   c = zeros (n, 1);
@@ -1023,11 +1023,11 @@
   ##      (0,1) matrix, Linear Algebra and Appl., 183 (1993), pp. 147-153.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for dramadah matrix.");
+    error ("gallery: 1 to 2 arguments are required for dramadah matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for dramadah matrix.");
+    error ("gallery: N must be an integer for dramadah matrix");
   elseif (! isnumeric (k) || ! isscalar (k))
-    error ("gallery: K must be a numeric scalar for dramadah matrix.");
+    error ("gallery: K must be a numeric scalar for dramadah matrix");
   endif
 
   switch (k)
@@ -1061,7 +1061,7 @@
       A = toeplitz (c, [1 1 zeros(1,n-2)]);
 
     otherwise
-      error ("gallery: unknown K '%d' for dramadah matrix.", k);
+      error ("gallery: unknown K '%d' for dramadah matrix", k);
   endswitch
 endfunction
 
@@ -1087,9 +1087,9 @@
   ##      Birkhauser, Basel, and Academic Press, New York, 1977, p. 159.
 
   if (nargin != 1)
-    error ("gallery: 1 argument is required for fiedler matrix.");
+    error ("gallery: 1 argument is required for fiedler matrix");
   elseif (! isnumeric (c))
-    error ("gallery: C must be numeric for fiedler matrix.");
+    error ("gallery: C must be numeric for fiedler matrix");
   endif
 
   n = numel (c);
@@ -1099,7 +1099,7 @@
   elseif (n > 1 && isvector (c))
     ## do nothing
   else
-    error ("gallery: C must be an integer or a vector for fiedler matrix.");
+    error ("gallery: C must be an integer or a vector for fiedler matrix");
   endif
   c = c(:).';           # Ensure c is a row vector.
 
@@ -1115,13 +1115,13 @@
   ##   ALPHA defaults to SQRT(EPS) and LAMBDA to 0.
 
   if (nargin < 1 || nargin > 3)
-    error ("gallery: 1 to 3 arguments are required for forsythe matrix.");
+    error ("gallery: 1 to 3 arguments are required for forsythe matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for forsythe matrix.");
+    error ("gallery: N must be an integer for forsythe matrix");
   elseif (! isnumeric (alpha) || ! isscalar (alpha))
-    error ("gallery: ALPHA must be a numeric scalar for forsythe matrix.");
+    error ("gallery: ALPHA must be a numeric scalar for forsythe matrix");
   elseif (! isnumeric (lambda) || ! isscalar (lambda))
-    error ("gallery: LAMBDA must be a numeric scalar for forsythe matrix.");
+    error ("gallery: LAMBDA must be a numeric scalar for forsythe matrix");
   endif
 
   A = jordbloc (n, lambda);
@@ -1167,11 +1167,11 @@
   ##      Comput., 7 (1986), pp. 835-839.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for frank matrix.");
+    error ("gallery: 1 to 2 arguments are required for frank matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for frank matrix.");
+    error ("gallery: N must be an integer for frank matrix");
   elseif (! isnumeric (k) || ! isscalar (k))
-    error ("gallery: K must be a numeric scalar for frank matrix.");
+    error ("gallery: K must be a numeric scalar for frank matrix");
   endif
 
   p = n:-1:1;
@@ -1181,15 +1181,15 @@
     case (0), # do nothing
     case (1), F = F(p,p)';
     otherwise
-      error ("gallery: K must have a value of 0 or 1 for frank matrix.");
+      error ("gallery: K must have a value of 0 or 1 for frank matrix");
   endswitch
 endfunction
 
 function c = gcdmat (n)
   if (nargin != 1)
-    error ("gallery: 1 argument is required for gcdmat matrix.");
+    error ("gallery: 1 argument is required for gcdmat matrix");
   elseif (! isscalar (n) || ! isnumeric (n) || fix (n) != n)
-    error ("gallery: N must be an integer for gcdmat matrix.");
+    error ("gallery: N must be an integer for gcdmat matrix");
   endif
   c = gcd (repmat ((1:n)', [1 n]), repmat (1:n, [n 1]));
 endfunction
@@ -1213,13 +1213,13 @@
   ##   Math. Comp., 23 (1969), pp. 119-125.
 
   if (nargin < 1 || nargin > 3)
-    error ("gallery: 1 to 3 arguments are required for gearmat matrix.");
+    error ("gallery: 1 to 3 arguments are required for gearmat matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for gearmat matrix.");
+    error ("gallery: N must be an integer for gearmat matrix");
   elseif (! isnumeric (i) || ! isscalar (i) || i == 0 || abs (i) > n)
-    error ("gallery: I must be a nonzero scalar, and abs (I) <= N for gearmat matrix.");
+    error ("gallery: I must be a nonzero scalar, and abs (I) <= N for gearmat matrix");
   elseif (! isnumeric (j) || ! isscalar (j) || i == 0 || abs (j) > n)
-    error ("gallery: J must be a nonzero scalar, and abs (J) <= N for gearmat matrix.");
+    error ("gallery: J must be a nonzero scalar, and abs (J) <= N for gearmat matrix");
   endif
 
   A = diag (ones (n-1, 1), -1) + diag (ones (n-1, 1), 1);
@@ -1243,11 +1243,11 @@
   ##        Appl., 13 (1992), pp. 796-825.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for grcar matrix.");
+    error ("gallery: 1 to 2 arguments are required for grcar matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for grcar matrix.");
+    error ("gallery: N must be an integer for grcar matrix");
   elseif (! isnumeric (k) || ! isscalar (k))
-    error ("gallery: K must be a numeric scalar for grcar matrix.");
+    error ("gallery: K must be a numeric scalar for grcar matrix");
   endif
 
   G = tril (triu (ones (n)), k) - diag (ones (n-1, 1), -1);
@@ -1267,13 +1267,13 @@
   ##   Berlin, 1987. (pp. 86-87)
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for hanowa matrix.");
+    error ("gallery: 1 to 2 arguments are required for hanowa matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for hanowa matrix.");
+    error ("gallery: N must be an integer for hanowa matrix");
   elseif (rem (n, 2) != 0)
-    error ("gallery: N must be even for hanowa matrix.");
+    error ("gallery: N must be even for hanowa matrix");
   elseif (! isnumeric (d) || ! isscalar (d))
-    error ("gallery: D must be a numeric scalar for hanowa matrix.");
+    error ("gallery: D must be a numeric scalar for hanowa matrix");
   endif
 
   m = n/2;
@@ -1307,9 +1307,9 @@
   ##      Press, 1965.
 
   if (nargin != 1)
-    error ("gallery: 1 argument is required for house matrix.");
+    error ("gallery: 1 argument is required for house matrix");
   elseif (! isnumeric (x) || ! isvector (x))
-    error ("gallery: X must be a vector for house matrix.");
+    error ("gallery: X must be a vector for house matrix");
   endif
 
   ## must be a column vector
@@ -1331,7 +1331,7 @@
 function A = integerdata (varargin)
 
   if (nargin < 3)
-    error ("gallery: At least 3 arguments required for integerdata matrix.");
+    error ("gallery: At least 3 arguments required for integerdata matrix");
   endif
 
   if (isnumeric (varargin{end}))
@@ -1394,9 +1394,9 @@
   ##       Operator Theory, 10 (1987), pp. 82-95.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for invhess matrix.");
+    error ("gallery: 1 to 2 arguments are required for invhess matrix");
   elseif (! isnumeric (x))
-    error ("gallery: X must be numeric for invhess matrix.");
+    error ("gallery: X must be numeric for invhess matrix");
   endif
 
   if (isscalar (x) && fix (x) == x)
@@ -1405,13 +1405,13 @@
   elseif (! isscalar (x) && isvector (x))
     n = numel (x);
   else
-    error ("gallery: X must be an integer scalar, or a vector for invhess matrix.");
+    error ("gallery: X must be an integer scalar, or a vector for invhess matrix");
   endif
 
   if (nargin < 2)
     y = -x(1:end-1);
   elseif (! isvector (y) || numel (y) != numel (x) -1)
-    error ("gallery: Y must be a vector of length -1 than X for invhess matrix.");
+    error ("gallery: Y must be a vector of length -1 than X for invhess matrix");
   endif
 
   x = x(:);
@@ -1436,10 +1436,10 @@
   ##   of involutory and of idempotent matrices, Numer. Math. 5 (1963),
   ##   pp. 234-237.
 
-  if (nargin != 1)
-    error ("gallery: 1 argument is required for invol matrix.");
+  if (nargin < 1)
+    error ("gallery: 1 argument is required for invol matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for invol matrix.");
+    error ("gallery: N must be an integer for invol matrix");
   endif
 
   A = hilb (n);
@@ -1470,11 +1470,11 @@
   ##   Dept. of Mathematics, University of Bradford, 1993.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for ipjfact matrix.");
+    error ("gallery: 1 to 2 arguments are required for ipjfact matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for ipjfact matrix.");
+    error ("gallery: N must be an integer for ipjfact matrix");
   elseif (! isnumeric (k) || ! isscalar (k))
-    error ("gallery: K must be a numeric scalar for ipjfact matrix.");
+    error ("gallery: K must be a numeric scalar for ipjfact matrix");
   endif
 
   c = cumprod (2:n+1);
@@ -1486,7 +1486,7 @@
     case (0), # do nothing
     case (1), A = ones (n) ./ A;
     otherwise
-      error ("gallery: K must have a value of 0 or 1 for ipjfact matrix.");
+      error ("gallery: K must have a value of 0 or 1 for ipjfact matrix");
   endswitch
 
   if (nargout == 2)
@@ -1507,7 +1507,7 @@
       endif
 
     else
-      error ("gallery: K must have a value of 0 or 1 for ipjfact matrix.");
+      error ("gallery: K must have a value of 0 or 1 for ipjfact matrix");
     endif
 
     detA = d;
@@ -1520,11 +1520,11 @@
   ##   LAMBDA.  LAMBDA = 1 is the default.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for jordbloc matrix.");
+    error ("gallery: 1 to 2 arguments are required for jordbloc matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for jordbloc matrix.");
+    error ("gallery: N must be an integer for jordbloc matrix");
   elseif (! isnumeric (lambda) || ! isscalar (lambda))
-    error ("gallery: LAMBDA must be a numeric scalar for jordbloc matrix.");
+    error ("gallery: LAMBDA must be a numeric scalar for jordbloc matrix");
   endif
 
   J = lambda * eye (n) + diag (ones (n-1, 1), 1);
@@ -1558,13 +1558,13 @@
   ##      triangular matrices, SIAM Review, 29 (1987), pp. 575-596.
 
   if (nargin < 1 || nargin > 3)
-    error ("gallery: 1 to 3 arguments are required for kahan matrix.");
+    error ("gallery: 1 to 3 arguments are required for kahan matrix");
   elseif (! isnumeric (n) || all (numel (n) != [1 2]) || fix (n) != n)
-    error ("gallery: N must be a 1 or 2 element integer for kahan matrix.");
+    error ("gallery: N must be a 1 or 2 element integer for kahan matrix");
   elseif (! isnumeric (theta) || ! isscalar (theta))
-    error ("gallery: THETA must be a numeric scalar for kahan matrix.");
+    error ("gallery: THETA must be a numeric scalar for kahan matrix");
   elseif (! isnumeric (pert) || ! isscalar (pert))
-    error ("gallery: PERT must be a numeric scalar for kahan matrix.");
+    error ("gallery: PERT must be a numeric scalar for kahan matrix");
   endif
 
   ## Parameter n specifies dimension: r-by-n
@@ -1603,11 +1603,11 @@
   ##    10 (1989), pp. 135-146 (and see the references therein).
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for lauchli matrix.");
+    error ("gallery: 1 to 2 arguments are required for lauchli matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for lauchli matrix.");
+    error ("gallery: N must be an integer for lauchli matrix");
   elseif (! isscalar (rho))
-    error ("gallery: RHO must be a scalar for lauchli matrix.");
+    error ("gallery: RHO must be a scalar for lauchli matrix");
   endif
 
   A = (1:n)'*ones (1,n);
@@ -1631,9 +1631,9 @@
   ##   Johns Hopkins University Press, Baltimore, Maryland, 1989, p. 369.
 
   if (nargin < 1 || nargin > 3)
-    error ("gallery: 1 to 3 arguments are required for krylov matrix.");
+    error ("gallery: 1 to 3 arguments are required for krylov matrix");
   elseif (! isnumeric (A) || ! issquare (A) || ndims (A) != 2)
-    error ("gallery: A must be a square 2-D matrix for krylov matrix.");
+    error ("gallery: A must be a square 2-D matrix for krylov matrix");
   endif
 
   n = length (A);
@@ -1645,13 +1645,13 @@
   if (nargin < 2)
     x = ones (n, 1);
   elseif (! isvector (x) || numel (x) != n)
-    error ("gallery: X must be a vector of length equal to A for krylov matrix.");
+    error ("gallery: X must be a vector of length equal to A for krylov matrix");
   endif
 
   if (nargin < 3)
     j = n;
   elseif (! isnumeric (j) || ! isscalar (j) || fix (j) != j)
-    error ("gallery: J must be an integer for krylov matrix.");
+    error ("gallery: J must be an integer for krylov matrix");
   endif
 
   B = ones (n, j);
@@ -1673,11 +1673,11 @@
   ##   kleinsten Quadraten, Numer. Math, 3 (1961), pp. 226-240.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for lauchli matrix.");
+    error ("gallery: 1 to 2 arguments are required for lauchli matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for lauchli matrix.");
+    error ("gallery: N must be an integer for lauchli matrix");
   elseif (! isscalar (mu))
-    error ("gallery: MU must be a scalar for lauchli matrix.");
+    error ("gallery: MU must be a scalar for lauchli matrix");
   endif
 
   A = [ones(1, n)
@@ -1700,10 +1700,10 @@
   ##   J. Todd, Basic Numerical Mathematics, Vol. 2: Numerical Algebra,
   ##      Birkhauser, Basel, and Academic Press, New York, 1977, p. 154.
 
-  if (nargin != 1)
-    error ("gallery: 1 argument is required for lehmer matrix.");
+  if (nargin < 1)
+    error ("gallery: 1 argument is required for lehmer matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for lehmer matrix.");
+    error ("gallery: N must be an integer for lehmer matrix");
   endif
 
   A = ones (n, 1) * (1:n);
@@ -1731,10 +1731,10 @@
   ##        Mathematics, volume 260, Longman Scientific and Technical, Essex,
   ##        UK, 1992, pp. 234-266.
 
-  if (nargin != 1)
-    error ("gallery: 1 argument is required for lesp matrix.");
+  if (nargin < 1)
+    error ("gallery: 1 argument is required for lesp matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for lesp matrix.");
+    error ("gallery: N must be an integer for lesp matrix");
   endif
 
   x = 2:n;
@@ -1751,10 +1751,10 @@
   ##   Reference:
   ##   M. Lotkin, A set of test matrices, MTAC, 9 (1955), pp. 153-161.
 
-  if (nargin != 1)
-    error ("gallery: 1 argument is required for lotkin matrix.");
+  if (nargin < 1)
+    error ("gallery: 1 argument is required for lotkin matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for lotkin matrix.");
+    error ("gallery: N must be an integer for lotkin matrix");
   endif
 
   A = hilb (n);
@@ -1779,10 +1779,10 @@
   ##      chemistry---II, Proc. Royal Soc. Edin., 63, A (1952), pp. 232-241.
   ##      (For the eigenvalues of Givens' matrix.)
 
-  if (nargin != 1)
-    error ("gallery: 1 argument is required for minij matrix.");
+  if (nargin < 1)
+    error ("gallery: 1 argument is required for minij matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for minij matrix.");
+    error ("gallery: N must be an integer for minij matrix");
   endif
 
   A = bsxfun (@min, 1:n, (1:n)');
@@ -1803,11 +1803,11 @@
   ##   Bristol, 1990 (Appendix 1).
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for moler matrix.");
+    error ("gallery: 1 to 2 arguments are required for moler matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for moler matrix.");
+    error ("gallery: N must be an integer for moler matrix");
   elseif (! isscalar (alpha))
-    error ("gallery: ALPHA must be a scalar for moler matrix.");
+    error ("gallery: ALPHA must be a scalar for moler matrix");
   endif
 
   A = triw (n, alpha)' * triw (n, alpha);
@@ -1826,16 +1826,16 @@
   ##   R.J. Plemmons, Regular splittings and the discrete Neumann
   ##   problem, Numer. Math., 25 (1976), pp. 153-161.
 
-  if (nargin != 1)
-    error ("gallery: 1 argument is required for neumann matrix.");
+  if (nargin < 1)
+    error ("gallery: 1 argument is required for neumann matrix");
   elseif (! isnumeric (n) || all (numel (n) != [1 2]) || fix (n) != n)
-    error ("gallery: N must be a 1 or 2 element integer for neumann matrix.");
+    error ("gallery: N must be a 1 or 2 element integer for neumann matrix");
   endif
 
   if (isscalar (n))
     m = sqrt (n);
     if (m^2 != n)
-      error ("gallery: N must be a perfect square for neumann matrix.");
+      error ("gallery: N must be a perfect square for neumann matrix");
     endif
     n(1) = m;
     n(2) = m;
@@ -1851,7 +1851,7 @@
 function A = normaldata (varargin)
 
   if (nargin < 2)
-    error ("gallery: At least 2 arguments required for normaldata matrix.");
+    error ("gallery: At least 2 arguments required for normaldata matrix");
   endif
   if (isnumeric (varargin{end}))
     jidx = varargin{end};
@@ -1924,11 +1924,11 @@
   ##        pp. 500-507.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for orthog matrix.");
+    error ("gallery: 1 to 2 arguments are required for orthog matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for orthog matrix.");
+    error ("gallery: N must be an integer for orthog matrix");
   elseif (! isnumeric (k) || ! isscalar (k))
-    error ("gallery: K must be a numeric scalar for orthog matrix.");
+    error ("gallery: K must be a numeric scalar for orthog matrix");
   endif
 
   switch (k)
@@ -1971,7 +1971,7 @@
       Q = cos (m);
 
     otherwise
-      error ("gallery: unknown K '%d' for orthog matrix.", k);
+      error ("gallery: unknown K '%d' for orthog matrix", k);
   endswitch
 endfunction
 
@@ -1992,10 +1992,10 @@
   ##   E.E. Tyrtyshnikov, Cauchy-Toeplitz matrices and some applications,
   ##        Linear Algebra and Appl., 149 (1991), pp. 1-18.
 
-  if (nargin != 1)
-    error ("gallery: 1 argument is required for parter matrix.");
+  if (nargin < 1)
+    error ("gallery: 1 argument is required for parter matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for parter matrix.");
+    error ("gallery: N must be an integer for parter matrix");
   endif
 
   A = cauchy ((1:n) + 0.5, -(1:n));
@@ -2013,11 +2013,11 @@
   ##   Comm. ACM, 5 (1962), p. 508.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for pei matrix.");
+    error ("gallery: 1 to 2 arguments are required for pei matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for pei matrix.");
+    error ("gallery: N must be an integer for pei matrix");
   elseif (! isnumeric (alpha) || ! isscalar (alpha))
-    error ("gallery: ALPHA must be a scalar for pei matrix.");
+    error ("gallery: ALPHA must be a scalar for pei matrix");
   endif
 
   P = alpha * eye (n) + ones (n);
@@ -2034,10 +2034,10 @@
   ##   Johns Hopkins University Press, Baltimore, Maryland, 1989
   ##   (Section 4.5.4).
 
-  if (nargin != 1)
-    error ("gallery: 1 argument is required for poisson matrix.");
+  if (nargin < 1)
+    error ("gallery: 1 argument is required for poisson matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for poisson matrix.");
+    error ("gallery: N must be an integer for poisson matrix");
   endif
 
   S = tridiag (n, -1, 2, -1);
@@ -2060,11 +2060,11 @@
   ##   187:269--278, 1993.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for prolate matrix.");
+    error ("gallery: 1 to 2 arguments are required for prolate matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for prolate matrix.");
+    error ("gallery: N must be an integer for prolate matrix");
   elseif (! isnumeric (w) || ! isscalar (w))
-    error ("gallery: W must be a scalar for prolate matrix.");
+    error ("gallery: W must be a scalar for prolate matrix");
   endif
 
   a      = zeros (n, 1);
@@ -2095,10 +2095,10 @@
   ##   W.B. Gragg, The QR algorithm for unitary Hessenberg matrices,
   ##   J. Comp. Appl. Math., 16 (1986), pp. 1-8.
 
-  if (nargin != 1)
-    error ("gallery: 1 argument is required for randhess matrix.");
+  if (nargin < 1)
+    error ("gallery: 1 argument is required for randhess matrix");
   elseif (! isnumeric (x) || ! isreal (x))
-    error ("gallery: N or X must be numeric real values for randhess matrix.");
+    error ("gallery: N or X must be numeric real values for randhess matrix");
   endif
 
   if (isscalar (x))
@@ -2111,7 +2111,7 @@
     H = eye (n);
     H(n,n) = sign (x(n)) + (x(n) == 0); # Second term ensures H(n,n) nonzero.
   else
-    error ("gallery: N or X must be a scalar or a vector for randhess matrix.");
+    error ("gallery: N or X must be a scalar or a vector for randhess matrix");
   endif
 
   for i = n:-1:2
@@ -2134,11 +2134,11 @@
   ##   N may be a 2-vector, in which case the matrix is N(1)-by-N(2).
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for rando matrix.");
+    error ("gallery: 1 to 2 arguments are required for rando matrix");
   elseif (! isnumeric (n) || all (numel (n) != [1 2]) || fix (n) != n)
-    error ("gallery: N must be an integer for rando matrix.");
+    error ("gallery: N must be an integer for rando matrix");
   elseif (! isnumeric (k) || ! isscalar (k))
-    error ("gallery: K must be a numeric scalar for smoke matrix.");
+    error ("gallery: K must be a numeric scalar for smoke matrix");
   endif
 
   ## Parameter n specifies dimension: m-by-n.
@@ -2150,7 +2150,7 @@
     case (2), A = 2*floor (  rand(m, n) + 0.5) -1;  # {-1, 1}
     case (3), A =   round (3*rand(m, n) - 1.5);     # {-1, 0, 1}
     otherwise
-      error ("gallery: unknown K '%d' for smoke matrix.", k);
+      error ("gallery: unknown K '%d' for smoke matrix", k);
   endswitch
 
 endfunction
@@ -2191,19 +2191,19 @@
   ##   New York, 1989.
 
   if (nargin < 1 || nargin > 5)
-    error ("gallery: 1 to 5 arguments are required for randsvd matrix.");
+    error ("gallery: 1 to 5 arguments are required for randsvd matrix");
   elseif (! isnumeric (n) || all (numel (n) != [1 2]) || fix (n) != n)
-    error ("gallery: N must be a 1 or 2 element integer vector for randsvd matrix.");
+    error ("gallery: N must be a 1 or 2 element integer vector for randsvd matrix");
   elseif (! isnumeric (kappa) || ! isscalar (kappa))
-    error ("gallery: KAPPA must be a numeric scalar for randsvd matrix.");
+    error ("gallery: KAPPA must be a numeric scalar for randsvd matrix");
   elseif (abs (kappa) < 1)
-    error ("gallery: KAPPA must larger than or equal to 1 for randsvd matrix.");
+    error ("gallery: KAPPA must larger than or equal to 1 for randsvd matrix");
   elseif (! isnumeric (mode) || ! isscalar (mode))
-    error ("gallery: MODE must be a numeric scalar for randsvd matrix.");
+    error ("gallery: MODE must be a numeric scalar for randsvd matrix");
   elseif (! isnumeric (kl) || ! isscalar (kl))
-    error ("gallery: KL must be a numeric scalar for randsvd matrix.");
+    error ("gallery: KL must be a numeric scalar for randsvd matrix");
   elseif (! isnumeric (ku) || ! isscalar (ku))
-    error ("gallery: KU must be a numeric scalar for randsvd matrix.");
+    error ("gallery: KU must be a numeric scalar for randsvd matrix");
   endif
 
   posdef = 0;
@@ -2242,7 +2242,7 @@
       rand ("uniform");
       sigma = exp (-rand (p, 1) * log (kappa));
     otherwise
-      error ("gallery: unknown MODE '%d' for randsvd matrix.", mode);
+      error ("gallery: unknown MODE '%d' for randsvd matrix", mode);
   endswitch
 
   ##  Convert to diagonal matrix of singular values.
@@ -2305,10 +2305,10 @@
   ##   Spectral Properties of a Matrix of Redheffer,
   ##   Linear Algebra and Appl., 162 (1992), pp. 673-683.
 
-  if (nargin != 1)
-    error ("gallery: 1 argument is required for redheff matrix.");
+  if (nargin < 1)
+    error ("gallery: 1 argument is required for redheff matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for redheff matrix.");
+    error ("gallery: N must be an integer for redheff matrix");
   endif
 
   i = (1:n)' * ones (1, n);
@@ -2335,10 +2335,10 @@
   ##   F. Roesler, Riemann's hypothesis as an eigenvalue problem,
   ##   Linear Algebra and Appl., 81 (1986), pp. 153-198.
 
-  if (nargin != 1)
-    error ("gallery: 1 argument is required for riemann matrix.");
+  if (nargin < 1)
+    error ("gallery: 1 argument is required for riemann matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for riemann matrix.");
+    error ("gallery: N must be an integer for riemann matrix");
   endif
 
   n += 1;
@@ -2361,10 +2361,10 @@
   ##   Algebra and Function Minimisation, second edition, Adam Hilger,
   ##   Bristol, 1990 (Appendix 1).
 
-  if (nargin != 1)
-    error ("gallery: 1 argument is required for ris matrix.");
+  if (nargin < 1)
+    error ("gallery: 1 argument is required for ris matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for ris matrix.");
+    error ("gallery: N must be an integer for ris matrix");
   endif
 
   p = -2*(1:n) + (n+1.5);
@@ -2389,11 +2389,11 @@
   ##   Toeplitz matrices, Linear Algebra and Appl., 162-164:153-185, 1992.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for smoke matrix.");
+    error ("gallery: 1 to 2 arguments are required for smoke matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for smoke matrix.");
+    error ("gallery: N must be an integer for smoke matrix");
   elseif (! isnumeric (n) || ! isscalar (n))
-    error ("gallery: K must be a numeric scalar for smoke matrix.");
+    error ("gallery: K must be a numeric scalar for smoke matrix");
   endif
 
   w = exp (2*pi*i/n);
@@ -2403,7 +2403,7 @@
     case (0), A(n,1) = 1;
     case (1), # do nothing
     otherwise,
-      error ("gallery: K must have a value of 0 or 1 for smoke matrix.");
+      error ("gallery: K must have a value of 0 or 1 for smoke matrix");
   endswitch
 endfunction
 
@@ -2424,13 +2424,13 @@
   ##   Comput., 7 (1986), pp. 123-131.
 
   if (nargin < 1 || nargin > 4)
-    error ("gallery: 1 to 4 arguments are required for toeppd matrix.");
+    error ("gallery: 1 to 4 arguments are required for toeppd matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be a numeric integer for toeppd matrix.");
+    error ("gallery: N must be a numeric integer for toeppd matrix");
   elseif (! isnumeric (m) || ! isscalar (m) || fix (m) != m)
-    error ("gallery: M must be a numeric integer for toeppd matrix.");
+    error ("gallery: M must be a numeric integer for toeppd matrix");
   elseif (numel (w) != m || numel (theta) != m)
-    error ("gallery: W and THETA must be vectors of length M for toeppd matrix.");
+    error ("gallery: W and THETA must be vectors of length M for toeppd matrix");
   endif
 
   T = zeros (n);
@@ -2465,11 +2465,11 @@
   ##      1966, pp. 349-365.
 
   if (nargin < 1 || nargin > 6)
-    error ("gallery: 1 to 6 arguments are required for toeppen matrix.");
+    error ("gallery: 1 to 6 arguments are required for toeppen matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be a numeric integer for toeppen matrix.");
+    error ("gallery: N must be a numeric integer for toeppen matrix");
   elseif (any (! cellfun ("isnumeric", {a b c d e})) || any (cellfun ("numel", {a b c d e}) != 1))
-    error ("gallery: A, B, C, D and E must be numeric scalars for toeppen matrix.");
+    error ("gallery: A, B, C, D and E must be numeric scalars for toeppen matrix");
   endif
 
   P = spdiags ([a*ones(n,1) b*ones(n,1) c*ones(n,1) d*ones(n,1) e*ones(n,1)],
@@ -2497,7 +2497,7 @@
   ##     chemistry---II, Proc. Royal Soc. Edin., 63, A (1952), pp. 232-241.
 
   if (nargin != 1 && nargin != 3 && nargin != 4)
-    error ("gallery: 1, 3, or 4 arguments are required for tridiag matrix.");
+    error ("gallery: 1, 3, or 4 arguments are required for tridiag matrix");
   elseif (nargin == 3)
     z = y;
     y = x;
@@ -2514,9 +2514,9 @@
     z *= ones (n-1, 1);
     y *= ones (n,   1);
   elseif (numel (y) != numel (x) + 1)
-    error ("gallery: X must have one element less than Y for tridiag matrix.");
+    error ("gallery: X must have one element less than Y for tridiag matrix");
   elseif (numel (y) != numel (z) + 1)
-    error ("gallery: Z must have one element less than Y for tridiag matrix.");
+    error ("gallery: Z must have one element less than Y for tridiag matrix");
   endif
 
   ##  T = diag (x, -1) + diag (y) + diag (z, 1);  # For non-sparse matrix.
@@ -2555,13 +2555,13 @@
   ##      Academic Press, London, 1978, pp. 109-135.
 
   if (nargin < 1 || nargin > 3)
-    error ("gallery: 1 to 3 arguments are required for triw matrix.");
+    error ("gallery: 1 to 3 arguments are required for triw matrix");
   elseif (! isnumeric (n) || all (numel (n) != [1 2]))
-    error ("gallery: N must be a 1 or 2 elements vector for triw matrix.");
+    error ("gallery: N must be a 1 or 2 elements vector for triw matrix");
   elseif (! isscalar (alpha))
-    error ("gallery: ALPHA must be a scalar for triw matrix.");
+    error ("gallery: ALPHA must be a scalar for triw matrix");
   elseif (! isscalar (k) || ! isnumeric (k) || fix (k) != k || k < 0)
-    error ("gallery: K must be a numeric integer >= 0 for triw matrix.");
+    error ("gallery: K must be a numeric integer >= 0 for triw matrix");
   endif
 
   m = n(1);              # Parameter n specifies dimension: m-by-n.
@@ -2573,7 +2573,7 @@
 function A = uniformdata (varargin)
 
   if (nargin < 2)
-    error ("gallery: At least 2 arguments required for uniformdata matrix.");
+    error ("gallery: At least 2 arguments required for uniformdata matrix");
   endif
   if (isnumeric (varargin{end}))
     jidx = varargin{end};
@@ -2687,13 +2687,13 @@
   ##   format.
 
   if (nargin < 2 || nargin > 3)
-    error ("gallery: 2 or 3 arguments are required for wathen matrix.");
+    error ("gallery: 2 or 3 arguments are required for wathen matrix");
   elseif (! isnumeric (nx) || ! isscalar (nx) || nx < 1)
-    error ("gallery: NX must be a positive scalar for wathen matrix.");
+    error ("gallery: NX must be a positive scalar for wathen matrix");
   elseif (! isnumeric (ny) || ! isscalar (ny) || ny < 1)
-    error ("gallery: NY must be a positive scalar for wathen matrix.");
+    error ("gallery: NY must be a positive scalar for wathen matrix");
   elseif (! isscalar (k))
-    error ("gallery: K must be a scalar for wathen matrix.");
+    error ("gallery: K must be a scalar for wathen matrix");
   endif
 
   e1 = [ 6  -6   2  -8
@@ -2762,10 +2762,10 @@
   ##   J.H. Wilkinson, The Algebraic Eigenvalue Problem, Oxford University
   ##      Press, 1965.
 
-  if (nargin != 1)
-    error ("gallery: 1 argument is required for wilk matrix.");
+  if (nargin < 1)
+    error ("gallery: 1 argument is required for wilk matrix");
   elseif (! isnumeric (n) || ! isscalar (n))
-    error ("gallery: N must be a numeric scalar for wilk matrix.");
+    error ("gallery: N must be a numeric scalar for wilk matrix");
   endif
 
   if (n == 3)
@@ -2802,7 +2802,7 @@
     A = diag (abs (-m:m)) + E + E';
 
   else
-    error ("gallery: unknown N '%d' for wilk matrix.", n);
+    error ("gallery: unknown N '%d' for wilk matrix", n);
   endif
 endfunction
 
@@ -2912,7 +2912,7 @@
 %!assert (gallery ("invhess", 2), [1 -1; 1 2])
 
 ## Test input validation of main dispatch function only
-%!error gallery ()
+%!error <Invalid call> gallery ()
 %!error <NAME must be a string> gallery (123)
 %!error <matrix binomial not implemented> gallery ("binomial")
 %!error <unknown matrix with NAME foobar> gallery ("foobar")
@@ -2930,9 +2930,9 @@
 %!   4  5  6  7  8
 %!   5  6  7  8  9
 %!   6  7  8  9  10];
-%! assert (gallery ("cauchy", 5), exp)
-%! assert (gallery ("cauchy", 1:5), exp)
-%! assert (gallery ("cauchy", 1:5, 1:5), exp)
+%! assert (gallery ("cauchy", 5), exp);
+%! assert (gallery ("cauchy", 1:5), exp);
+%! assert (gallery ("cauchy", 1:5, 1:5), exp);
 %!
 %! exp = 1 ./ [
 %!   1  2  3  4  5
@@ -2940,9 +2940,9 @@
 %!   3  4  5  6  7
 %!   4  5  6  7  8
 %!   5  6  7  8  9];
-%! assert (gallery ("cauchy", 0:4, 1:5), exp)
-%! assert (gallery ("cauchy", 1:5, 0:4), exp)
-%! assert (gallery ("cauchy", 1:5, 4:-1:0), fliplr (exp))
+%! assert (gallery ("cauchy", 0:4, 1:5), exp);
+%! assert (gallery ("cauchy", 1:5, 0:4), exp);
+%! assert (gallery ("cauchy", 1:5, 4:-1:0), fliplr (exp));
 %!
 %! exp = 1 ./ [
 %!  -1  0  1  2  3
@@ -2950,16 +2950,16 @@
 %!   1  2  3  4  5
 %!   2  3  4  5  6
 %!   3  4  5  6  7];
-%! assert (gallery ("cauchy", 1:5, -2:2), exp)
+%! assert (gallery ("cauchy", 1:5, -2:2), exp);
 %!
 %! exp = 1 ./ [
 %!    8  18  -4  2
 %!   13  23   1  7
 %!    9  19  -3  3
 %!   15  25   3  9];
-%! assert (gallery ("cauchy", [-2 3 -1 5], [10 20 -2 4]), exp)
-%! assert (gallery ("cauchy", [-2 3 -1 5], [10 20 -2 4]'), exp)
-%! assert (gallery ("cauchy", [-2 3 -1 5]', [10 20 -2 4]), exp)
+%! assert (gallery ("cauchy", [-2 3 -1 5], [10 20 -2 4]), exp);
+%! assert (gallery ("cauchy", [-2 3 -1 5], [10 20 -2 4]'), exp);
+%! assert (gallery ("cauchy", [-2 3 -1 5]', [10 20 -2 4]), exp);
 
 %!assert (size (gallery ("chebspec", 5)), [5 5])
 %!assert (size (gallery ("chebspec", 5, 1)), [5 5])
@@ -3006,10 +3006,10 @@
 %!   2   1   0   1   2
 %!   3   2   1   0   1
 %!   4   3   2   1   0];
-%! assert (gallery ("fiedler", 5), exp)
-%! assert (gallery ("fiedler", 1:5), exp)
-%! assert (gallery ("fiedler", -2:2), exp)
-%! assert (gallery ("fiedler", 2:5), exp(1:4,1:4))
+%! assert (gallery ("fiedler", 5), exp);
+%! assert (gallery ("fiedler", 1:5), exp);
+%! assert (gallery ("fiedler", -2:2), exp);
+%! assert (gallery ("fiedler", 2:5), exp(1:4,1:4));
 
 %!assert (size (gallery ("forsythe", 5)), [5 5])
 %!assert (size (gallery ("forsythe", 5, 1, 0.5)), [5 5])
--- a/scripts/special-matrix/hadamard.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/special-matrix/hadamard.m	Thu Nov 19 13:08:00 2020 -0800
@@ -67,7 +67,7 @@
 
 function h = hadamard (n)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -176,6 +176,6 @@
 %!   assert (norm (h*h' - n*eye (n)), 0);
 %! endfor
 
-%!error hadamard ()
+%!error <Invalid call> hadamard ()
 %!error hadamard (1,2)
 %!error <N must be 2\^k\*p> hadamard (5)
--- a/scripts/special-matrix/hankel.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/special-matrix/hankel.m	Thu Nov 19 13:08:00 2020 -0800
@@ -56,7 +56,7 @@
 
 function retval = hankel (c, r)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -99,7 +99,6 @@
 %!warning <column wins anti-diagonal conflict>
 %!  assert (hankel (1:3,4:6), [1,2,3;2,3,5;3,5,6]);
 
-%!error hankel ()
-%!error hankel (1, 2, 3)
+%!error <Invalid call> hankel ()
 %!error <C must be a vector> hankel ([1, 2; 3, 4])
 %!error <C and R must be vectors> hankel (1:4, [1, 2; 3, 4])
--- a/scripts/special-matrix/hilb.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/special-matrix/hilb.m	Thu Nov 19 13:08:00 2020 -0800
@@ -60,7 +60,7 @@
 
 function retval = hilb (n)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   elseif (! isscalar (n))
     error ("hilb: N must be a scalar integer");
@@ -77,6 +77,5 @@
 %!assert (hilb (2), [1, 1/2; 1/2, 1/3])
 %!assert (hilb (3), [1, 1/2, 1/3; 1/2, 1/3, 1/4; 1/3, 1/4, 1/5])
 
-%!error hilb ()
-%!error hilb (1, 2)
+%!error <Invalid call> hilb ()
 %!error <N must be a scalar integer> hilb (ones (2))
--- a/scripts/special-matrix/invhilb.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/special-matrix/invhilb.m	Thu Nov 19 13:08:00 2020 -0800
@@ -81,7 +81,7 @@
 
 function retval = invhilb (n)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   elseif (! isscalar (n))
     error ("invhilb: N must be a scalar integer");
@@ -128,6 +128,5 @@
 %! assert (invhilb (4), result4);
 %!assert (invhilb (7) * hilb (7), eye (7), sqrt (eps))
 
-%!error invhilb ()
-%!error invhilb (1, 2)
+%!error <Invalid call> invhilb ()
 %!error <N must be a scalar integer> invhilb ([1, 2])
--- a/scripts/special-matrix/magic.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/special-matrix/magic.m	Thu Nov 19 13:08:00 2020 -0800
@@ -38,7 +38,7 @@
 
 function A = magic (n)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -105,6 +105,5 @@
 %!assert (magic (1.5), 1)
 
 ## Test input validation
-%!error magic ()
-%!error magic (1, 2)
+%!error <Invalid call> magic ()
 %!error <N must be non-negative> magic (-5)
--- a/scripts/special-matrix/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/special-matrix/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/gallery.m \
   %reldir%/hadamard.m \
   %reldir%/hankel.m \
--- a/scripts/special-matrix/pascal.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/special-matrix/pascal.m	Thu Nov 19 13:08:00 2020 -0800
@@ -47,7 +47,7 @@
 
 function retval = pascal (n, t = 0)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   elseif (! (isscalar (n) && isscalar (t)))
     error ("pascal: N and T must be scalars");
@@ -90,8 +90,7 @@
 %!assert (pascal (0,2), [])
 
 ## Test input validation
-%!error pascal ()
-%!error pascal (1,2,3)
+%!error <Invalid call> pascal ()
 %!error <N and T must be scalars> pascal ([1 2])
 %!error <N and T must be scalars> pascal (1, [1 2])
 %!error <T must be -1> pascal (3,-2)
--- a/scripts/special-matrix/rosser.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/special-matrix/rosser.m	Thu Nov 19 13:08:00 2020 -0800
@@ -33,10 +33,6 @@
 
 function retval = rosser ()
 
-  if (nargin != 0)
-    print_usage ();
-  endif
-
   retval = [611,   196,  -192,   407,    -8,   -52,   -49,    29;
             196,   899,   113,  -192,   -71,   -43,    -8,   -44;
            -192,   113,   899,   196,    61,    49,     8,    52;
@@ -52,4 +48,4 @@
 %!assert (size (rosser ()), [8,8])
 %!assert (rosser ()([1, end]), [611, 99])
 
-%!error (rosser (1))
+%!error rosser (1)
--- a/scripts/special-matrix/toeplitz.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/special-matrix/toeplitz.m	Thu Nov 19 13:08:00 2020 -0800
@@ -65,7 +65,7 @@
 
 function retval = toeplitz (c, r)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -133,8 +133,7 @@
 %!assert (toeplitz ([1, 2, 3], [1; -3i; -5i]), [1, -3i, -5i; 2, 1, -3i; 3, 2, 1])
 
 ## Test input validation
-%!error toeplitz ()
-%!error toeplitz (1, 2, 3)
+%!error <Invalid call> toeplitz ()
 %!error <C must be a vector> toeplitz ([1, 2; 3, 4])
 %!error <C and R must be vectors> toeplitz ([1, 2; 3, 4], 1)
 %!error <C and R must be vectors> toeplitz (1, [1, 2; 3, 4])
--- a/scripts/special-matrix/vander.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/special-matrix/vander.m	Thu Nov 19 13:08:00 2020 -0800
@@ -95,6 +95,5 @@
 %!assert (vander (2, 3), [4, 2, 1])
 %!assert (vander ([2, 3], 3), [4, 2, 1; 9, 3, 1])
 
-%!error vander ()
-%!error vander (1, 2, 3)
+%!error <Invalid call> vander ()
 %!error <polynomial C must be a vector> vander ([1, 2; 3, 4])
--- a/scripts/special-matrix/wilkinson.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/special-matrix/wilkinson.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,7 +36,7 @@
 
 function retval = wilkinson (n)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -58,8 +58,7 @@
 %!assert (wilkinson (4), [1.5,1,0,0;1,0.5,1,0;0,1,0.5,1;0,0,1,1.5])
 
 ## Test input validation
-%!error wilkinson ()
-%!error wilkinson (1,2)
+%!error <Invalid call> wilkinson ()
 %!error <N must be a non-negative integer> wilkinson (ones (2))
 %!error <N must be a non-negative integer> wilkinson (-1)
 %!error <N must be a non-negative integer> wilkinson (1.5)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/statistics/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/statistics/bounds.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/bounds.m	Thu Nov 19 13:08:00 2020 -0800
@@ -48,7 +48,7 @@
 
 function [s, l] = bounds (x, dim, nanflag = false)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -119,8 +119,7 @@
 %! assert (l, x(:,:,3));
 
 ## Test input validation
-%!error bounds ()
-%!error bounds (1, 2, 3, 4)
+%!error <Invalid call> bounds ()
 %!error <X must be a numeric> bounds (['A'; 'B'])
 %!error <DIM must be an integer> bounds (1, ones (2,2))
 %!error <DIM must be an integer> bounds (1, 1.5)
--- a/scripts/statistics/center.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/center.m	Thu Nov 19 13:08:00 2020 -0800
@@ -44,7 +44,7 @@
 
 function retval = center (x, dim)
 
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -92,8 +92,7 @@
 %!assert (center (1, 3), 0)
 
 ## Test input validation
-%!error center ()
-%!error center (1, 2, 3)
+%!error <Invalid call> center ()
 %!error <DIM must be an integer> center (1, ones (2,2))
 %!error <DIM must be an integer> center (1, 1.5)
 %!error <DIM must be .* a valid dimension> center (1, 0)
--- a/scripts/statistics/corr.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/corr.m	Thu Nov 19 13:08:00 2020 -0800
@@ -51,7 +51,7 @@
 
 function retval = corr (x, y = [])
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -107,8 +107,7 @@
 %!assert (corr (single (5)), single (1))
 
 ## Test input validation
-%!error corr ()
-%!error corr (1, 2, 3)
+%!error <Invalid call> corr ()
 %!error corr ([1; 2], ["A", "B"])
 %!error corr (ones (2,2,2))
 %!error corr (ones (2,2), ones (2,2,2))
--- a/scripts/statistics/corrcoef.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/corrcoef.m	Thu Nov 19 13:08:00 2020 -0800
@@ -284,7 +284,7 @@
 %! r = corrcoef (x, y);
 %! assert (r, [1, NaN; NaN, 1]);
 
-%!error corrcoef ()
+%!error <Invalid call> corrcoef ()
 %!error <parameter 1 must be a string> corrcoef (1, 2, 3)
 %!error <parameter "alpha" missing value> corrcoef (1, 2, "alpha")
 %!error <"alpha" must be a scalar> corrcoef (1,2, "alpha", "1")
--- a/scripts/statistics/cov.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/cov.m	Thu Nov 19 13:08:00 2020 -0800
@@ -79,7 +79,7 @@
 
 function c = cov (x, y = [], opt = 0)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -171,10 +171,9 @@
 %! assert (c, 2);
 
 ## Test input validation
-%!error cov ()
-%!error cov (1, 2, 3, 4)
+%!error <Invalid call> cov ()
 %!error cov ([1; 2], ["A", "B"])
 %!error cov (ones (2,2,2))
 %!error cov (ones (2,2), ones (2,2,2))
-%!error cov (1, 3)
+%!error <normalization OPT must be 0 or 1> cov (1, 3)
 %!error cov (ones (2,2), ones (3,2))
--- a/scripts/statistics/discrete_cdf.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/discrete_cdf.m	Thu Nov 19 13:08:00 2020 -0800
@@ -64,7 +64,7 @@
 %!shared x,v,p,y
 %! x = [-1 0.1 1.1 1.9 3];
 %! v = 0.1:0.2:1.9;
-%! p = 1/length(v) * ones (1, length(v));
+%! p = 1/length (v) * ones (1, length (v));
 %! y = [0 0.1 0.6 1 1];
 %!assert (discrete_cdf ([x, NaN], v, p), [y, NaN], eps)
 
@@ -74,10 +74,9 @@
 %!assert (discrete_cdf ([x, NaN], v, single (p)), single ([y, NaN]), 2*eps ("single"))
 
 ## Test input validation
-%!error discrete_cdf ()
-%!error discrete_cdf (1)
-%!error discrete_cdf (1,2)
-%!error discrete_cdf (1,2,3,4)
+%!error <Invalid call> discrete_cdf ()
+%!error <Invalid call> discrete_cdf (1)
+%!error <Invalid call> discrete_cdf (1,2)
 %!error discrete_cdf (1, ones (2), ones (2,1))
 %!error discrete_cdf (1, [1 ; NaN], ones (2,1))
 %!error discrete_cdf (1, ones (2,1), ones (1,1))
--- a/scripts/statistics/discrete_inv.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/discrete_inv.m	Thu Nov 19 13:08:00 2020 -0800
@@ -76,7 +76,7 @@
 %!shared x,v,p,y
 %! x = [-1 0 0.1 0.5 1 2];
 %! v = 0.1:0.2:1.9;
-%! p = 1/length(v) * ones (1, length(v));
+%! p = 1/length (v) * ones (1, length (v));
 %! y = [NaN v(1) v(1) v(end/2) v(end) NaN];
 %!assert (discrete_inv ([x, NaN], v, p), [y, NaN], eps)
 
@@ -86,10 +86,9 @@
 %!assert (discrete_inv ([x, NaN], v, single (p)), single ([y, NaN]), eps ("single"))
 
 ## Test input validation
-%!error discrete_inv ()
-%!error discrete_inv (1)
-%!error discrete_inv (1,2)
-%!error discrete_inv (1,2,3,4)
+%!error <Invalid call> discrete_inv ()
+%!error <Invalid call> discrete_inv (1)
+%!error <Invalid call> discrete_inv (1,2)
 %!error discrete_inv (1, ones (2), ones (2,1))
 %!error discrete_inv (1, ones (2,1), ones (1,1))
 %!error discrete_inv (1, ones (2,1), [1 NaN])
--- a/scripts/statistics/discrete_pdf.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/discrete_pdf.m	Thu Nov 19 13:08:00 2020 -0800
@@ -75,10 +75,9 @@
 %!assert (discrete_pdf ([x, NaN], v, single (p)), single ([y, NaN]), 5*eps ("single"))
 
 ## Test input validation
-%!error discrete_pdf ()
-%!error discrete_pdf (1)
-%!error discrete_pdf (1,2)
-%!error discrete_pdf (1,2,3,4)
+%!error <Invalid call> discrete_pdf ()
+%!error <Invalid call> discrete_pdf (1)
+%!error <Invalid call> discrete_pdf (1,2)
 %!error discrete_pdf (1, ones (2), ones (2,1))
 %!error discrete_pdf (1, [1 ; NaN], ones (2,1))
 %!error discrete_pdf (1, ones (2,1), ones (1,1))
--- a/scripts/statistics/discrete_rnd.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/discrete_rnd.m	Thu Nov 19 13:08:00 2020 -0800
@@ -88,11 +88,11 @@
 %!assert (class (discrete_rnd (1:2, 1:2)), "double")
 %!assert (class (discrete_rnd (single (1:2), 1:2)), "single")
 ## FIXME: Maybe this should work, maybe it shouldn't.
-#%!assert(class (discrete_rnd (1:2, single(1:2))), "single")
+#%!assert (class (discrete_rnd (1:2, single(1:2))), "single")
 
 ## Test input validation
-%!error discrete_rnd ()
-%!error discrete_rnd (1)
+%!error <Invalid call> discrete_rnd ()
+%!error <Invalid call> discrete_rnd (1)
 %!error discrete_rnd (1:2,1:2, -1)
 %!error discrete_rnd (1:2,1:2, ones (2))
 %!error discrete_rnd (1:2,1:2, [2 -1 2])
--- a/scripts/statistics/empirical_cdf.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/empirical_cdf.m	Thu Nov 19 13:08:00 2020 -0800
@@ -58,7 +58,6 @@
 %!assert (empirical_cdf ([x, NaN], single (v)), single ([y, NaN]), eps)
 
 ## Test input validation
-%!error empirical_cdf ()
-%!error empirical_cdf (1)
-%!error empirical_cdf (1,2,3)
+%!error <Invalid call> empirical_cdf ()
+%!error <Invalid call> empirical_cdf (1)
 %!error empirical_cdf (1, ones (2))
--- a/scripts/statistics/empirical_inv.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/empirical_inv.m	Thu Nov 19 13:08:00 2020 -0800
@@ -57,7 +57,6 @@
 %!assert (empirical_inv ([x, NaN], single (v)), single ([y, NaN]), eps)
 
 ## Test input validation
-%!error empirical_inv ()
-%!error empirical_inv (1)
-%!error empirical_inv (1,2,3)
+%!error <Invalid call> empirical_inv ()
+%!error <Invalid call> empirical_inv (1)
 %!error empirical_inv (1, ones (2))
--- a/scripts/statistics/empirical_pdf.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/empirical_pdf.m	Thu Nov 19 13:08:00 2020 -0800
@@ -68,7 +68,6 @@
 %!assert (empirical_pdf (2, [1 2 3 2]), 0.5)
 
 ## Test input validation
-%!error empirical_pdf ()
-%!error empirical_pdf (1)
-%!error empirical_pdf (1,2,3)
+%!error <Invalid call> empirical_pdf ()
+%!error <Invalid call> empirical_pdf (1)
 %!error empirical_inv (1, ones (2))
--- a/scripts/statistics/empirical_rnd.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/empirical_rnd.m	Thu Nov 19 13:08:00 2020 -0800
@@ -65,6 +65,6 @@
 %!assert (class (empirical_rnd (single (1:2), 1)), "single")
 
 ## Test input validation
-%!error empirical_rnd ()
+%!error <Invalid call> empirical_rnd ()
 %!error empirical_rnd (ones (2), 1)
 %!error empirical_rnd (ones (2), 1, 1)
--- a/scripts/statistics/histc.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/histc.m	Thu Nov 19 13:08:00 2020 -0800
@@ -62,7 +62,7 @@
 
 function [n, idx] = histc (x, edges, dim)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -188,9 +188,9 @@
 %! n = histc (x, 0:10, 2);
 %! assert (n, repmat ([repmat(100, 1, 10), 1], [2, 1, 3]));
 
-%!error histc ()
-%!error histc (1)
-%!error histc (1, 2, 3, 4)
+## Test input validation
+%!error <Invalid call> histc ()
+%!error <Invalid call> histc (1)
 %!error histc ([1:10 1+i], 2)
 %!warning <empty EDGES specified> histc (1:10, []);
 %!error histc (1, 1, 3)
--- a/scripts/statistics/iqr.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/iqr.m	Thu Nov 19 13:08:00 2020 -0800
@@ -41,7 +41,7 @@
 
 function y = iqr (x, dim)
 
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -97,8 +97,7 @@
 %! assert (iqr (x, 1), 50);
 %! assert (iqr (x', 2), 50);
 
-%!error iqr ()
-%!error iqr (1, 2, 3)
+%!error <Invalid call> iqr ()
 %!error iqr (1)
 %!error iqr (['A'; 'B'])
 %!error iqr (1:10, 3)
--- a/scripts/statistics/kendall.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/kendall.m	Thu Nov 19 13:08:00 2020 -0800
@@ -93,7 +93,7 @@
 
 function tau = kendall (x, y = [])
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -148,8 +148,7 @@
 %!assert (kendall (single (1)), single (1))
 
 ## Test input validation
-%!error kendall ()
-%!error kendall (1, 2, 3)
+%!error <Invalid call> kendall ()
 %!error kendall (['A'; 'B'])
 %!error kendall (ones (2,1), ['A'; 'B'])
 %!error kendall (ones (2,2,2))
--- a/scripts/statistics/kurtosis.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/kurtosis.m	Thu Nov 19 13:08:00 2020 -0800
@@ -88,7 +88,7 @@
 
 function y = kurtosis (x, flag, dim)
 
-  if (nargin < 1) || (nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -162,8 +162,7 @@
 %! assert (lastwarn (), "");
 
 ## Test input validation
-%!error kurtosis ()
-%!error kurtosis (1, 2, 3)
+%!error <Invalid call> kurtosis ()
 %!error <X must be a numeric vector or matrix> kurtosis (['A'; 'B'])
 %!error <FLAG must be 0 or 1> kurtosis (1, 2)
 %!error <FLAG must be 0 or 1> kurtosis (1, [1 0])
--- a/scripts/statistics/mad.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/mad.m	Thu Nov 19 13:08:00 2020 -0800
@@ -58,7 +58,7 @@
 
 function retval = mad (x, opt = 0, dim)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -105,8 +105,7 @@
 %!assert (mad (magic (4), 1, 2), [5.5; 1.5; 1.5; 5.5])
 
 ## Test input validation
-%!error mad ()
-%!error mad (1, 2, 3, 4)
+%!error <Invalid call> mad ()
 %!error <X must be a numeric> mad (['A'; 'B'])
 %!error <OPT must be 0 or 1> mad (1, 2)
 %!error <DIM must be an integer> mad (1, [], ones (2,2))
--- a/scripts/statistics/mean.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/mean.m	Thu Nov 19 13:08:00 2020 -0800
@@ -179,6 +179,7 @@
       ## this should have been filtered out during input check, but...
       error ("mean: OUTTYPE '%s' not recognized", out_type);
   endswitch
+
 endfunction
 
 
@@ -217,25 +218,25 @@
 %!test
 %! in = [1 2 3];
 %! out = 2;
-%! assert (mean (in, "default"), mean (in))
-%! assert (mean (in, "default"), out)
+%! assert (mean (in, "default"), mean (in));
+%! assert (mean (in, "default"), out);
 %!
 %! in = single ([1 2 3]);
 %! out = 2;
-%! assert (mean (in, "default"), mean (in))
-%! assert (mean (in, "default"), single (out))
-%! assert (mean (in, "double"), out)
-%! assert (mean (in, "native"), single (out))
+%! assert (mean (in, "default"), mean (in));
+%! assert (mean (in, "default"), single (out));
+%! assert (mean (in, "double"), out);
+%! assert (mean (in, "native"), single (out));
 %!
 %! in = uint8 ([1 2 3]);
 %! out = 2;
-%! assert (mean (in, "default"), mean (in))
-%! assert (mean (in, "default"), out)
-%! assert (mean (in, "double"), out)
-%! assert (mean (in, "native"), uint8 (out))
+%! assert (mean (in, "default"), mean (in));
+%! assert (mean (in, "default"), out);
+%! assert (mean (in, "double"), out);
+%! assert (mean (in, "native"), uint8 (out));
 %!
 %! in = logical ([1 0 1]);
 %! out = 2/3;
-%! assert (mean (in, "default"), mean (in))
-%! assert (mean (in, "default"), out)
-%! assert (mean (in, "native"), out) # logical ignores native option
+%! assert (mean (in, "default"), mean (in));
+%! assert (mean (in, "default"), out);
+%! assert (mean (in, "native"), out);  # logical ignores native option
--- a/scripts/statistics/meansq.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/meansq.m	Thu Nov 19 13:08:00 2020 -0800
@@ -57,7 +57,7 @@
 
 function y = meansq (x, dim)
 
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -88,8 +88,7 @@
 %!assert (meansq ([1 2], 3), [1 4])
 
 ## Test input validation
-%!error meansq ()
-%!error meansq (1, 2, 3)
+%!error <Invalid call> meansq ()
 %!error <X must be a numeric> meansq (['A'; 'B'])
 %!error <DIM must be an integer> meansq (1, ones (2,2))
 %!error <DIM must be an integer> meansq (1, 1.5)
--- a/scripts/statistics/median.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/median.m	Thu Nov 19 13:08:00 2020 -0800
@@ -62,7 +62,7 @@
 
 function retval = median (x, dim)
 
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -138,8 +138,7 @@
 %!assert (median (single ([1, 3, NaN])), single (NaN))
 
 ## Test input validation
-%!error median ()
-%!error median (1, 2, 3)
+%!error <Invalid call> median ()
 %!error <X must be a numeric> median ({1:5})
 %!error <X cannot be an empty matrix> median ([])
 %!error <DIM must be an integer> median (1, ones (2,2))
--- a/scripts/statistics/mode.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/mode.m	Thu Nov 19 13:08:00 2020 -0800
@@ -45,7 +45,7 @@
 
 function [m, f, c] = mode (x, dim)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -182,8 +182,7 @@
 %! assert (c{3}, [1; 2; 3]);
 
 ## Test input validation
-%!error mode ()
-%!error mode (1, 2, 3)
+%!error <Invalid call> mode ()
 %!error <X must be a numeric> mode ({1 2 3})
 %!error <DIM must be an integer> mode (1, ones (2,2))
 %!error <DIM must be an integer> mode (1, 1.5)
--- a/scripts/statistics/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/bounds.m \
   %reldir%/center.m \
   %reldir%/corr.m \
--- a/scripts/statistics/moment.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/moment.m	Thu Nov 19 13:08:00 2020 -0800
@@ -130,7 +130,7 @@
 
 function m = moment (x, p, opt1, opt2)
 
-  if (nargin < 2 || nargin > 4)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -206,9 +206,8 @@
 %!assert (moment (1, 2, 4), 0)
 
 ## Test input validation
-%!error moment ()
-%!error moment (1)
-%!error moment (1, 2, 3, 4, 5)
+%!error <Invalid call> moment ()
+%!error <Invalid call> moment (1)
 %!error <X must be a non-empty numeric matrix> moment (['A'; 'B'], 2)
 %!error <X must be a non-empty numeric matrix> moment (ones (2,0,3), 2)
 %!error <P must be a numeric scalar> moment (1, true)
--- a/scripts/statistics/movmad.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/movmad.m	Thu Nov 19 13:08:00 2020 -0800
@@ -123,7 +123,7 @@
 ## @end table
 ##
 ## Programming Note: This function is a wrapper which calls @code{movfun}.
-## For additional options and documentation, @pxref{XREFmovfun,,movfun}.
+## For additional options and documentation, @pxref{XREFmovfun,,@code{movfun}}.
 ##
 ## @seealso{movfun, movslice, movmax, movmean, movmedian, movmin, movprod, movstd, movsum, movvar}
 ## @end deftypefn
@@ -140,10 +140,9 @@
 
 
 ## FIXME: Need functional BIST tests
-# test for bug #55241
+## test for bug #55241
 %!assert ([0.5; repmat(2/3,8,1); 0.5], movmad ((1:10).', 3))
 
-
 ## Test input validation
-%!error movmad ()
-%!error movmad (1)
+%!error <Invalid call> movmad ()
+%!error <Invalid call> movmad (1)
--- a/scripts/statistics/movmax.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/movmax.m	Thu Nov 19 13:08:00 2020 -0800
@@ -123,7 +123,7 @@
 ## @end table
 ##
 ## Programming Note: This function is a wrapper which calls @code{movfun}.
-## For additional options and documentation, @pxref{XREFmovfun,,movfun}.
+## For additional options and documentation, @pxref{XREFmovfun,,@code{movfun}}.
 ##
 ## @seealso{movfun, movslice, movmad, movmean, movmedian, movmin, movprod, movstd, movsum, movvar}
 ## @end deftypefn
@@ -141,9 +141,9 @@
 
 
 ## FIXME: Need functional BIST tests
-# test for bug #55241
+## test for bug #55241
 %!assert ([(2:10).'; 10], movmax ((1:10).', 3))
 
 ## Test input validation
-%!error movmax ()
-%!error movmax (1)
+%!error <Invalid call> movmax ()
+%!error <Invalid call> movmax (1)
--- a/scripts/statistics/movmean.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/movmean.m	Thu Nov 19 13:08:00 2020 -0800
@@ -123,7 +123,7 @@
 ## @end table
 ##
 ## Programming Note: This function is a wrapper which calls @code{movfun}.
-## For additional options and documentation, @pxref{XREFmovfun,,movfun}.
+## For additional options and documentation, @pxref{XREFmovfun,,@code{movfun}}.
 ##
 ## @seealso{movfun, movslice, movmad, movmax, movmedian, movmin, movprod, movstd, movsum, movvar}
 ## @end deftypefn
@@ -140,9 +140,9 @@
 
 
 ## FIXME: Need functional BIST tests
-# test for bug #55241
+## test for bug #55241
 %!assert ([1.5; (2:9).'; 9.5], movmean ((1:10).', 3))
 
 ## Test input validation
-%!error movmean ()
-%!error movmean (1)
+%!error <Invalid call> movmean ()
+%!error <Invalid call> movmean (1)
--- a/scripts/statistics/movmedian.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/movmedian.m	Thu Nov 19 13:08:00 2020 -0800
@@ -123,7 +123,7 @@
 ## @end table
 ##
 ## Programming Note: This function is a wrapper which calls @code{movfun}.
-## For additional options and documentation, @pxref{XREFmovfun,,movfun}.
+## For additional options and documentation, @pxref{XREFmovfun,,@code{movfun}}.
 ##
 ## @seealso{movfun, movslice, movmad, movmax, movmean, movmin, movprod, movstd, movsum, movvar}
 ## @end deftypefn
@@ -140,9 +140,9 @@
 
 
 ## FIXME: Need functional BIST tests
-# test for bug #55241
+## test for bug #55241
 %!assert ([1.5; (2:9).'; 9.5], movmedian ((1:10).', 3))
 
 ## Test input validation
-%!error movmedian ()
-%!error movmedian (1)
+%!error <Invalid call> movmedian ()
+%!error <Invalid call> movmedian (1)
--- a/scripts/statistics/movmin.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/movmin.m	Thu Nov 19 13:08:00 2020 -0800
@@ -123,7 +123,7 @@
 ## @end table
 ##
 ## Programming Note: This function is a wrapper which calls @code{movfun}.
-## For additional options and documentation, @pxref{XREFmovfun,,movfun}.
+## For additional options and documentation, @pxref{XREFmovfun,,@code{movfun}}.
 ##
 ## @seealso{movfun, movslice, movmad, movmax, movmean, movmedian, movprod, movstd, movsum, movvar}
 ## @end deftypefn
@@ -141,9 +141,9 @@
 
 
 ## FIXME: Need functional BIST tests
-# test for bug #55241
+## test for bug #55241
 %!assert ([1; (1:9).'], movmin ((1:10).', 3))
 
 ## Test input validation
-%!error movmin ()
-%!error movmin (1)
+%!error <Invalid call> movmin ()
+%!error <Invalid call> movmin (1)
--- a/scripts/statistics/movprod.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/movprod.m	Thu Nov 19 13:08:00 2020 -0800
@@ -123,7 +123,7 @@
 ## @end table
 ##
 ## Programming Note: This function is a wrapper which calls @code{movfun}.
-## For additional options and documentation, @pxref{XREFmovfun,,movfun}.
+## For additional options and documentation, @pxref{XREFmovfun,,@code{movfun}}.
 ##
 ## @seealso{movfun, movslice, movmad, movmax, movmean, movmedian, movmin, movstd, movsum, movvar}
 ## @end deftypefn
@@ -141,9 +141,9 @@
 
 
 ## FIXME: Need functional BIST tests
-# test for bug #55241
+## test for bug #55241
 %!assert ([2; 6; 24; 60; 120; 210; 336; 504; 720; 90], movprod ((1:10).', 3))
 
 ## Test input validation
-%!error movprod ()
-%!error movprod (1)
+%!error <Invalid call> movprod ()
+%!error <Invalid call> movprod (1)
--- a/scripts/statistics/movstd.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/movstd.m	Thu Nov 19 13:08:00 2020 -0800
@@ -138,7 +138,7 @@
 ## @end table
 ##
 ## Programming Note: This function is a wrapper which calls @code{movfun}.
-## For additional options and documentation, @pxref{XREFmovfun,,movfun}.
+## For additional options and documentation, @pxref{XREFmovfun,,@code{movfun}}.
 ##
 ## @seealso{movfun, movslice, movmad, movmax, movmean, movmedian, movmin, movprod, movsum, movvar}
 ## @end deftypefn
@@ -167,7 +167,7 @@
 
 
 ## FIXME: Need functional BIST tests
-# test for bug #55241
+## test for bug #55241
 %!assert ([1/sqrt(2); ones(8,1); 1/sqrt(2)], movstd ((1:10).', 3), 1e-8)
 
 %!test <*56765>
@@ -179,5 +179,5 @@
 %! assert (y1(1:3), sqrt ([1/4, 2/3, 5/4]));
 
 ## Test input validation
-%!error movstd ()
-%!error movstd (1)
+%!error <Invalid call> movstd ()
+%!error <Invalid call> movstd (1)
--- a/scripts/statistics/movsum.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/movsum.m	Thu Nov 19 13:08:00 2020 -0800
@@ -123,7 +123,7 @@
 ## @end table
 ##
 ## Programming Note: This function is a wrapper which calls @code{movfun}.
-## For additional options and documentation, @pxref{XREFmovfun,,movfun}.
+## For additional options and documentation, @pxref{XREFmovfun,,@code{movfun}}.
 ##
 ## @seealso{movfun, movslice, movmad, movmax, movmean, movmedian, movmin, movprod, movstd, movvar}
 ## @end deftypefn
@@ -141,9 +141,9 @@
 
 
 ## FIXME: Need functional BIST tests
-# test for bug #55241
+## test for bug #55241
 %!assert ([(3:3:27).'; 19], movsum ((1:10).', 3))
 
 ## Test input validation
-%!error movsum ()
-%!error movsum (1)
+%!error <Invalid call> movsum ()
+%!error <Invalid call> movsum (1)
--- a/scripts/statistics/movvar.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/movvar.m	Thu Nov 19 13:08:00 2020 -0800
@@ -137,7 +137,7 @@
 ## @end table
 ##
 ## Programming Note: This function is a wrapper which calls @code{movfun}.
-## For additional options and documentation, @pxref{XREFmovfun,,movfun}.
+## For additional options and documentation, @pxref{XREFmovfun,,@code{movfun}}.
 ##
 ## @seealso{movfun, movslice, movmad, movmax, movmean, movmedian, movmin, movprod, movstd, movsum}
 ## @end deftypefn
@@ -166,7 +166,7 @@
 
 
 ## FIXME: Need functional BIST tests
-# test for bug #55241
+## test for bug #55241
 %!assert ([0.5; ones(8,1); 0.5], movvar ((1:10).', 3))
 
 %!test <*56765>
@@ -178,5 +178,5 @@
 %! assert (y1(1:3), [1/4, 2/3, 5/4]);
 
 ## Test input validation
-%!error movvar ()
-%!error movvar (1)
+%!error <Invalid call> movvar ()
+%!error <Invalid call> movvar (1)
--- a/scripts/statistics/prctile.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/prctile.m	Thu Nov 19 13:08:00 2020 -0800
@@ -46,7 +46,7 @@
 
 function q = prctile (x, p = [], dim)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -180,8 +180,7 @@
 %! assert (q, qa, tol);
 
 ## Test input validation
-%!error prctile ()
-%!error prctile (1, 2, 3, 4)
+%!error <Invalid call> prctile ()
 %!error prctile (['A'; 'B'], 10)
 %!error prctile (1:10, [true, false])
 %!error prctile (1:10, ones (2,2))
--- a/scripts/statistics/quantile.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/quantile.m	Thu Nov 19 13:08:00 2020 -0800
@@ -156,7 +156,7 @@
 
 function q = quantile (x, p = [], dim, method = 5)
 
-  if (nargin < 1 || nargin > 4)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -384,8 +384,7 @@
 %!assert <*54421> (quantile ([1:10], [0.25, 0.75]'), [3; 8])
 
 ## Test input validation
-%!error quantile ()
-%!error quantile (1, 2, 3, 4, 5)
+%!error <Invalid call> quantile ()
 %!error quantile (['A'; 'B'], 10)
 %!error quantile (1:10, [true, false])
 %!error quantile (1:10, ones (2,2))
@@ -405,7 +404,7 @@
 ## Description: Quantile function of empirical samples
 function inv = __quantile__ (x, p, method = 5)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ("quantile");
   endif
 
--- a/scripts/statistics/range.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/range.m	Thu Nov 19 13:08:00 2020 -0800
@@ -42,7 +42,7 @@
 
 function y = range (x, dim)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -62,5 +62,4 @@
 %!assert (range (2), 0)
 
 ## Test input validation
-%!error range ()
-%!error range (1, 2, 3)
+%!error <Invalid call> range ()
--- a/scripts/statistics/ranks.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/ranks.m	Thu Nov 19 13:08:00 2020 -0800
@@ -53,7 +53,7 @@
 
 function y = ranks (x, dim, rtype = 0)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -105,7 +105,7 @@
       otherwise
         if (! ischar (rtype))
           rtype = num2str (rtype);
-        end
+        endif
         error ("ranks: unknown RTYPE '%s'", rtype);
     endswitch
 
@@ -164,8 +164,7 @@
 %!assert (ranks ([1, 2, 2, 4], [], "dense"), [1, 2, 2, 3])
 
 ## Test input validation
-%!error ranks ()
-%!error ranks (1, 2, 3, 4)
+%!error <Invalid call> ranks ()
 %!error <X must be a numeric vector or matrix> ranks ({1, 2})
 %!error <X must be a numeric vector or matrix> ranks (['A'; 'B'])
 %!error <DIM must be an integer> ranks (1, 1.5)
--- a/scripts/statistics/run_count.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/run_count.m	Thu Nov 19 13:08:00 2020 -0800
@@ -36,7 +36,7 @@
 
 function retval = run_count (x, n, dim)
 
-  if (nargin != 2 && nargin != 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -103,9 +103,8 @@
 %!assert (run_count (ones (3), 4), [0,0,0;0,0,0;1,1,1;0,0,0])
 
 ## Test input validation
-%!error run_count ()
-%!error run_count (1)
-%!error run_count (1, 2, 3, 4)
+%!error <Invalid call> run_count ()
+%!error <Invalid call> run_count (1)
 %!error run_count ({1, 2}, 3)
 %!error run_count (['A'; 'A'; 'B'], 3)
 %!error run_count (1:5, ones (2,2))
--- a/scripts/statistics/runlength.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/runlength.m	Thu Nov 19 13:08:00 2020 -0800
@@ -44,7 +44,7 @@
 
 function [count, value] = runlength (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -73,7 +73,6 @@
 %! assert (v, [2 0 4 0 1]);
 
 ## Test input validation
-%!error runlength ()
-%!error runlength (1, 2)
+%!error <Invalid call> runlength ()
 %!error runlength (['A'; 'B'])
 %!error runlength (ones (2,2))
--- a/scripts/statistics/skewness.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/skewness.m	Thu Nov 19 13:08:00 2020 -0800
@@ -87,7 +87,7 @@
 
 function y = skewness (x, flag, dim)
 
-  if (nargin < 1) || (nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -161,8 +161,7 @@
 %! assert (lastwarn (), "");
 
 ## Test input validation
-%!error skewness ()
-%!error skewness (1, 2, 3)
+%!error <Invalid call> skewness ()
 %!error <X must be a numeric vector or matrix> skewness (['A'; 'B'])
 %!error <FLAG must be 0 or 1> skewness (1, 2)
 %!error <FLAG must be 0 or 1> skewness (1, [1 0])
--- a/scripts/statistics/spearman.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/spearman.m	Thu Nov 19 13:08:00 2020 -0800
@@ -68,7 +68,7 @@
 
 function rho = spearman (x, y = [])
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -114,8 +114,7 @@
 %!assert (spearman ([1 2 3], [-1 1 -2]), -0.5, 5*eps)
 
 ## Test input validation
-%!error spearman ()
-%!error spearman (1, 2, 3)
+%!error <Invalid call> spearman ()
 %!error spearman (['A'; 'B'])
 %!error spearman (ones (1,2), {1, 2})
 %!error spearman (ones (2,2,2))
--- a/scripts/statistics/statistics.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/statistics.m	Thu Nov 19 13:08:00 2020 -0800
@@ -39,7 +39,7 @@
 
 function stats = statistics (x, dim)
 
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -93,8 +93,7 @@
 %! assert (kurtosis (x, [], 2), s(:,9), eps);
 
 ## Test input validation
-%!error statistics ()
-%!error statistics (1, 2, 3)
+%!error <Invalid call> statistics ()
 %!error statistics (['A'; 'B'])
 %!error statistics (1, ones (2,2))
 %!error statistics (1, 1.5)
--- a/scripts/statistics/std.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/std.m	Thu Nov 19 13:08:00 2020 -0800
@@ -70,7 +70,7 @@
 
 function retval = std (x, opt = 0, dim)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -126,8 +126,7 @@
 %!assert (std ([1 2 3], [], 3), [0 0 0])
 
 ## Test input validation
-%!error std ()
-%!error std (1, 2, 3, 4)
+%!error <Invalid call> std ()
 %!error <X must be a numeric> std (['A'; 'B'])
 %!error <OPT must be 0 or 1> std (1, 2)
 %!error <DIM must be an integer> std (1, [], ones (2,2))
--- a/scripts/statistics/var.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/var.m	Thu Nov 19 13:08:00 2020 -0800
@@ -74,7 +74,7 @@
 
 function retval = var (x, opt = 0, dim)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -123,8 +123,7 @@
 %!assert (var ([1,2,3], [], 3), [0,0,0])
 
 ## Test input validation
-%!error var ()
-%!error var (1,2,3,4)
+%!error <Invalid call> var ()
 %!error <X must be a numeric> var (['A'; 'B'])
 %!error <OPT must be 0 or 1> var (1, -1)
 %!error <FLAG must be 0 or 1> skewness (1, 2)
--- a/scripts/statistics/zscore.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/statistics/zscore.m	Thu Nov 19 13:08:00 2020 -0800
@@ -49,7 +49,7 @@
 
 function [z, mu, sigma] = zscore (x, opt = 0, dim)
 
-  if (nargin < 1 || nargin > 3 )
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -102,7 +102,7 @@
 %!assert <*54531> (zscore ([1,2,3], [], 2), [-1,0,1])
 
 ## Test input validation
-%!error zscore ()
+%!error <Invalid call> zscore ()
 %!error zscore (1, 2, 3)
 %!error <X must be a numeric> zscore (['A'; 'B'])
 %!error <OPT must be empty, 0, or 1> zscore (1, ones (2,2))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/strings/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/strings/base2dec.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/base2dec.m	Thu Nov 19 13:08:00 2020 -0800
@@ -115,7 +115,7 @@
 
   ## Multiply the resulting digits by the appropriate power
   ## and sum the rows.
-  out = s * (base .^ (columns(s)-1 : -1 : 0)');
+  out = s * (base .^ (columns (s)-1 : -1 : 0)');
 
 endfunction
 
@@ -128,7 +128,7 @@
 %!assert <*35621> (base2dec (["0"; "1"], 2), [0; 1])
 
 ## Test input validation
-%!error base2dec ()
+%!error <Invalid call> base2dec ()
 %!error base2dec ("11120")
 %!error base2dec ("11120", 3, 4)
 %!error <symbols .* must be unique> base2dec ("11120", "1231")
--- a/scripts/strings/bin2dec.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/bin2dec.m	Thu Nov 19 13:08:00 2020 -0800
@@ -57,7 +57,7 @@
 
 function d = bin2dec (s)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -74,6 +74,5 @@
 %!assert (bin2dec (char ("1 0 1", "   1111")), [5; 15])
 
 ## Test input validation
-%!error bin2dec ()
-%!error bin2dec (1)
-%!error bin2dec ("1", 2)
+%!error <Invalid call> bin2dec ()
+%!error <S must be a string> bin2dec (1)
--- a/scripts/strings/blanks.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/blanks.m	Thu Nov 19 13:08:00 2020 -0800
@@ -44,7 +44,7 @@
 
 function s = blanks (n)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   elseif (! (isscalar (n) && n == fix (n) && n >= 0))
     error ("blanks: N must be a non-negative integer");
@@ -63,8 +63,7 @@
 %!assert (blanks (10), "          ")
 
 ## Test input validation
-%!error blanks ()
-%!error blanks (1, 2)
+%!error <Invalid call> blanks ()
 %!error blanks (ones (2))
 %!error blanks (2.1)
 %!error blanks (-2)
--- a/scripts/strings/deblank.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/deblank.m	Thu Nov 19 13:08:00 2020 -0800
@@ -47,7 +47,7 @@
 
 function s = deblank (s)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -102,5 +102,5 @@
 %!assert (deblank ({" abc   ", {"   def   "}}), {" abc", {"   def"}})
 
 %!error <Invalid call to deblank> deblank ()
-%!error <Invalid call to deblank> deblank ("foo", "bar")
+%!error <called with too many inputs> deblank ("foo", "bar")
 %!error <argument must be a string> deblank (1)
--- a/scripts/strings/dec2base.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/dec2base.m	Thu Nov 19 13:08:00 2020 -0800
@@ -58,7 +58,7 @@
 
 function retval = dec2base (d, base, len)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -163,9 +163,8 @@
 %!assert <*56005> (dec2base ([0, 0], 16), ["0"; "0"])
 
 ## Test input validation
-%!error dec2base ()
-%!error dec2base (1)
-%!error dec2base (1, 2, 3, 4)
+%!error <Invalid call> dec2base ()
+%!error <Invalid call> dec2base (1)
 %!error dec2base ("A")
 %!error dec2base (2i)
 %!error dec2base (-1)
--- a/scripts/strings/dec2bin.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/dec2bin.m	Thu Nov 19 13:08:00 2020 -0800
@@ -24,45 +24,111 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn {} {} dec2bin (@var{d}, @var{len})
-## Return a binary number corresponding to the non-negative integer @var{d},
-## as a string of ones and zeros.
+## @deftypefn  {} {} dec2bin (@var{d})
+## @deftypefnx {} {} dec2bin (@var{d}, @var{len})
+## Return a string of ones and zeros representing the conversion of the integer
+## @var{d} to a binary number.
 ##
-## For example:
+## If @var{d} is negative, return the two's complement binary value of @var{d}.
+## If @var{d} is a matrix or cell array, return a string matrix with one row
+## for each element in @var{d}, padded with leading zeros to the width of the
+## largest value.
+##
+## The optional second argument, @var{len}, specifies the minimum number of
+## digits in the result.
+##
+## Examples:
 ##
 ## @example
 ## @group
 ## dec2bin (14)
 ##      @result{} "1110"
+##
+## dec2bin (-14)
+##      @result{} "11110010"
 ## @end group
 ## @end example
 ##
-## If @var{d} is a matrix or cell array, return a string matrix with one row
-## per element in @var{d}, padded with leading zeros to the width of the
-## largest value.
+## Programming Notes: The largest negative value that can be converted in to
+## two's complement is @code{- (flintmax () / 2)}.
 ##
-## The optional second argument, @var{len}, specifies the minimum number of
-## digits in the result.
 ## @seealso{bin2dec, dec2base, dec2hex}
 ## @end deftypefn
 
 function b = dec2bin (d, len)
 
+  if (nargin == 0)
+    print_usage ();
+  endif
+
+  if (iscell (d))
+    d = cell2mat (d);
+  endif
+  ## Create column vector for algorithm (output is always col. vector anyways)
+  d = d(:);
+
+  lt_zero_idx = (d < 0);
+  if (any (lt_zero_idx))
+    ## FIXME: Need an algorithm that works with larger values such as int64.
+    if (any (d(lt_zero_idx) < -2^52))
+      error ("dec2bin: negative inputs cannot be less than -flintmax () / 2");
+    elseif (any (d(lt_zero_idx) < intmin ("int32")))
+      d(lt_zero_idx) += flintmax ();
+    elseif (any (d < intmin ("int16")))
+      d(lt_zero_idx) += double (intmax ("uint32")) + 1;
+    elseif (any (d < intmin ("int8")))
+      d(lt_zero_idx) += double (intmax ("uint16"))+ 1;
+    else
+      d(lt_zero_idx) += double (intmax ("uint8")) + 1;
+    endif
+  endif
+
   if (nargin == 1)
     b = dec2base (d, 2);
-  elseif (nargin == 2)
+  else
     b = dec2base (d, 2, len);
-  else
-    print_usage ();
   endif
 
 endfunction
 
 
+%!assert (dec2bin (3), "11")
 %!assert (dec2bin (14), "1110")
 %!assert (dec2bin (14, 6), "001110")
+%!assert (dec2bin ([1, 2; 3, 4]), ["001"; "011"; "010"; "100"])
 %!assert (dec2bin ({1, 2; 3, 4}), ["001"; "011"; "010"; "100"])
+%!assert (dec2bin ({1, 2; 3, 4}, 4), ["0001"; "0011"; "0010"; "0100"])
+
+## Test negative inputs
+%!assert (dec2bin (-3), "11111101")
+%!assert (dec2bin (-3, 3), "11111101")
+%!assert (dec2bin (-3, 9), "011111101")
+%!assert (dec2bin (-2^7 -1), "1111111101111111")
+%!assert (dec2bin (-2^15 -1), "11111111111111110111111111111111")
+## FIXME: Matlab generates a string that is 64 characters long
+%!assert (dec2bin (-2^31 -1),
+%!        "11111111111111111111101111111111111111111111111111111")
+%!assert (dec2bin (-2^52),
+%!        "10000000000000000000000000000000000000000000000000000")
+## FIXME: Uncomment when support for int64 is added
+%!#assert (dec2bin (-2^63),
+%!        "1000000000000000000000000000000000000000000000000000000000000000")
+%!#test
+%! assert (dec2bin (int64 (-2^63)),
+%!        "1000000000000000000000000000000000000000000000000000000000000000");
+%!#test
+%! assert (dec2bin (int64 (-2^63) -1),
+%!        "1000000000000000000000000000000000000000000000000000000000000000");
+%!#test
+%! assert (dec2bin (int64 (-2^63) +1),
+%!        "1000000000000000000000000000000000000000000000000000000000000001");
+%!assert (dec2bin ([-1, -2; -3, -4]),
+%!        ["11111111"; "11111101"; "11111110"; "11111100"])
+%!assert (dec2bin ([1, 2; 3, -4]),
+%!        ["00000001"; "00000011"; "00000010"; "11111100"])
+%!assert (dec2bin ({1, 2; 3, -4}),
+%!        ["00000001"; "00000011"; "00000010"; "11111100"])
 
 ## Test input validation
-%!error dec2bin ()
-%!error dec2bin (1, 2, 3)
+%!error <Invalid call> dec2bin ()
+%!error <negative inputs cannot be less than> dec2bin (- flintmax ())
--- a/scripts/strings/dec2hex.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/dec2hex.m	Thu Nov 19 13:08:00 2020 -0800
@@ -24,36 +24,66 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn {} {} dec2hex (@var{d}, @var{len})
-## Return the hexadecimal string corresponding to the non-negative integer
-## @var{d}.
+## @deftypefn  {} {} dec2hex (@var{d})
+## @deftypefnx {} {} dec2hex (@var{d}, @var{len})
+## Return a string representing the conversion of the integer @var{d} to a
+## hexadecimal (base16) number.
 ##
-## For example:
+## If @var{d} is negative, return the two's complement binary value of @var{d}.
+## If @var{d} is a matrix or cell array, return a string matrix with one row
+## for each element in @var{d}, padded with leading zeros to the width of the
+## largest value.
+##
+## The optional second argument, @var{len}, specifies the minimum number of
+## digits in the result.
+##
+## Examples:
 ##
 ## @example
 ## @group
 ## dec2hex (2748)
 ##      @result{} "ABC"
+##
+## dec2hex (-2)
+##      @result{} "FE"
 ## @end group
 ## @end example
 ##
-## If @var{d} is a matrix or cell array, return a string matrix with one row
-## per element in @var{d}, padded with leading zeros to the width of the
-## largest value.
-##
-## The optional second argument, @var{len}, specifies the minimum number of
-## digits in the result.
 ## @seealso{hex2dec, dec2base, dec2bin}
 ## @end deftypefn
 
 function h = dec2hex (d, len)
 
+  if (nargin == 0)
+    print_usage ();
+  endif
+
+  if (iscell (d))
+    d = cell2mat (d);
+  endif
+  ## Create column vector for algorithm (output is always col. vector anyways)
+  d = d(:);
+
+  lt_zero_idx = (d < 0);
+  if (any (lt_zero_idx))
+    ## FIXME: Need an algorithm that works with larger values such as int64.
+    if (any (d(lt_zero_idx) < -2^52))
+      error ("dec2hex: negative inputs cannot be less than -flintmax () / 2");
+    elseif (any (d(lt_zero_idx) < intmin ("int32")))
+      d(lt_zero_idx) += flintmax ();
+    elseif (any (d < intmin ("int16")))
+      d(lt_zero_idx) += double (intmax ("uint32")) + 1;
+    elseif (any (d < intmin ("int8")))
+      d(lt_zero_idx) += double (intmax ("uint16"))+ 1;
+    else
+      d(lt_zero_idx) += double (intmax ("uint8")) + 1;
+    endif
+  endif
+
   if (nargin == 1)
     h = dec2base (d, 16);
-  elseif (nargin == 2)
+  else
     h = dec2base (d, 16, len);
-  else
-    print_usage ();
   endif
 
 endfunction
@@ -61,8 +91,36 @@
 
 %!assert (dec2hex (2748), "ABC")
 %!assert (dec2hex (2748, 5), "00ABC")
+%!assert (dec2hex ([2748, 2746]), ["ABC"; "ABA"])
 %!assert (dec2hex ({2748, 2746}), ["ABC"; "ABA"])
+%!assert (dec2hex ({2748, 2746}, 4), ["0ABC"; "0ABA"])
+
+## Test negative inputs
+%!assert (dec2hex (-3), "FD")
+%!assert (dec2hex (-3, 1), "FD")
+%!assert (dec2hex (-3, 3), "0FD")
+%!assert (dec2hex (-2^7 -1), "FF7F")
+%!assert (dec2hex (-2^15 -1), "FFFF7FFF")
+## FIXME: Matlab returns longer string that begins with 'F'
+%!assert (dec2hex (-2^31 -1), "1FFFFF7FFFFFFF")
+## FIXME: Matlab returns longer string that begins with 'FFF'
+%!assert (dec2hex (-2^52), "10000000000000")
+## FIXME: Uncomment when support for int64 is added
+%!#assert (dec2hex (-2^63),
+%!        "1000000000000000000000000000000000000000000000000000000000000000")
+%!#test
+%! assert (dec2hex (int64 (-2^63)),
+%!        "1000000000000000000000000000000000000000000000000000000000000000");
+%!#test
+%! assert (dec2hex (int64 (-2^63) -1),
+%!        "1000000000000000000000000000000000000000000000000000000000000000");
+%!#test
+%! assert (dec2hex (int64 (-2^63) +1),
+%!        "1000000000000000000000000000000000000000000000000000000000000001");
+%!assert (dec2hex ([-1, -2; -3, -4]), ["FF"; "FD"; "FE"; "FC"])
+%!assert (dec2hex ([1, 2; 3, -4]), ["01"; "03"; "02"; "FC"])
+%!assert (dec2hex ({1, 2; 3, -4}), ["01"; "03"; "02"; "FC"])
 
 ## Test input validation
-%!error dec2hex ()
-%!error dec2hex (1, 2, 3)
+%!error <Invalid call> dec2hex ()
+%!error <negative inputs cannot be less than> dec2hex (- flintmax ())
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/strings/endsWith.m	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,173 @@
+########################################################################
+##
+## Copyright (C) 2020 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn  {} {@var{retval} =} endsWith (@var{str}, @var{pattern})
+## @deftypefnx {} {@var{retval} =} endsWith (@var{str}, @var{pattern}, "IgnoreCase", @var{ignore_case})
+## Check whether string(s) end with pattern(s).
+##
+## Return an array of logical values that indicates which string(s) in the
+## input @var{str} (a single string or cell array of strings) end with
+## the input @var{pattern} (a single string or cell array of strings).
+##
+## If the value of the parameter @qcode{"IgnoreCase"} is true, then the
+## function will ignore the letter case of @var{str} and @var{pattern}.  By
+## default, the comparison is case sensitive.
+##
+## Examples:
+##
+## @example
+## @group
+## ## one string and one pattern while considering case
+## endsWith ("hello", "lo")
+##       @result{}  1
+## @end group
+##
+## @group
+## ## one string and one pattern while ignoring case
+## endsWith ("hello", "LO", "IgnoreCase", true)
+##       @result{}  1
+## @end group
+##
+## @group
+## ## multiple strings and multiple patterns while considering case
+## endsWith (@{"tests.txt", "mydoc.odt", "myFunc.m", "results.pptx"@},
+##           @{".docx", ".odt", ".txt"@})
+##       @result{}  1  1  0  0
+## @end group
+##
+## @group
+## ## multiple strings and one pattern while considering case
+## endsWith (@{"TESTS.TXT", "mydoc.odt", "result.txt", "myFunc.m"@},
+##           ".txt", "IgnoreCase", false)
+##       @result{}  0  0  1  0
+## @end group
+##
+## @group
+## ## multiple strings and one pattern while ignoring case
+## endsWith (@{"TESTS.TXT", "mydoc.odt", "result.txt", "myFunc.m"@},
+##           ".txt", "IgnoreCase", true)
+##       @result{}  1  0  1  0
+## @end group
+## @end example
+##
+## @seealso{startsWith, regexp, strncmp, strncmpi}
+## @end deftypefn
+
+function retval = endsWith (str, pattern, IgnoreCase, ignore_case)
+
+  if (nargin != 2 && nargin != 4)
+    print_usage ();
+  endif
+
+  ## Validate input str and pattern
+  if (! (iscellstr (str) || ischar (str)))
+    error ("endsWith: STR must be a string or cell array of strings");
+  endif
+  if (! (iscellstr (pattern) || ischar (pattern)))
+    error ("endsWith: PATTERN must be a string or cell array of strings");
+  endif
+
+  ## reverse str and pattern
+  str = cellfun (@flip, cellstr (str), "UniformOutput", false);
+  pattern = cellfun (@flip, cellstr (pattern), "UniformOutput", false);
+
+  if (nargin == 2)
+    ignore_case = false;
+  else
+    ## For Matlab compatibility accept any abbreviation of 3rd argument
+    if (! ischar (IgnoreCase) || isempty (IgnoreCase)
+        || ! strncmpi (IgnoreCase, "IgnoreCase", length (IgnoreCase)))
+      error ('endsWith: third input must be "IgnoreCase"');
+    endif
+
+    if (! isscalar (ignore_case) || ! isreal (ignore_case))
+      error ('endsWith: "IgnoreCase" value must be a logical scalar');
+    endif
+    ignore_case = logical (ignore_case);
+  endif
+
+  retval = false (size (str));
+  if (ignore_case)
+    for j = 1:numel (pattern)
+      retval |= strncmpi (str, pattern{j}, length (pattern{j}));
+    endfor
+  else
+    for j = 1:numel (pattern)
+      retval |= strncmp (str, pattern{j}, length (pattern{j}));
+    endfor
+  endif
+
+endfunction
+
+
+## Test simple use with one string and one pattern
+%!assert (endsWith ("hello", "lo"))
+%!assert (! endsWith ("hello", "LO"))
+%!assert (endsWith ("hello", "LO", "i", 5))
+%!assert (! endsWith ("hello", "no"))
+
+## Test multiple strings with a single pattern
+%!test
+%! str = {"myFile.odt", "results.ppt", "myCode.m"; ...
+%!        "data-analysis.ppt", "foundations.txt", "data.odt"};
+%! pattern = ".odt";
+%! expected = [true, false, false; false, false, true];
+%! assert (endsWith (str, pattern), expected);
+
+## Test multiple strings with multiple patterns
+%!test
+%! str = {"tests.txt", "mydoc.odt", "myFunc.m", "results.pptx"};
+%! pattern = {".docx", ".odt", ".txt"};
+%! expected = [true, true, false, false];
+%! assert (endsWith (str, pattern), expected);
+
+## Test IgnoreCase
+%!test
+%! str = {"TESTS.TXT", "mydoc.odt", "result.txt", "myFunc.m"};
+%! pattern = ".txt";
+%! expected_ignore = [true, false, true, false];
+%! expected_wo_ignore = [false, false, true, false];
+%! assert (endsWith (str, pattern, "IgnoreCase", true), expected_ignore);
+%! assert (endsWith (str, pattern, "IgnoreCase", false), expected_wo_ignore);
+%! assert (endsWith (str, pattern, "I", 500), expected_ignore);
+%! assert (endsWith (str, pattern, "iG", 0), expected_wo_ignore);
+
+## Test input validation
+%!error <Invalid call> endsWith ()
+%!error endsWith ("A")
+%!error endsWith ("A", "B", "C")
+%!error endsWith ("A", "B", "C", "D", "E")
+%!error <STR must be a string> endsWith (152, "hi")
+%!error <STR must be a .* cell array of strings> endsWith ({152}, "hi")
+%!error <PATTERN must be a string> endsWith ("hi", 152)
+%!error <PATTERN must be a .* cell array of strings> endsWith ("hi", {152})
+%!error <third input must be "IgnoreCase"> endsWith ("hello", "lo", 1, 1)
+%!error <third input must be "IgnoreCase"> endsWith ("hello", "lo", "", 1)
+%!error <third input must be "IgnoreCase"> endsWith ("hello", "lo", "foo", 1)
+%!error <"IgnoreCase" value must be a logical scalar>
+%! endsWith ("hello", "hi", "i", "true");
+%!error <"IgnoreCase" value must be a logical scalar>
+%! endsWith ("hello", "hi", "i", {true});
--- a/scripts/strings/erase.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/erase.m	Thu Nov 19 13:08:00 2020 -0800
@@ -64,7 +64,7 @@
 ## @end group
 ## @end example
 ##
-## See @code{strrep} for processing overlaps.
+## For processing overlaps, @pxref{XREFstrrep,,@code{strrep}}.
 ##
 ## @seealso{strrep, regexprep}
 ## @end deftypefn
@@ -143,7 +143,7 @@
 %!assert (erase ({'Hello World t '}, {'ld '; 'o '}), {'HellWort '})
 
 ## Test input validation
-%!error erase ()
+%!error <Invalid call> erase ()
 %!error erase ("a")
 %!error erase ("a", "b", "c")
 %!error <STR must be a string> erase ([1], "foo")
--- a/scripts/strings/hex2dec.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/hex2dec.m	Thu Nov 19 13:08:00 2020 -0800
@@ -50,7 +50,7 @@
 
 function d = hex2dec (s)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -65,6 +65,5 @@
 %!assert (hex2dec ({"A1", "1A"}), [161; 26])
 
 ## Test input validation
-%!error hex2dec ()
-%!error hex2dec (1)
-%!error hex2dec ("1", 2)
+%!error <Invalid call> hex2dec ()
+%!error <S must be a string> hex2dec (1)
--- a/scripts/strings/index.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/index.m	Thu Nov 19 13:08:00 2020 -0800
@@ -48,7 +48,7 @@
 
 function n = index (s, t, direction = "first")
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -113,7 +113,7 @@
 %! assert (index (str, "o", "last"), [5; 2; 3; 2]);
 
 ## Test input validation
-%!error index ()
+%!error <Invalid call> index ()
 %!error index ("a")
 %!error index ("a", "b", "first", "d")
 %!error index (1, "bar")
--- a/scripts/strings/isletter.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/isletter.m	Thu Nov 19 13:08:00 2020 -0800
@@ -34,7 +34,7 @@
 
 function retval = isletter (s)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -43,5 +43,5 @@
 endfunction
 
 
-%!error isletter ()
+%!error <Invalid call> isletter ()
 %!error isletter ("a", "b")
--- a/scripts/strings/isstring.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/isstring.m	Thu Nov 19 13:08:00 2020 -0800
@@ -42,7 +42,7 @@
 
 function retval = isstring (s)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -59,5 +59,5 @@
 %!assert (isstring ({'a'}), false)
 %!assert (isstring ({"b"}), false)
 
-%!error isstring ()
+%!error <Invalid call> isstring ()
 %!error isstring ("a", "b")
--- a/scripts/strings/isstrprop.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/isstrprop.m	Thu Nov 19 13:08:00 2020 -0800
@@ -137,7 +137,7 @@
 %!assert (isstrprop ({"AbC", "123"}, "lower"), {logical([0 1 0]), logical([0 0 0])})
 
 ## Test input validation
-%!error isstrprop ()
+%!error <Invalid call> isstrprop ()
 %!error isstrprop ("abc123")
 %!error isstrprop ("abc123", "alpha", "alpha")
 %!error <invalid string property> isstrprop ("abc123", "foo")
--- a/scripts/strings/mat2str.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/mat2str.m	Thu Nov 19 13:08:00 2020 -0800
@@ -65,7 +65,7 @@
 
 function s = mat2str (x, n = 15, cls = "")
 
-  if (nargin < 1 || nargin > 3 || ! (isnumeric (x) || islogical (x)))
+  if (nargin < 1 || ! (isnumeric (x) || islogical (x)))
     print_usage ();
   elseif (ndims (x) > 2)
     error ("mat2str: X must be two dimensional");
@@ -151,8 +151,7 @@
 %!assert (mat2str (logical ([0 1; 0 0])), "[false true;false false]")
 
 ## Test input validation
-%!error mat2str ()
-%!error mat2str (1,2,3,4)
+%!error <Invalid call> mat2str ()
 %!error mat2str (["Hello"])
 %!error <X must be two dimensional> mat2str (ones (3,3,2))
 %!error <N must have only 1 or 2 elements> mat2str (ones (3,3), [1 2 3])
--- a/scripts/strings/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/base2dec.m \
   %reldir%/bin2dec.m \
   %reldir%/blanks.m \
@@ -9,6 +10,7 @@
   %reldir%/dec2base.m \
   %reldir%/dec2bin.m \
   %reldir%/dec2hex.m \
+  %reldir%/endsWith.m \
   %reldir%/erase.m \
   %reldir%/hex2dec.m \
   %reldir%/index.m \
@@ -20,6 +22,7 @@
   %reldir%/ostrsplit.m \
   %reldir%/regexptranslate.m \
   %reldir%/rindex.m \
+  %reldir%/startsWith.m \
   %reldir%/str2num.m \
   %reldir%/strcat.m \
   %reldir%/strchr.m \
--- a/scripts/strings/native2unicode.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/native2unicode.m	Thu Nov 19 13:08:00 2020 -0800
@@ -45,7 +45,7 @@
 
 function utf8_str = native2unicode (native_bytes, codepage = "")
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -59,7 +59,7 @@
   endif
 
   if (! ischar (codepage))
-    error ("native2unicode: CODEPAGE must be a string")
+    error ("native2unicode: CODEPAGE must be a string");
   endif
 
   ## FIXME: Would it be better to do this by converting to uint8?  Or to
@@ -88,12 +88,12 @@
 %! assert (double (native2unicode ([164:166 0 167:170], 'ISO-8859-5')),
 %!         [208 132 208 133 208 134 0 208 135 208 136 208 137 208 138]);
 
-%!assert (native2unicode ("foobar"), "foobar");
+%!assert (native2unicode ("foobar"), "foobar")
 %!assert <*54384> (double (native2unicode ([0 0 120.3 0 0 122.6 0 0])),
-%!        [0 0 120 0 0 123 0 0]);
+%!                 [0 0 120 0 0 123 0 0])
 
 %!error <Invalid call> native2unicode ()
-%!error <Invalid call> native2unicode (1, 'ISO-8859-1', 'test')
+%!error <called with too many inputs> native2unicode (1, 'ISO-8859-1', 'test')
 %!error <NATIVE_BYTES must be a numeric vector> native2unicode ([1 2; 3 4])
 %!error <NATIVE_BYTES must be a numeric vector> native2unicode ({1 2 3 4})
 %!error <CODEPAGE must be a string> native2unicode (164:170, 123)
--- a/scripts/strings/ostrsplit.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/ostrsplit.m	Thu Nov 19 13:08:00 2020 -0800
@@ -62,7 +62,7 @@
 
 function cstr = ostrsplit (s, sep, strip_empty = false)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   elseif (! ischar (s) || ! ischar (sep))
     error ("ostrsplit: S and SEP must be string values");
@@ -119,7 +119,7 @@
 %!assert (ostrsplit (char ("a,bc", ",de"), ", ", true), {"a", "bc", "de"})
 
 ## Test input validation
-%!error ostrsplit ()
+%!error <Invalid call> ostrsplit ()
 %!error ostrsplit ("abc")
 %!error ostrsplit ("abc", "b", true, 4)
 %!error <S and SEP must be string values> ostrsplit (123, "b")
--- a/scripts/strings/regexptranslate.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/regexptranslate.m	Thu Nov 19 13:08:00 2020 -0800
@@ -89,6 +89,6 @@
 ## Test input validation
 %!error <Invalid call to regexptranslate> regexptranslate ()
 %!error <Invalid call to regexptranslate> regexptranslate ("wildcard")
-%!error <Invalid call to regexptranslate> regexptranslate ("a", "b", "c")
+%!error <called with too many inputs> regexptranslate ("a", "b", "c")
 %!error <invalid operation> regexptranslate ("foo", "abc")
 %!error <operation OP must be a string> regexptranslate (10, "abc")
--- a/scripts/strings/rindex.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/rindex.m	Thu Nov 19 13:08:00 2020 -0800
@@ -67,6 +67,6 @@
 %! assert (rindex (str, "o"), [5; 2; 3; 2]);
 
 ## Test input validation
-%!error rindex ()
+%!error <Invalid call> rindex ()
 %!error rindex ("foo")
 %!error rindex ("foo", "bar", "last")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/strings/startsWith.m	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,172 @@
+########################################################################
+##
+## Copyright (C) 2020 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn  {} {@var{retval} =} startsWith (@var{str}, @var{pattern})
+## @deftypefnx {} {@var{retval} =} startsWith (@var{str}, @var{pattern}, "IgnoreCase", @var{ignore_case})
+## Check whether string(s) start with pattern(s).
+##
+## Return an array of logical values that indicates which string(s) in the
+## input @var{str} (a single string or cell array of strings) begin with
+## the input @var{pattern} (a single string or cell array of strings).
+##
+## If the value of the parameter @qcode{"IgnoreCase"} is true, then the
+## function will ignore the letter case of @var{str} and @var{pattern}.  By
+## default, the comparison is case sensitive.
+##
+## Examples:
+##
+## @example
+## @group
+## ## one string and one pattern while considering case
+## startsWith ("hello", "he")
+##       @result{}  1
+## @end group
+##
+## @group
+## ## one string and one pattern while ignoring case
+## startsWith ("hello", "HE", "IgnoreCase", true)
+##       @result{}  1
+## @end group
+##
+## @group
+## ## multiple strings and multiple patterns while considering case
+## startsWith (@{"lab work.pptx", "data.txt", "foundations.ppt"@},
+##             @{"lab", "data"@})
+##       @result{}  1  1  0
+## @end group
+##
+## @group
+## ## multiple strings and one pattern while considering case
+## startsWith (@{"DATASHEET.ods", "data.txt", "foundations.ppt"@},
+##             "data", "IgnoreCase", false)
+##       @result{}  0  1  0
+## @end group
+##
+## @group
+## ## multiple strings and one pattern while ignoring case
+## startsWith (@{"DATASHEET.ods", "data.txt", "foundations.ppt"@},
+##             "data", "IgnoreCase", true)
+##       @result{}  1  1  0
+## @end group
+## @end example
+##
+## @seealso{endsWith, regexp, strncmp, strncmpi}
+## @end deftypefn
+
+function retval = startsWith (str, pattern, IgnoreCase, ignore_case)
+
+  if (nargin != 2 && nargin != 4)
+    print_usage ();
+  endif
+
+  ## Validate input str and pattern
+  if (! (iscellstr (str) || ischar (str)))
+    error ("startsWith: STR must be a string or cell array of strings");
+  endif
+  if (! (iscellstr (pattern) || ischar (pattern)))
+    error ("startsWith: PATTERN must be a string or cell array of strings");
+  endif
+
+  str = cellstr (str);
+  pattern = cellstr (pattern);
+
+  if (nargin == 2)
+    ignore_case = false;
+  else
+    ## For Matlab compatibility accept any abbreviation of 3rd argument
+    if (! ischar (IgnoreCase) || isempty (IgnoreCase)
+        || ! strncmpi (IgnoreCase, "IgnoreCase", length (IgnoreCase)))
+      error ('startsWith: third input must be "IgnoreCase"');
+    endif
+
+    if (! isscalar (ignore_case) || ! isreal (ignore_case))
+      error ('startsWith: "IgnoreCase" value must be a logical scalar');
+    endif
+    ignore_case = logical (ignore_case);
+  endif
+
+  retval = false (size (str));
+  if (ignore_case)
+    for j = 1:numel (pattern)
+      retval |= strncmpi (str, pattern{j}, length (pattern{j}));
+    endfor
+  else
+    for j = 1:numel (pattern)
+      retval |= strncmp (str, pattern{j}, length (pattern{j}));
+    endfor
+  endif
+
+endfunction
+
+
+## Test simple use with one string and one pattern
+%!assert (startsWith ("hello", "he"))
+%!assert (! startsWith ("hello", "HE"))
+%!assert (startsWith ("hello", "HE", "i", 5))
+%!assert (! startsWith ("hello", "no"))
+
+## Test multiple strings with a single pattern
+%!test
+%! str = {"data science", "dataSheet.ods", "myFunc.m"; "foundations.ppt", ...
+%!        "results.txt", "myFile.odt"};
+%! pattern = "data";
+%! expected = [true, true, false; false, false, false];
+%! assert (startsWith (str, pattern), expected);
+
+## Test multiple strings with multiple patterns
+%!test
+%! str = {"lab work.pptx", "myFile.odt", "data.txt", "foundations.ppt"};
+%! pattern = {"lab", "data"};
+%! expected = [true, false, true, false];
+%! assert (startsWith (str, pattern), expected);
+
+## Test IgnoreCase
+%!test
+%! str = {"DATASHEET.ods", "myFile.odt", "data.txt", "foundations.ppt"};
+%! pattern = "data";
+%! expected_ignore = [true, false, true, false];
+%! expected_wo_ignore = [false, false, true, false];
+%! assert (startsWith (str, pattern, "IgnoreCase", true), expected_ignore);
+%! assert (startsWith (str, pattern, "IgnoreCase", false), expected_wo_ignore);
+%! assert (startsWith (str, pattern, "I", 500), expected_ignore);
+%! assert (startsWith (str, pattern, "iG", 0), expected_wo_ignore);
+
+## Test input validation
+%!error <Invalid call> startsWith ()
+%!error startsWith ("A")
+%!error startsWith ("A", "B", "C")
+%!error startsWith ("A", "B", "C", "D", "E")
+%!error <STR must be a string> startsWith (152, "hi")
+%!error <STR must be a .* cell array of strings> startsWith ({152}, "hi")
+%!error <PATTERN must be a string> startsWith ("hi", 152)
+%!error <PATTERN must be a .* cell array of strings> startsWith ("hi", {152})
+%!error <third input must be "IgnoreCase"> startsWith ("hello", "he", 1, 1)
+%!error <third input must be "IgnoreCase"> startsWith ("hello", "he", "", 1)
+%!error <third input must be "IgnoreCase"> startsWith ("hello", "he", "foo", 1)
+%!error <"IgnoreCase" value must be a logical scalar>
+%! startsWith ("hello", "hi", "i", "true");
+%!error <"IgnoreCase" value must be a logical scalar>
+%! startsWith ("hello", "hi", "i", {true});
--- a/scripts/strings/str2num.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/str2num.m	Thu Nov 19 13:08:00 2020 -0800
@@ -55,7 +55,7 @@
 
 function [m, state] = str2num (s)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   elseif (! ischar (s))
     error ("str2num: S must be a string or string array");
@@ -90,6 +90,5 @@
 %! assert (! state);
 
 ## Test input validation
-%!error str2num ()
-%!error str2num ("string", 1)
+%!error <Invalid call> str2num ()
 %!error <S must be a string> str2num ({"string"})
--- a/scripts/strings/strchr.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/strchr.m	Thu Nov 19 13:08:00 2020 -0800
@@ -41,7 +41,7 @@
 
 function varargout = strchr (str, chars, varargin)
 
-  if (nargin < 2)
+  if (nargin < 2 || nargin > 4)
     print_usage ();
   elseif (! ischar (str))
     error ("strchr: STR argument must be a string or string array");
@@ -82,7 +82,8 @@
 %!assert (strchr ("Octave is the best software", "software"), [3, 4, 6, 9, 11, 13, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27])
 
 ## Test input validation
-%!error strchr ()
-%!error strchr (1)
+%!error <Invalid call> strchr ()
+%!error <Invalid call> strchr (1)
+%!error <Invalid call> strchr ("s", "a", 1, "last", 5)
 %!error <STR argument must be a string> strchr (1, "aeiou")
 %!error <CHARS argument must be a string> strchr ("aeiou", 1)
--- a/scripts/strings/strjoin.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/strjoin.m	Thu Nov 19 13:08:00 2020 -0800
@@ -49,11 +49,9 @@
 ## @seealso{strsplit}
 ## @end deftypefn
 
-function rval = strjoin (cstr, delimiter)
+function rval = strjoin (cstr, delimiter = " ")
 
-  if (nargin == 1)
-    delimiter = " ";
-  elseif (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   elseif (! (iscellstr (cstr) && (ischar (delimiter) || iscellstr (delimiter))))
     print_usage ();
--- a/scripts/strings/strjust.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/strjust.m	Thu Nov 19 13:08:00 2020 -0800
@@ -51,7 +51,7 @@
 
 function y = strjust (s, pos = "right")
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   elseif (! ischar (s) || ndims (s) > 2)
     error ("strjust: S must be a string or 2-D character matrix");
@@ -113,6 +113,6 @@
 
 ## Test input validation
 %!error <Invalid call to strjust> strjust ()
-%!error <Invalid call to strjust> strjust (["a";"ab"], "center", 1)
+%!error <called with too many inputs> strjust (["a";"ab"], "center", 1)
 %!error <S must be a string> strjust (ones (3,3))
 %!error <S must be a string> strjust (char (ones (3,3,3)))
--- a/scripts/strings/strsplit.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/strsplit.m	Thu Nov 19 13:08:00 2020 -0800
@@ -187,7 +187,7 @@
   if (! ischar (str) || (! ischar (del) && ! iscellstr (del)))
     error ("strsplit: S and DEL must be string values");
   elseif (! isempty (str) && ! isrow (str))
-    error ("strsplit: S must be a char row vector")
+    error ("strsplit: S must be a char row vector");
   elseif (! isscalar (args.collapsedelimiters))
     error ("strsplit: COLLAPSEDELIMITERS must be a scalar value");
   endif
@@ -314,7 +314,7 @@
 %!assert <*47403> (strsplit ('xxx+yyy', '+'), {"xxx", "yyy"})
 
 ## Test input validation
-%!error strsplit ()
+%!error <Invalid call> strsplit ()
 %!error strsplit ("abc", "b", true, 4)
 %!error <invalid parameter name, 'foo'> strsplit ("abc", "b", "foo", "true")
 %!error <S and DEL must be string values> strsplit (123, "b")
--- a/scripts/strings/strtok.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/strtok.m	Thu Nov 19 13:08:00 2020 -0800
@@ -58,12 +58,12 @@
 
 function [tok, rem] = strtok (str, delim)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   elseif (! (ischar (str) || iscellstr (str)))
-    error ("strtok: STR must be a string or cell array of strings.");
+    error ("strtok: STR must be a string or cell array of strings");
   elseif (ischar (str) && ! isvector (str) &&! isempty (str))
-    error ("strtok: STR cannot be a 2-D character array.");
+    error ("strtok: STR cannot be a 2-D character array");
   endif
 
   if (nargin < 2 || isempty (delim))
@@ -137,7 +137,7 @@
     if (isargout (2))
       rem = cell (size (str));
       rem(eidx) = {""};
-      rem(midx) = tmp(2:2:end);
+      rem (midx) = tmp(2:2:end);
     endif
   endif
 
@@ -229,7 +229,6 @@
 %! endfor
 
 ## Test input validation
-%!error strtok ()
-%!error strtok ("a", "b", "c")
+%!error <Invalid call> strtok ()
 %!error <STR must be a string> strtok (1, "b")
 %!error <STR cannot be a 2-D> strtok (char ("hello", "world"), "l")
--- a/scripts/strings/strtrim.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/strtrim.m	Thu Nov 19 13:08:00 2020 -0800
@@ -49,7 +49,7 @@
 
 function s = strtrim (s)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -90,6 +90,6 @@
 %!assert (strtrim ({" abc   ", {"   def   "}}), {"abc", {"def"}})
 
 %!error <Invalid call to strtrim> strtrim ()
-%!error <Invalid call to strtrim> strtrim ("abc", "def")
+%!error <called with too many inputs> strtrim ("abc", "def")
 %!error <argument must be a string> strtrim (1)
 %!error <argument must be a string> strtrim ({[]})
--- a/scripts/strings/strtrunc.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/strtrunc.m	Thu Nov 19 13:08:00 2020 -0800
@@ -78,7 +78,7 @@
 %! assert (y{2}, repmat ("line", 2, 1));
 
 ## Test input validation
-%!error strtrunc ()
+%!error <Invalid call> strtrunc ()
 %!error strtrunc ("abcd")
 %!error strtrunc ("abcd", 4, 5)
 %!error <N must be a positive integer> strtrunc ("abcd", ones (2,2))
--- a/scripts/strings/substr.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/substr.m	Thu Nov 19 13:08:00 2020 -0800
@@ -54,7 +54,7 @@
 
 function t = substr (s, offset, len)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -104,7 +104,7 @@
 %!assert (isempty (substr ("This is a test string", 1, 0)))
 
 ## Test input validation
-%!error substr ()
+%!error <Invalid call> substr ()
 %!error substr ("foo", 2, 3, 4)
 %!error substr (ones (5, 1), 1, 1)
 %!error substr ("foo", ones (2,2))
--- a/scripts/strings/unicode2native.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/unicode2native.m	Thu Nov 19 13:08:00 2020 -0800
@@ -45,7 +45,7 @@
 
 function native_bytes = unicode2native (utf8_str, codepage = "")
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -73,7 +73,7 @@
 %!         uint8 ([164:166 0 167:170]));
 
 %!error <Invalid call> unicode2native ()
-%!error <Invalid call> unicode2native ('a', 'ISO-8859-1', 'test')
+%!error <called with too many inputs> unicode2native ('a', 'ISO-8859-1', 'test')
 %!error <UTF8_STR must be a character vector> unicode2native (['ab'; 'cd'])
 %!error <UTF8_STR must be a character vector> unicode2native ({1 2 3 4})
 %!error <CODEPAGE must be a string> unicode2native ('ЄЅІЇЈЉЊ', 123)
--- a/scripts/strings/untabify.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/strings/untabify.m	Thu Nov 19 13:08:00 2020 -0800
@@ -57,7 +57,7 @@
 
 function s = untabify (t, tw = 8, deblank_arg = false)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   elseif (! (ischar (t) || iscellstr (t)))
     error ("untabify: T must be a string or cellstring");
@@ -122,6 +122,6 @@
 %! s = char (randi ([97 97+25], 3, 3));
 %! assert (untabify (s), char (untabify (cellstr (s))));
 
-%!error untabify ()
-%!error untabify (1,2,3,4)
+## Test input validation
+%!error <Invalid call> untabify ()
 %!error <must be a string> untabify (1)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/testfun/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/testfun/__debug_octave__.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/testfun/__debug_octave__.m	Thu Nov 19 13:08:00 2020 -0800
@@ -45,10 +45,6 @@
 
 function __debug_octave__ (command_string)
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   if (nargin == 0)
     if (ismac ())
       status = system ("lldb --version");
--- a/scripts/testfun/assert.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/testfun/assert.m	Thu Nov 19 13:08:00 2020 -0800
@@ -682,8 +682,8 @@
 %! end_try_catch
 
 ## test input validation
-%!error assert ()
-%!error assert (1,2,3,4)
+%!error <Invalid call> assert ()
+%!error <Invalid call> assert (1,2,3,4)
 
 
 ## Convert all error indices into tuple format
--- a/scripts/testfun/demo.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/testfun/demo.m	Thu Nov 19 13:08:00 2020 -0800
@@ -103,7 +103,7 @@
 
 function demo (name, n = 0)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -186,8 +186,7 @@
 %! #-------------------------------------------------
 %! # the figure window shows one cycle of a sine wave
 
-%!error demo ()
-%!error demo (1, 2, 3)
+%!error <Invalid call> demo ()
 %!error <N must be a scalar integer> demo ("demo", {1})
 %!error <N must be a scalar integer> demo ("demo", ones (2,2))
 %!error <N must be a scalar integer> demo ("demo", 1.5)
--- a/scripts/testfun/example.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/testfun/example.m	Thu Nov 19 13:08:00 2020 -0800
@@ -39,13 +39,13 @@
 ## a string @var{s}, with @var{idx} indicating the ending position of the
 ## various examples.
 ##
-## See @code{demo} for a complete explanation.
+## For a complete explanation @pxref{XREFdemo,,@code{demo}}.
 ## @seealso{demo, test}
 ## @end deftypefn
 
 function [ex_code, ex_idx] = example (name, n = 0)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -119,8 +119,7 @@
 %! assert (idx, [1, 23, 73]);
 
 ## Test input validation
-%!error example ()
-%!error example ("example", 3, 5)
+%!error <Invalid call> example ()
 %!error <N must be a scalar integer> example ("example", {1})
 %!error <N must be a scalar integer> example ("example", ones (2,2))
 %!error <N must be a scalar integer> example ("example", 1.5)
--- a/scripts/testfun/fail.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/testfun/fail.m	Thu Nov 19 13:08:00 2020 -0800
@@ -67,7 +67,7 @@
 
 function retval = fail (code, pattern, warning_pattern)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -157,6 +157,5 @@
 %!error <warning failure> fail ("warning ('warning failure')", "warning", "success")
 
 ## Test input validation
-%!error fail ()
-%!error fail (1,2,3,4)
+%!error <Invalid call> fail ()
 %!error fail (1, "nowarning", "foo")
--- a/scripts/testfun/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/testfun/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -9,6 +9,7 @@
   %reldir%/private/html_plot_demos_template.html
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/__debug_octave__.m \
   %reldir%/__have_feature__.m \
   %reldir%/__printf_assert__.m \
--- a/scripts/testfun/oruntests.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/testfun/oruntests.m	Thu Nov 19 13:08:00 2020 -0800
@@ -41,7 +41,7 @@
   if (nargin == 0)
     dirs = ostrsplit (path (), pathsep ());
     do_class_dirs = true;
-  elseif (nargin == 1)
+  else
     dirs = {canonicalize_file_name(directory)};
     if (isempty (dirs{1}) || ! isfolder (dirs{1}))
       ## Search for directory name in path
@@ -55,8 +55,6 @@
       dirs = {fullname};
     endif
     do_class_dirs = false;
-  else
-    print_usage ();
   endif
 
   for i = 1:numel (dirs)
--- a/scripts/testfun/private/compare_plot_demos.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/testfun/private/compare_plot_demos.m	Thu Nov 19 13:08:00 2020 -0800
@@ -57,7 +57,7 @@
   arg.fcn_file = "dump_plot_demos.m";
   arg.replace_images = false;
 
-  for n = 1:2:numel(varargin)
+  for n = 1:2:numel (varargin)
     if (! ischar (varargin{n}))
       print_usage ();
     else
@@ -68,17 +68,17 @@
   if (ischar (arg.toolkits))
     arg.toolkits = {arg.toolkits};
   elseif (! iscellstr (arg.toolkits))
-    error ('compare_plot_demos: Invalid value for "toolkits"')
+    error ('compare_plot_demos: Invalid value for "toolkits"');
   endif
 
   if (ischar (arg.directories))
     arg.directories = {arg.directories};
   elseif (! iscellstr (arg.directories))
-    error ('compare_plot_demos: Invalid value for "directory"')
+    error ('compare_plot_demos: Invalid value for "directory"');
   endif
 
   if (! ischar (arg.fmt))
-    error ('compare_plot_demos: Invalid value for "fmt"')
+    error ('compare_plot_demos: Invalid value for "fmt"');
   endif
 
   ## Generate arg.fcn_file for rendering/saving the plot demo images
--- a/scripts/testfun/private/dump_demos.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/testfun/private/dump_demos.m	Thu Nov 19 13:08:00 2020 -0800
@@ -57,10 +57,6 @@
 
 function dump_demos (dirs={"plot/appearance", "plot/draw", "plot/util", "image"}, mfile="dump_plot_demos.m", fmt="png")
 
-  if (nargin > 3)
-    print_usage ();
-  endif
-
   if (ischar (dirs))
     dirs = {dirs};
   elseif (! iscellstr (dirs))
--- a/scripts/testfun/private/html_compare_plot_demos.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/testfun/private/html_compare_plot_demos.m	Thu Nov 19 13:08:00 2020 -0800
@@ -70,12 +70,12 @@
   in.plots_per_page = 50;
 
   ## Parse inputs
-  for n = 1:2:numel(varargin)
+  for n = 1:2:numel (varargin)
     in.(lower(varargin{n})) = varargin{n+1};
   endfor
 
   ## Compile a list of all files for all toolkits
-  for t = 1:numel(toolkits)
+  for t = 1:numel (toolkits)
     filter = sprintf ("%s/*.%s", toolkits{t}, in.fmt);
     in.figfiles = union (in.figfiles, {dir(filter).name});
   endfor
@@ -87,7 +87,7 @@
   anchor = "<!-- ##ADD TABLE HERE## -->";
   n = strfind (template, anchor);
   header = strtrim (template(1:n-1));
-  trailer = strtrim (template(n+numel(anchor):end));
+  trailer = strtrim (template(n+numel (anchor):end));
 
   page = 1;
   do
@@ -123,7 +123,7 @@
 
       ## Create table header
       fprintf (fid, "<table>\n<tr>\n");
-      for t = 1:numel(toolkits)
+      for t = 1:numel (toolkits)
         ## set default
         column_header = upper (toolkits{t});
         if (isfield (in, toolkits{t}))
@@ -147,7 +147,7 @@
           else
             err_fn = strrep (ffn, ".png", ".err");
             if (! exist (err_fn, "file"))
-              warning("File %s doesn't exist...", err_fn);
+              warning ("File %s doesn't exist...", err_fn);
             else
               err_fid = fopen (err_fn);
               msg = char (fread (err_fid))';
--- a/scripts/testfun/speed.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/testfun/speed.m	Thu Nov 19 13:08:00 2020 -0800
@@ -159,7 +159,7 @@
 ## FIXME: consider two dimensional speedup surfaces for functions like kron.
 function [__order, __test_n, __tnew, __torig] = speed (__f1, __init, __max_n = 100, __f2 = "", __tol = eps)
 
-  if (nargin < 1 || nargin > 6)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -243,7 +243,7 @@
         __t = min ([__t, __t2, __t3]);
       endif
       __torig(k) = __t;
-      if (! isinf(__tol))
+      if (! isinf (__tol))
         assert (__v1, __v2, __tol);
       endif
     endif
@@ -276,7 +276,7 @@
   endif
 
   if (do_display)
-    figure;
+    figure ();
     ## Strip semicolon added to code fragments before displaying
     __init(end) = "";
     __f1(end) = "";
@@ -403,7 +403,7 @@
 %! fstr_build = cstrcat (
 %!   "function x = build (n)\n",
 %!   "  idx = [1:100]';\n",
-%!   "  x = idx(:,ones(1,n));\n",
+%!   "  x = idx(:,ones (1,n));\n",
 %!   "  x = reshape (x, 1, n*100);\n",
 %!   "endfunction");
 %!
@@ -453,5 +453,4 @@
 %! assert (length (T_f2) > 10);
 
 ## Test input validation
-%!error speed ()
-%!error speed (1, 2, 3, 4, 5, 6, 7)
+%!error <Invalid call> speed ()
--- a/scripts/testfun/test.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/testfun/test.m	Thu Nov 19 13:08:00 2020 -0800
@@ -115,7 +115,7 @@
 ## any built-in demo blocks are extracted but not executed.  The text for all
 ## code blocks is concatenated and returned as @var{code} with @var{idx} being
 ## a vector of positions of the ends of each demo block.  For an easier way to
-## extract demo blocks from files, @xref{XREFexample,,example}.
+## extract demo blocks from files, @xref{XREFexample,,@code{example}}.
 ##
 ## If the second argument is @qcode{"explain"} then @var{name} is ignored and
 ## an explanation of the line markers used in @code{test} output reports is
@@ -137,7 +137,7 @@
   persistent __signal_file  = ">>>>> ";
   persistent __signal_skip  = "----- ";
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   elseif (! isempty (__name) && ! ischar (__name))
     error ("test: NAME must be a string");
@@ -670,7 +670,7 @@
       endif
 
       ## evaluate code for test, shared, and assert.
-      if (! isempty(__code))
+      if (! isempty (__code))
         try
           eval (sprintf ("function %s__test__(%s)\n%s\nendfunction",
                          __shared_r, __shared, __code));
@@ -727,7 +727,7 @@
             && ! strcmp (__type, "xtest")
             && ! all (__shared == " "))
           fputs (__fid, "shared variables ");
-          eval (sprintf ("fdisp(__fid,var2struct(%s));", __shared));
+          eval (sprintf ("fdisp (__fid,var2struct(%s));", __shared));
         endif
         fflush (__fid);
       endif
@@ -915,7 +915,7 @@
 function msg = trimerr (msg, prefix)
   idx = index (msg, [prefix ":"]);
   if (idx > 0)
-    msg(1:idx+length(prefix)) = [];
+    msg(1:idx+length (prefix)) = [];
   endif
   msg = strtrim (msg);
 endfunction
@@ -950,7 +950,7 @@
 %!fail ("toeplitz ([1,2],[1,2;3,4])", msg2)
 %!fail ("toeplitz ([1,2;3,4],[1,2])", msg2)
 %!test fail ("toeplitz", "Invalid call to toeplitz")
-%!fail ("toeplitz (1, 2, 3)", "Invalid call to toeplitz")
+%!fail ("toeplitz (1, 2, 3)", "called with too many inputs")
 %!test assert (toeplitz ([1,2,3], [1,4]), [1,4; 2,1; 3,2])
 %!assert (toeplitz ([1,2,3], [1,4]), [1,4; 2,1; 3,2])
 %!demo toeplitz ([1,2,3,4],[1,5,6])
@@ -984,15 +984,14 @@
 
 ## Test 'fail' keyword
 %!fail ("test", "Invalid call to test")  # no args, generates usage()
-%!fail ("test (1,2,3,4)", "usage.*test") # too many args, generates usage()
+%!fail ("test (1,2,3,4)", "called with too many inputs") # too many args
 %!fail ('test ("test", "invalid")', "unknown flag")  # incorrect args
 %!fail ('garbage','garbage.*undefined')  # usage on nonexistent function should be
 
 ## Test 'error' keyword
-%!error test              # no args, generates usage()
-%!error test (1,2,3,4)    # too many args, generates usage()
+%!error <Invalid call> test              # no args, generates usage()
 %!error <unknown flag> test ("test", "invalid"); # incorrect args
-%!error test ("test", "invalid");  # test without pattern
+%!error test ("test", "invalid");        # test without pattern
 %!error <'garbage' undefined> garbage; # usage on nonexistent function is error
 
 ## Test 'warning' keyword
@@ -1081,15 +1080,15 @@
 ## All of the following tests should fail.  These tests should
 ## be disabled unless you are developing test() since users don't
 ## like to be presented with known failures.
-## %!test   error("---------Failure tests.  Use test('test','verbose',1)");
-## %!test   assert([a,b,c],[1,3,6]);   # variables have wrong values
+## %!test   error ("---------Failure tests.  Use test('test','verbose',1)");
+## %!test   assert ([a,b,c],[1,3,6]);   # variables have wrong values
 ## %!invalid                   # unknown block type
-## %!error  toeplitz([1,2,3]); # correct usage
+## %!error  toeplitz ([1,2,3]); # correct usage
 ## %!test   syntax errors)     # syntax errors fail properly
 ## %!shared garbage in         # variables must be comma separated
 ## %!error  syntax++error      # error test fails on syntax errors
 ## %!error  "succeeds.";       # error test fails if code succeeds
-## %!error <wrong pattern> error("message")  # error pattern must match
+## %!error <wrong pattern> error ("message")  # error pattern must match
 ## %!demo   with syntax error  # syntax errors in demo fail properly
 ## %!shared a,b,c
 ## %!demo                      # shared variables not available in demo
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/time/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/time/addtodate.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/time/addtodate.m	Thu Nov 19 13:08:00 2020 -0800
@@ -121,10 +121,9 @@
 %!assert (addtodate ([d d+1], 1, "month"), [d+31 d+1+31])
 
 ## Test input validation
-%!error addtodate ()
-%!error addtodate (1)
-%!error addtodate (1,2)
-%!error addtodate (1,2,3,4)
+%!error <Invalid call> addtodate ()
+%!error <Invalid call> addtodate (1)
+%!error <Invalid call> addtodate (1,2)
 %!error <F must be a single character string> addtodate (1,2,3)
 %!error <F must be a single character string> addtodate (1,2,"month"')
 %!error <Invalid time unit> addtodate (1,2,"abc")
--- a/scripts/time/asctime.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/time/asctime.m	Thu Nov 19 13:08:00 2020 -0800
@@ -43,7 +43,7 @@
 
 function retval = asctime (tm_struct)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -58,5 +58,4 @@
 
 %!assert (asctime (localtime (time ()))(end), "\n")
 
-%!error asctime ()
-%!error asctime (1, 2)
+%!error <Invalid call> asctime ()
--- a/scripts/time/clock.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/time/clock.m	Thu Nov 19 13:08:00 2020 -0800
@@ -62,6 +62,6 @@
 
 
 %!test
-%! t1 = clock;
+%! t1 = clock ();
 %! t2 = str2num (strftime ("[%Y, %m, %d, %H, %M, %S]", localtime (time ())));
 %! assert (etime (t1, t2) < 1);
--- a/scripts/time/ctime.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/time/ctime.m	Thu Nov 19 13:08:00 2020 -0800
@@ -43,7 +43,7 @@
 
 function retval = ctime (t)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -58,5 +58,4 @@
 
 %!assert (ctime (time ())(end), "\n")
 
-%!error ctime ()
-%!error ctime (1, 2)
+%!error <Invalid call> ctime ()
--- a/scripts/time/date.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/time/date.m	Thu Nov 19 13:08:00 2020 -0800
@@ -40,16 +40,9 @@
 
 function retval = date ()
 
-  if (nargin != 0)
-    print_usage ();
-  endif
-
   retval = strftime ("%d-%b-%Y", localtime (time ()));
 
 endfunction
 
 
 %!assert (strcmp (date (), strftime ("%d-%b-%Y", localtime (time ()))))
-
-## Test input validation
-%!error date (1)
--- a/scripts/time/datenum.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/time/datenum.m	Thu Nov 19 13:08:00 2020 -0800
@@ -42,16 +42,17 @@
 ## The fractional part, @code{rem (@var{days}, 1)} corresponds to the time
 ## on the given day.
 ##
-## The input may be a date vector (see @code{datevec}),
-## datestr (see @code{datestr}), or directly specified as input.
+## The input may be a date vector (@pxref{XREFdatevec,,@code{datevec}}),
+## date string (@pxref{XREFdatestr,,@code{datestr}}), or directly specified
+## as input.
 ##
 ## When processing input datestrings, @var{f} is the format string used to
-## interpret date strings (see @code{datestr}).  If no format @var{f} is
-## specified, then a relatively slow search is performed through various
-## formats.  It is always preferable to specify the format string @var{f} if
-## it is known.  Formats which do not specify a particular time component
-## will have the value set to zero.  Formats which do not specify a date
-## will default to January 1st of the current year.
+## interpret date strings (@pxref{XREFdatestr,,@code{datestr}}).  If no
+## format @var{f} is specified, then a relatively slow search is performed
+## through various formats.  It is always preferable to specify the format
+## string @var{f} if it is known.  Formats which do not specify a particular
+## time component will have the value set to zero.  Formats which do not
+## specify a date will default to January 1st of the current year.
 ##
 ## @var{p} is the year at the start of the century to which two-digit years
 ## will be referenced.  If not specified, it defaults to the current year
@@ -109,8 +110,7 @@
   persistent monthstart = [306; 337; 0; 31; 61; 92; 122; 153; 184; 214; 245; 275];
   persistent monthlength = [31; 28; 31; 30; 31; 30; 31; 31; 30; 31; 30; 31];
 
-  if (nargin == 0 || nargin > 6
-      || (nargin > 2 && (ischar (year) || iscellstr (year))))
+  if (nargin == 0 || (nargin > 2 && (ischar (year) || iscellstr (year))))
     print_usage ();
   endif
 
@@ -251,8 +251,7 @@
 %!assert (datenum ("5-19, 2001", "mm-dd, yyyy"), 730990)
 
 ## Test input validation
-%!error datenum ()
-%!error datenum (1,2,3,4,5,6,7)
+%!error <Invalid call> datenum ()
 %!error <expected date vector containing> datenum ([1, 2])
 %!error <expected date vector containing> datenum ([1,2,3,4,5,6,7])
 %!error <all inputs must be of class double> datenum (int32 (2000), int32 (1), int32 (1))
--- a/scripts/time/datestr.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/time/datestr.m	Thu Nov 19 13:08:00 2020 -0800
@@ -30,9 +30,10 @@
 ## Format the given date/time according to the format @var{f} and return
 ## the result in @var{str}.
 ##
-## @var{date} is a serial date number (see @code{datenum}), a date vector (see
-## @code{datevec}), or a string or cell array of strings.  In the latter case,
-## it is passed to @code{datevec} to guess the input date format.
+## @var{date} is a serial date number (@pxref{XREFdatenum,,@code{datenum}}), a
+## date vector (@pxref{XREFdatevec,,@code{datevec}}), or a string or cell array
+## of strings.  In the latter case, it is passed to @code{datevec} to guess the
+## input date format.
 ##
 ## @var{f} can be an integer which corresponds to one of the codes in the table
 ## below, or a date format string.
@@ -175,7 +176,7 @@
     names_d = {"S", "M", "T", "W", "T", "F", "S"};
   endif
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -368,5 +369,4 @@
 %!                 "00:05:00.000")
 
 ## Test input validation
-%!error datestr ()
-%!error datestr (1, 2, 3, 4)
+%!error <Invalid call> datestr ()
--- a/scripts/time/datevec.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/time/datevec.m	Thu Nov 19 13:08:00 2020 -0800
@@ -29,19 +29,19 @@
 ## @deftypefnx {} {@var{v} =} datevec (@var{date}, @var{p})
 ## @deftypefnx {} {@var{v} =} datevec (@var{date}, @var{f}, @var{p})
 ## @deftypefnx {} {[@var{y}, @var{m}, @var{d}, @var{h}, @var{mi}, @var{s}] =} datevec (@dots{})
-## Convert a serial date number (see @code{datenum}) or date string (see
-## @code{datestr}) into a date vector.
+## Convert a serial date number (@pxref{XREFdatenum,,@code{datenum}}) or date
+## string (@pxref{XREFdatestr,,@code{datestr}}) into a date vector.
 ##
 ## A date vector is a row vector with six members, representing the year,
 ## month, day, hour, minute, and seconds respectively.
 ##
 ## @var{f} is the format string used to interpret date strings
-## (see @code{datestr}).  If @var{date} is a string, but no format is
-## specified, then a relatively slow search is performed through various
-## formats.  It is always preferable to specify the format string @var{f} if it
-## is known.  Formats which do not specify a particular time component will
-## have the value set to zero.  Formats which do not specify a date will
-## default to January 1st of the current year.
+## (@pxref{XREFdatestr,,@code{datestr}}).  If @var{date} is a string, but no
+## format is specified, then a relatively slow search is performed through
+## various formats.  It is always preferable to specify the format string
+## @var{f} if it is known.  Formats which do not specify a particular time
+## component will have the value set to zero.  Formats which do not specify a
+## date will default to January 1st of the current year.
 ##
 ## @var{p} is the year at the start of the century to which two-digit years
 ## will be referenced.  If not specified, it defaults to the current year minus
@@ -94,7 +94,7 @@
     std_formats{++nfmt} = "mm/dd/yyyy HH:MM";
   endif
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -423,7 +423,6 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error datevec ()
-%!error datevec (1,2,3,4)
+%!error <Invalid call> datevec ()
 %!error <none of the standard formats match> datevec ("foobar")
 %!error <DATE not parsed correctly with given format> datevec ("foobar", "%d")
--- a/scripts/time/eomday.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/time/eomday.m	Thu Nov 19 13:08:00 2020 -0800
@@ -61,6 +61,5 @@
 %!assert (eomday ([2004;2005], [2;2]), [29;28])
 
 ## Test input validation
-%!error eomday ()
-%!error eomday (1)
-%!error eomday (1,2,3)
+%!error <Invalid call> eomday ()
+%!error <Invalid call> eomday (1)
--- a/scripts/time/etime.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/time/etime.m	Thu Nov 19 13:08:00 2020 -0800
@@ -80,6 +80,5 @@
 %! assert (etime (t5, t1), 13);
 
 ## Test input validation
-%!error etime ()
-%!error etime (1)
-%!error etime (1, 2, 3)
+%!error <Invalid call> etime ()
+%!error <Invalid call> etime (1)
--- a/scripts/time/is_leap_year.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/time/is_leap_year.m	Thu Nov 19 13:08:00 2020 -0800
@@ -43,10 +43,6 @@
 
 function retval = is_leap_year (year)
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   if (nargin == 0)
     t = clock ();
     year = t(1);
@@ -63,4 +59,3 @@
 %!assert (is_leap_year (1800), false)
 %!assert (is_leap_year (1600), true)
 
-%!error is_leap_year (1, 2)
--- a/scripts/time/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/time/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/addtodate.m \
   %reldir%/asctime.m \
   %reldir%/calendar.m \
--- a/scripts/time/now.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/time/now.m	Thu Nov 19 13:08:00 2020 -0800
@@ -26,7 +26,7 @@
 ## -*- texinfo -*-
 ## @deftypefn {} {t =} now ()
 ## Return the current local date/time as a serial day number
-## (see @code{datenum}).
+## (@pxref{XREFdatenum,,@code{datenum}}).
 ##
 ## The integral part, @code{floor (now)} corresponds to the number of days
 ## between today and Jan 1, 0000.
@@ -37,10 +37,6 @@
 
 function t = now ()
 
-  if (nargin != 0)
-    print_usage ();
-  endif
-
   t = datenum (clock ());
 
   ## The following doesn't work (e.g., one hour off on 2005-10-04):
@@ -59,5 +55,3 @@
 %!assert (isnumeric (now ()))
 %!assert (now () > 0)
 %!assert (now () <= now ())
-
-%!error now (1)
--- a/scripts/time/weekday.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/time/weekday.m	Thu Nov 19 13:08:00 2020 -0800
@@ -55,7 +55,7 @@
 
 function [d, s] = weekday (d, format = "short")
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/web/.oct-config	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/web/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/web/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/web.m \
   %reldir%/weboptions.m \
   %reldir%/webread.m \
--- a/scripts/web/weboptions.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/web/weboptions.m	Thu Nov 19 13:08:00 2020 -0800
@@ -160,6 +160,7 @@
   endproperties
 
   methods
+
     function f = weboptions (varargin)
       if (rem (numel (varargin), 2) != 0)
         error ("weboptions: invalid number of arguments");
@@ -244,6 +245,7 @@
           error (["weboptions: Undefined field " field]);
         endif
       endif
+
     endfunction
 
     function f = set.CharacterEncoding (f, value)
@@ -264,7 +266,7 @@
 
     function f = set.Timeout (f, value)
       if (! isreal (value) || ! isscalar (value)
-          || floor(value) != value || value < 0)
+          || floor (value) != value || value < 0)
         error ("weboptions: invalid Timeout value");
       else
         f.Timeout = value;
@@ -355,6 +357,7 @@
     endfunction
 
     function display (f)
+
       Timeout = int2str (f.Timeout);
       Password = repmat ("*", 1, numel (num2str (f.Password)));
 
@@ -393,6 +396,7 @@
                 "\n           HeaderFields: " , HeaderFields,...
                 "\n    CertificateFilename: '", f.CertificateFilename, "'\n"];
       disp (output);
+
     endfunction
 
   endmethods
--- a/scripts/web/webread.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/web/webread.m	Thu Nov 19 13:08:00 2020 -0800
@@ -48,7 +48,7 @@
 function response = webread (url, varargin)
 
   if (nargin == 0)
-    print_usage();
+    print_usage ();
   endif
 
   if (! (ischar (url) && isrow (url)))
@@ -105,7 +105,7 @@
 
 
 ## Test input validation
-%!error webread ()
+%!error <Invalid call> webread ()
 %!error <URL must be a string> webread (1)
 %!error <URL must be a string> webread (["a";"b"])
 %!error <KEYS and VALUES must be strings> webread ("URL", "NAME1", 5)
--- a/scripts/web/webwrite.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/scripts/web/webwrite.m	Thu Nov 19 13:08:00 2020 -0800
@@ -47,7 +47,7 @@
 function response = webwrite (url, varargin)
 
   if (nargin < 2)
-    print_usage();
+    print_usage ();
   endif
 
   if (! (ischar (url) && isrow (url)))
@@ -94,7 +94,7 @@
     if (ischar (varargin{1}) && isrow (varargin{1}))
       param = strsplit (varargin{1}, {"=", "&"});
       response = __restful_service__ (url, param, options);
-    elseif  (! iscellstr (varargin))
+    elseif (! iscellstr (varargin))
       error ("webwrite: DATA must be a string");
     else
       response = __restful_service__ (url, varargin, options);
@@ -113,8 +113,8 @@
 
 
 ## Test input validation
-%!error webwrite ()
-%!error webwrite ("abc")
+%!error <Invalid call> webwrite ()
+%!error <Invalid call> webwrite ("abc")
 %!error <URL must be a string> webwrite (1, "NAME1", "VALUE1")
 %!error <URL must be a string> webwrite (["a";"b"], "NAME1", "VALUE1")
 %!error <DATA must be a string> webwrite ("URL", 1, weboptions ())
--- a/src/mkoctfile.in.cc	Thu Nov 19 13:05:51 2020 -0800
+++ b/src/mkoctfile.in.cc	Thu Nov 19 13:08:00 2020 -0800
@@ -66,8 +66,6 @@
 #  include "wait-wrappers.h"
 #endif
 
-static std::map<std::string, std::string> vars;
-
 #if ! defined (OCTAVE_VERSION)
 #  define OCTAVE_VERSION %OCTAVE_CONF_VERSION%
 #endif
@@ -170,11 +168,13 @@
   return s;
 }
 
-static void
-initialize (void)
+static std::map<std::string, std::string>
+make_vars_map (bool link_stand_alone, bool verbose, bool debug)
 {
   set_octave_home ();
 
+  std::map<std::string, std::string> vars;
+
   vars["OCTAVE_HOME"] = Voctave_home;
   vars["OCTAVE_EXEC_HOME"] = Voctave_exec_home;
 
@@ -227,14 +227,14 @@
     = get_variable ("OCTLIBDIR",
                     prepend_octave_exec_home (%OCTAVE_CONF_OCTLIBDIR%));
 
+  std::string DEFAULT_INCFLAGS;
+
 #if defined (OCTAVE_USE_WINDOWS_API)
-  std::string DEFAULT_INCFLAGS
-    = "-I" + quote_path (vars["OCTINCLUDEDIR"] + R"(\..)")
-      + " -I" + quote_path (vars["OCTINCLUDEDIR"]);
+  DEFAULT_INCFLAGS = "-I" + quote_path (vars["OCTINCLUDEDIR"] + R"(\..)")
+                     + " -I" + quote_path (vars["OCTINCLUDEDIR"]);
 #else
-  std::string DEFAULT_INCFLAGS
-    = "-I" + quote_path (vars["OCTINCLUDEDIR"] + "/..")
-      + " -I" + quote_path (vars["OCTINCLUDEDIR"]);
+  DEFAULT_INCFLAGS = "-I" + quote_path (vars["OCTINCLUDEDIR"] + "/..")
+                     + " -I" + quote_path (vars["OCTINCLUDEDIR"]);
 #endif
 
   if (vars["INCLUDEDIR"] != "/usr/include")
@@ -264,16 +264,22 @@
   vars["FPICFLAG"] = get_variable ("FPICFLAG", %OCTAVE_CONF_FPICFLAG%);
 
   vars["CC"] = get_variable ("CC", %OCTAVE_CONF_MKOCTFILE_CC%);
+  if (verbose && vars["CC"] == "cc-msvc")
+    vars["CC"] += " -d";
 
   vars["CFLAGS"] = get_variable ("CFLAGS", %OCTAVE_CONF_CFLAGS%);
 
   vars["CPICFLAG"] = get_variable ("CPICFLAG", %OCTAVE_CONF_CPICFLAG%);
 
   vars["CXX"] = get_variable ("CXX", %OCTAVE_CONF_MKOCTFILE_CXX%);
+  if (verbose && vars["CXX"] == "cc-msvc")
+    vars["CXX"] += " -d";
 
   vars["CXXFLAGS"] = get_variable ("CXXFLAGS", %OCTAVE_CONF_CXXFLAGS%);
 
   vars["CXXLD"] = get_variable ("CXXLD", vars["CXX"]);
+  if (verbose && vars["CXXLD"] == "cc-msvc")
+    vars["CXXLD"] += " -d";
 
   vars["CXXPICFLAG"] = get_variable ("CXXPICFLAG", %OCTAVE_CONF_CXXPICFLAG%);
 
@@ -296,6 +302,9 @@
   vars["DL_LDFLAGS"] = get_variable ("DL_LDFLAGS",
                                      %OCTAVE_CONF_MKOCTFILE_DL_LDFLAGS%);
 
+  if (! link_stand_alone)
+    DEFAULT_LDFLAGS += ' ' + vars["DL_LDFLAGS"];
+
   vars["RDYNAMIC_FLAG"] = get_variable ("RDYNAMIC_FLAG",
                                         %OCTAVE_CONF_RDYNAMIC_FLAG%);
 
@@ -339,8 +348,7 @@
     = get_variable ("OCT_LINK_OPTS",
                     replace_prefix (%OCTAVE_CONF_OCT_LINK_OPTS%));
 
-  vars["LDFLAGS"] = get_variable ("LDFLAGS",
-                                  replace_prefix (%OCTAVE_CONF_LDFLAGS%));
+  vars["LDFLAGS"] = get_variable ("LDFLAGS", DEFAULT_LDFLAGS);
 
   vars["LD_STATIC_FLAG"] = get_variable ("LD_STATIC_FLAG",
                                          %OCTAVE_CONF_LD_STATIC_FLAG%);
@@ -348,17 +356,23 @@
   // FIXME: Remove LFLAGS in Octave 8.0
   vars["LFLAGS"] = get_variable ("LFLAGS", DEFAULT_LDFLAGS);
   if (vars["LFLAGS"] != DEFAULT_LDFLAGS)
-    std::cerr << "warning: LFLAGS is deprecated and will be removed in a future version of Octave, use LDFLAGS instead" << std::endl;
+    std::cerr << "mkoctfile: warning: LFLAGS is deprecated and will be removed in a future version of Octave, use LDFLAGS instead" << std::endl;
 
   vars["F77_INTEGER8_FLAG"] = get_variable ("F77_INTEGER8_FLAG",
                                             %OCTAVE_CONF_F77_INTEGER_8_FLAG%);
   vars["ALL_FFLAGS"] = vars["FFLAGS"] + ' ' + vars["F77_INTEGER8_FLAG"];
+  if (debug)
+    vars["ALL_FFLAGS"] += " -g";
 
   vars["ALL_CFLAGS"]
     = vars["INCFLAGS"] + ' ' + vars["XTRA_CFLAGS"] + ' ' + vars["CFLAGS"];
+  if (debug)
+    vars["ALL_CFLAGS"] += " -g";
 
   vars["ALL_CXXFLAGS"]
     = vars["INCFLAGS"] + ' ' + vars["XTRA_CXXFLAGS"] + ' ' + vars["CXXFLAGS"];
+  if (debug)
+    vars["ALL_CXXFLAGS"] += " -g";
 
   vars["ALL_LDFLAGS"]
     = vars["LD_STATIC_FLAG"] + ' ' + vars["CPICFLAG"] + ' ' + vars["LDFLAGS"];
@@ -369,14 +383,14 @@
 
   vars["FFTW_LIBS"] = vars["FFTW3_LDFLAGS"] + ' ' + vars["FFTW3_LIBS"] + ' '
                       + vars["FFTW3F_LDFLAGS"] + ' ' + vars["FFTW3F_LIBS"];
+
+  return vars;
 }
 
 static std::string usage_msg = "usage: mkoctfile [options] file ...";
 
 static std::string version_msg = "mkoctfile, version " OCTAVE_VERSION;
 
-static bool debug = false;
-
 static std::string help_msg =
   "\n"
   "Options:\n"
@@ -564,7 +578,7 @@
 }
 
 static int
-run_command (const std::string& cmd, bool printonly = false)
+run_command (const std::string& cmd, bool verbose, bool printonly = false)
 {
   if (printonly)
     {
@@ -572,7 +586,7 @@
       return 0;
     }
 
-  if (debug)
+  if (verbose)
     std::cout << cmd << std::endl;
 
   int result = system (cmd.c_str ());
@@ -630,6 +644,32 @@
 }
 
 static std::string
+create_interleaved_complex_file (void)
+{
+  std::string tmpl = get_temp_directory () + "/oct-XXXXXX.c";
+
+  char *ctmpl = new char [tmpl.length () + 1];
+
+  ctmpl = strcpy (ctmpl, tmpl.c_str ());
+
+  // mkostemps will open the file and return a file descriptor.  We
+  // won't worry about closing it because we will need the file until we
+  // are done and then the file will be closed when mkoctfile exits.
+  int fd = octave_mkostemps_wrapper (ctmpl, 2);
+
+  // Make C++ string from filled-in template.
+  std::string retval (ctmpl);
+  delete [] ctmpl;
+
+  // Write symbol definition to file.
+  FILE *fid = fdopen (fd, "w");
+  fputs ("const int __mx_has_interleaved_complex__ = 1;\n", fid);
+  fclose (fid);
+
+  return retval;
+}
+
+static std::string
 tmp_objfile_name (void)
 {
   std::string tmpl = get_temp_directory () + "/oct-XXXXXX.o";
@@ -659,8 +699,6 @@
 int
 main (int argc, char **argv)
 {
-  initialize ();
-
   if (argc == 1)
     {
       std::cout << usage_msg << std::endl;
@@ -679,6 +717,9 @@
   std::string output_ext = ".oct";
   std::string objfiles, libfiles, octfile, outputfile;
   std::string incflags, defs, ldflags, pass_on_options;
+  std::string var_to_print;
+  bool debug = false;
+  bool verbose = false;
   bool strip = false;
   bool no_oct_file_strip_on_this_platform = is_true ("%NO_OCT_FILE_STRIP%");
   bool compile_only = false;
@@ -686,6 +727,11 @@
   bool depend = false;
   bool printonly = false;
   bool output_file_option = false;
+  bool creating_mex_file = false;
+  bool r2017b_option = false;
+  bool r2018a_option = false;
+  // The default for this may change in the future.
+  bool mx_has_interleaved_complex = false;
 
   for (int i = 1; i < argc; i++)
     {
@@ -725,13 +771,7 @@
       else if (arg == "-d" || arg == "-debug" || arg == "--debug"
                || arg == "-v" || arg == "-verbose" ||  arg == "--verbose")
         {
-          debug = true;
-          if (vars["CC"] == "cc-msvc")
-            vars["CC"] += " -d";
-          if (vars["CXX"] == "cc-msvc")
-            vars["CXX"] += " -d";
-          if (vars["CXXLD"] == "cc-msvc")
-            vars["CXXLD"] += " -d";
+          verbose = true;
         }
       else if (arg == "-silent" ||  arg == "--silent")
         {
@@ -764,7 +804,28 @@
         }
       else if (arg == "-largeArrayDims" || arg == "-compatibleArrayDims")
         {
-          std::cerr << "warning: -largeArrayDims and -compatibleArrayDims are accepted for compatibility, but ignored" << std::endl;
+          std::cerr << "mkoctfile: warning: -largeArrayDims and -compatibleArrayDims are accepted for compatibility, but ignored" << std::endl;
+        }
+      else if (arg == "-R2017b")
+        {
+          if (r2018a_option)
+            {
+              std::cerr << "mkoctfile: only one of -R2017b and -R2018a may be used" << std::endl;
+              return 1;
+            }
+
+          r2017b_option = true;
+        }
+      else if (arg == "-R2018a")
+        {
+          if (r2017b_option)
+            {
+              std::cerr << "mkoctfile: only one of -R2017b and -R2018a may be used" << std::endl;
+              return 1;
+            }
+
+          r2018a_option = true;
+          mx_has_interleaved_complex = true;
         }
       else if (starts_with (arg, "-Wl,") || starts_with (arg, "-l")
                || starts_with (arg, "-L") || starts_with (arg, "-R"))
@@ -801,13 +862,17 @@
         {
           if (i < argc-1)
             {
-              arg = argv[++i];
+              ++i;
+
               // FIXME: Remove LFLAGS checking in Octave 7.0
-              if (arg == "LFLAGS")
-                std::cerr << "warning: LFLAGS is deprecated and will be removed in a future version of Octave, use LDFLAGS instead" << std::endl;
+              if (! strcmp (argv[i], "LFLAGS"))
+                std::cerr << "mkoctfile: warning: LFLAGS is deprecated and will be removed in a future version of Octave, use LDFLAGS instead" << std::endl;
 
-              std::cout << vars[arg] << std::endl;
-              return 0;
+              if (! var_to_print.empty ())
+                std::cerr << "mkoctfile: warning: only one '" << arg
+                          << "' option will be processed" << std::endl;
+              else
+                var_to_print = argv[i];
             }
           else
             std::cerr << "mkoctfile: --print requires argument" << std::endl;
@@ -826,9 +891,7 @@
         }
       else if (arg == "-g")
         {
-          vars["ALL_CFLAGS"] += " -g";
-          vars["ALL_CXXFLAGS"] += " -g";
-          vars["ALL_FFLAGS"] += " -g";
+          debug = true;
         }
       else if (arg == "-link-stand-alone" || arg == "--link-stand-alone")
         {
@@ -836,6 +899,8 @@
         }
       else if (arg == "-mex" || arg == "--mex")
         {
+          creating_mex_file = true;
+
           incflags += " -I.";
 #if defined (_MSC_VER)
           ldflags += " -Wl,-export:mexFunction";
@@ -876,10 +941,54 @@
         octfile = file;
     }
 
-  if (output_ext ==  ".mex"
-      && vars["ALL_CFLAGS"].find ("-g") != std::string::npos)
+  std::map<std::string, std::string> vars
+    = make_vars_map (link_stand_alone, verbose, debug);
+
+  if (! var_to_print.empty ())
+    {
+      if (vars.find (var_to_print) == vars.end ())
+        {
+          std::cerr << "mkoctfile: unknown variable '" << var_to_print << "'"
+                    << std::endl;
+          return 1;
+        }
+
+      std::cout << vars[var_to_print] << std::endl;
+
+      return 0;
+    }
+
+  if (creating_mex_file)
     {
-      defs += " -DMEX_DEBUG";
+      if (vars["ALL_CFLAGS"].find ("-g") != std::string::npos)
+        defs += " -DMEX_DEBUG";
+
+      if (mx_has_interleaved_complex)
+        {
+          defs += " -DMX_HAS_INTERLEAVED_COMPLEX=1";
+
+          if (! compile_only)
+            {
+              // Create tmp C source file that defines an extern symbol
+              // that can be checked when loading the mex file to
+              // determine that the file was compiled expecting
+              // interleaved complex values.
+
+              std::string tmp_file = create_interleaved_complex_file ();
+
+              cfiles.push_back (tmp_file);
+            }
+        }
+    }
+  else
+    {
+      if (r2017b_option)
+        std::cerr << "mkoctfile: warning: -R2017b option ignored unless creating mex file"
+                  << std::endl;
+
+      if (r2018a_option)
+        std::cerr << "mkoctfile: warning: -R2018a option ignored unless creating mex file"
+                  << std::endl;
     }
 
   if (compile_only && output_file_option
@@ -1064,7 +1173,7 @@
                + vars["ALL_FFLAGS"] + ' ' + incflags + ' ' + defs + ' '
                + pass_on_options + ' ' + f + " -o " + o);
 
-          int status = run_command (cmd, printonly);
+          int status = run_command (cmd, verbose, printonly);
 
           if (status)
             return status;
@@ -1104,7 +1213,7 @@
                + pass_on_options + ' ' + incflags + ' ' + defs + ' '
                + quote_path (f) + " -o " + quote_path (o));
 
-          int status = run_command (cmd, printonly);
+          int status = run_command (cmd, verbose, printonly);
 
           if (status)
             return status;
@@ -1144,7 +1253,7 @@
                + pass_on_options + ' ' + incflags + ' ' + defs + ' '
                + quote_path (f) + " -o " + quote_path (o));
 
-          int status = run_command (cmd, printonly);
+          int status = run_command (cmd, verbose, printonly);
 
           if (status)
             return status;
@@ -1185,7 +1294,7 @@
                + vars["LFLAGS"] + ' ' + octave_libs + ' '
                + vars["OCTAVE_LINK_OPTS"] + ' ' + vars["OCTAVE_LINK_DEPS"]);
 
-          int status = run_command (cmd, printonly);
+          int status = run_command (cmd, verbose, printonly);
 
           clean_up_tmp_files (tmp_objfiles);
 
@@ -1219,7 +1328,7 @@
         cmd += ' ' + vars["FLIBS"];
 #endif
 
-      int status = run_command (cmd, printonly);
+      int status = run_command (cmd, verbose, printonly);
 
       clean_up_tmp_files (tmp_objfiles);
 
@@ -1231,7 +1340,7 @@
     {
       std::string cmd = "strip " + octfile;
 
-      int status = run_command (cmd, printonly);
+      int status = run_command (cmd, verbose, printonly);
 
       if (status)
         return status;
--- a/test/args.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/args.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -219,7 +219,7 @@
 %! f()
 
 ## struct
-%!function f (x = struct("a", 3))
+%!function f (x = struct ("a", 3))
 %!  assert (x, struct ("a", 3));
 %!endfunction
 %!test
--- a/test/bug-35448/fA.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/bug-35448/fA.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,7 +1,7 @@
-# fA.m
+## fA.m
 function y = fA (x, f)
   global gfun
-  if nargin < 2
+  if (nargin < 2)
     y = fA (x, gfun);
   else
     w = feval (f, x);
--- a/test/bug-35448/fB.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/bug-35448/fB.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,4 +1,4 @@
-# fB.m
+## fB.m
 function y = fB (x)
   y = x;
 endfunction
--- a/test/bug-35448/fC.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/bug-35448/fC.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,4 +1,4 @@
-# fC.m
+## fC.m
 function y = fC (x)
   y = x;
 endfunction
--- a/test/bug-36025/@testclass/one.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/bug-36025/@testclass/one.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,4 +1,4 @@
-% function ONE return item "X"
+%% function ONE return item "X"
 
 function a = one (m)
   a = m.x;
--- a/test/bug-36025/@testclass/two.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/bug-36025/@testclass/two.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,4 +1,4 @@
-% function TWO returns item "Y"
+%% function TWO returns item "Y"
 
 function a = one (m)
   a = m.y;
--- a/test/bug-38236/df_vr.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/bug-38236/df_vr.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,2 +1,2 @@
-# df_vr.m
+## df_vr.m
 vr = 7;
--- a/test/bug-38236/u_vr.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/bug-38236/u_vr.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,4 +1,4 @@
-# u_vr.m
+## u_vr.m
 
 ## define and exectute "__demo__" once
 eval ("function __demo__ ();  df_vr;  v = vr * 2; endfunction");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/bug-40117.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,76 @@
+########################################################################
+##
+## Copyright (C) 2020 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+%!function __mktestfun_40117__ (file, varargin)
+%!  unwind_protect
+%!    fid = fopen (file, "w");
+%!    fprintf (fid, "%s\n", varargin{:});
+%!  unwind_protect_cleanup
+%!    if (fid > 0)
+%!      fclose (fid);
+%!    endif
+%!  end_unwind_protect
+%!endfunction
+
+%!test <40117>
+%! unwind_protect
+%!   tmp_dir = tempname ();
+%!   mkdir (tmp_dir);
+%!   a_dir = fullfile (tmp_dir, "a");
+%!   a_private_dir = fullfile (a_dir, "private");
+%!   mkdir (a_dir);
+%!   mkdir (a_private_dir);
+%!   __mktestfun_40117__ (fullfile (a_dir, "main_40117.m"),
+%!                        "function r = main_40117 ()",
+%!                        "  r = p1_40117 ();",
+%!                        "endfunction");
+%!   __mktestfun_40117__ (fullfile (a_private_dir, "p1_40117.m"),
+%!                        "function r = p1_40117 ()",
+%!                        "  r = p2_40117 ();",
+%!                        "endfunction");
+%!   __mktestfun_40117__ (fullfile (a_private_dir, "p2_40117.m"),
+%!                        "function r = p2_40117 ()",
+%!                        "  r = 'a_p2_40117';",
+%!                        "endfunction");
+%!   addpath (a_dir);
+%!   assert (main_40117 (), "a_p2_40117");
+%!
+%!   ## Update the secondary private function, attempting to avoid
+%!   ## filesystem timestamp resolution problems.
+%!   pause (1);
+%!   __mktestfun_40117__ (fullfile (a_private_dir, "p2_40117.m"),
+%!                        "function r = p2_40117 ()",
+%!                        "  r = 'new function!';",
+%!                        "endfunction");
+%!
+%!   ## Force new functions to be found.
+%!   rehash ();
+%!
+%!   assert (main_40117 (), "new function!");
+%! unwind_protect_cleanup
+%!   rmpath (a_dir);
+%!   confirm_recursive_rmdir (false, "local");
+%!   rmdir (tmp_dir, "s");
+%! end_unwind_protect
--- a/test/bug-47680/super_bug47680.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/bug-47680/super_bug47680.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,7 +1,7 @@
 classdef super_bug47680
   properties
     tag;
-  end
+  endproperties
   methods
     function obj = super_bug47680 (x)
       obj.tag = x;
--- a/test/bug-50014/bug-50014.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/bug-50014/bug-50014.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -26,7 +26,7 @@
 %!error <duplicate subfunction or nested function name>
 %! duplicate_nested_function ()
 
-%!assert (duplicate_nested_in_subfunction_ok (), 3);
+%!assert (duplicate_nested_in_subfunction_ok (), 3)
 
 %!error <duplicate subfunction or nested function name>
 %! duplicate_nested_parent_function ()
@@ -52,4 +52,4 @@
 %!error <duplicate subfunction or nested function name>
 %! duplicate_subfunction_old_syntax ()
 
-%!assert (duplicate_subfunction_separate_scope_ok (), 3);
+%!assert (duplicate_subfunction_separate_scope_ok (), 3)
--- a/test/bug-50014/duplicate_parent_nested2.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/bug-50014/duplicate_parent_nested2.m	Thu Nov 19 13:08:00 2020 -0800
@@ -4,8 +4,8 @@
     function bug ()
     endfunction
   endfunction
-  function bug () ## no error here
-    function bug () ## error here (duplicates parent name)
+  function bug ()  # no error here
+    function bug ()  # error here (duplicates parent name)
     endfunction
   endfunction
 endfunction
--- a/test/bug-51532/+package_bug51532/foo.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/bug-51532/+package_bug51532/foo.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,3 +1,3 @@
 function retval = foo (val)
   retval = val;
-end
+endfunction
--- a/test/bug-54995/@testclass54995/testclass54995.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/bug-54995/@testclass54995/testclass54995.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,4 +1,4 @@
 function obj = testclass54995 ()
   obj = struct ("x", eye (4));
-  obj = class(obj, "testclass54995");
+  obj = class (obj, "testclass54995");
 endfunction
--- a/test/bug-55321.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/bug-55321.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -23,7 +23,7 @@
 ##
 ########################################################################
 
-%!function cb_children (hg)
+%!function cb_children (hg, ~)
 %!  hl = get (hg, "children");
 %!  color = get (hl, "color");
 %!  set (hl, "userdata", isequal (color, [1 0 0]));
--- a/test/bug-58593/myclass2.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/bug-58593/myclass2.m	Thu Nov 19 13:08:00 2020 -0800
@@ -13,16 +13,16 @@
       case '.'
         switch (S(1).subs)
         case 'data'
-          % Transform: obj.data --> obj.data_
+          %% Transform: obj.data --> obj.data_
           r = obj.data_;
           if (length (S) > 1)
             r = subsref (r, S(2:end));
           end
         case 'alldata'
-          % Transform: obj.data --> obj.data_(1:end)
-          % This statement should trigger *builtin* subsref *twice* (one
-          % for the evaluation of 'end', and the other for the whole rvalue).
-          % 'end' here is also builtin 'end'
+          %% Transform: obj.data --> obj.data_(1:end)
+          %% This statement should trigger *builtin* subsref *twice* (one
+          %% for the evaluation of 'end', and the other for the whole rvalue).
+          %% 'end' here is also builtin 'end'
           r = obj.data_(1:end);
 
           if (length (S) > 1)
@@ -32,7 +32,7 @@
           error ('Incorrect usage');
         end
       case '()'
-        % Transform: obj(index) --> obj.data_(index)
+        %% Transform: obj(index) --> obj.data_(index)
         r = subsref (obj.data_, S);
       otherwise
         error ('Incorrect usage');
@@ -44,25 +44,25 @@
       case '.'
         switch (S(1).subs)
         case 'data'
-          % Transform: obj.data --> obj.data_
-          if length(S)>1
+          %% Transform: obj.data --> obj.data_
+          if (length (S)>1)
             B = subsasgn (obj.data_, S(2:end), B);
           end
           obj.data_ = B;
         case 'alldata'
-          % Transform: obj.data --> obj.data_(1:end)
-          if length(S)>1
+          %% Transform: obj.data --> obj.data_(1:end)
+          if (length (S)>1)
             B = subsasgn (obj.data_(1:end), S(2:end), B);
           end
-          % This statement should trigger *builtin* subsref to evaluate 'end',
-          % then *builtin* subsasgn for the whole assignment expression
-          % 'end' here is also builtin 'end'
+          %% This statement should trigger *builtin* subsref to evaluate 'end',
+          %% then *builtin* subsasgn for the whole assignment expression
+          %% 'end' here is also builtin 'end'
           obj.data_(1:end) = B;
         otherwise
-          error('Incorrect usage');
+          error ('Incorrect usage');
         end
       case '()'
-        % Transform: obj(index) --> obj.data_(index)
+        %% Transform: obj(index) --> obj.data_(index)
         obj.data_ = subsasgn (obj.data_, S, B);
       otherwise
         error ('Incorrect usage');
@@ -70,7 +70,7 @@
     end
 
     function r = end (obj, k, n)
-      % We subtract 1 from the "real" end of obj.data_
+      %% We subtract 1 from the "real" end of obj.data_
       r = builtin ('end', obj.data_, k, n) - 1;
     end
   end
--- a/test/classdef/foo_subsref_subsasgn.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classdef/foo_subsref_subsasgn.m	Thu Nov 19 13:08:00 2020 -0800
@@ -18,7 +18,7 @@
 
     function ind = end (obj, k, n)
       sz = size (obj.x);
-      if k < n
+      if (k < n)
         ind = sz(k);
       else
         ind = prod (sz(k:end));
@@ -31,7 +31,7 @@
           if (S(1).type == "()")
             varargout = {obj.x(S(1).subs{1})};
           elseif (S(1).type == "{}")
-            % Note in ML R2018b "x{1:3}" expects "nargout == 3".
+            %% Note in ML R2018b "x{1:3}" expects "nargout == 3".
             varargout = num2cell (obj.x(S(1).subs{1}));
           elseif (S(1).type == "." && S(1).subs == 'x')
             varargout = {obj.x};
@@ -40,7 +40,7 @@
               'foo_subsref_subsasgn: Invalid syntax');
           end
         case 2
-          % Note in ML R2018b "x(1)(1)" is not allowed.
+          %% Note in ML R2018b "x(1)(1)" is not allowed.
           if (S(1).type == "{}" && (S(2).type == "{}" || S(2).type == "()"))
             varargout = {obj.x(S(1).subs{1}, S(2).subs{1})};
           elseif (S(1).type == "." && S(1).subs == 'x' ...
@@ -68,7 +68,7 @@
               'foo_subsref_subsasgn: Invalid syntax');
           end
         case 2
-          % Note in ML R2018b "x(1)(1)" is not allowed.
+          %% Note in ML R2018b "x(1)(1)" is not allowed.
           if (S(1).type == "{}" && (S(2).type == "{}" || S(2).type == "()"))
             obj.x(S(1).subs{1}, S(2).subs{1}) = varargin{1};
           elseif (S(1).type == "." && S(1).subs == 'x' ...
--- a/test/classes/@Blork/Blork.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@Blork/Blork.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,5 +1,5 @@
 function s = Blork (bleek)
-% Test class.
+%% Test class.
 
   if (nargin == 1 && isa (bleek, 'Blork'))
     s = bleek;
--- a/test/classes/@Blork/get.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@Blork/get.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,6 +1,6 @@
 function v = get (s, propName)
 
-  switch propName
+  switch (propName)
     case 'bleek'
       v = s.bleek;
     otherwise
--- a/test/classes/@Blork/set.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@Blork/set.m	Thu Nov 19 13:08:00 2020 -0800
@@ -5,7 +5,7 @@
     propName  = propArgs{1};
     propValue = propArgs{2};
     propArgs  = propArgs(3:end);
-    switch propName
+    switch (propName)
       case 'bleek'
         s.bleek = propValue;
       otherwise
--- a/test/classes/@CPrecedenceTester1/CPrecedenceTester1.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@CPrecedenceTester1/CPrecedenceTester1.m	Thu Nov 19 13:08:00 2020 -0800
@@ -3,6 +3,6 @@
   x = struct ('useless_data', pi);
   x = class (x, 'CPrecedenceTester1');
 
-  % don't change anything as far as precedence is concerned
+  %% don't change anything as far as precedence is concerned
 
 end
--- a/test/classes/@CPrecedenceTester2/CPrecedenceTester2.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@CPrecedenceTester2/CPrecedenceTester2.m	Thu Nov 19 13:08:00 2020 -0800
@@ -3,7 +3,7 @@
   x = struct ('useless_data', pi^2);
   x = class (x, 'CPrecedenceTester2');
 
-  switch flag
+  switch (flag)
     case 1  % CPrecedencetester2 > Snork
       superiorto ('Snork');
     case 2  % CPrecedencetester2 < Snork
--- a/test/classes/@CPrecedenceTester3/CPrecedenceTester3.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@CPrecedenceTester3/CPrecedenceTester3.m	Thu Nov 19 13:08:00 2020 -0800
@@ -3,7 +3,7 @@
   x = struct ('useless_data', pi^3);
   x = class (x, 'CPrecedenceTester3');
 
-  switch flag
+  switch (flag)
     case 1  % CPrecedencetester3 > Snork
       superiorto ('Snork');
     case 2  % CPrecedencetester3 < Snork
--- a/test/classes/@Cork/Cork.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@Cork/Cork.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,5 +1,5 @@
 function s = Cork (click)
-% Test class.
+%% Test class.
 
   if (nargin == 1 && isa (click, 'Cork'))
     s = click;
--- a/test/classes/@Cork/get.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@Cork/get.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,6 +1,6 @@
 function v = get (s, propName)
 
-  switch propName
+  switch (propName)
     case 'click'
       v = s.click;
     otherwise
--- a/test/classes/@Cork/set.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@Cork/set.m	Thu Nov 19 13:08:00 2020 -0800
@@ -5,7 +5,7 @@
     propName  = propArgs{1};
     propValue = propArgs{2};
     propArgs  = propArgs(3:end);
-    switch propName
+    switch (propName)
       case 'click'
         s.click = propValue;
       otherwise
--- a/test/classes/@Dork/display.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@Dork/display.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,5 +1,5 @@
 function display (s)
-%  Display the critical info for an amplifier
+%%  Display the critical info for an amplifier
 
    gick = get (s, 'gick');
    disp ([inputname(1),'.gick = ']);
--- a/test/classes/@Dork/get.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@Dork/get.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,6 +1,6 @@
 function v = get (s, propName)
 
-  switch propName
+  switch (propName)
     case 'gack'
       v = s.gack;
     otherwise
--- a/test/classes/@Dork/set.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@Dork/set.m	Thu Nov 19 13:08:00 2020 -0800
@@ -5,7 +5,7 @@
     propName  = propArgs{1};
     propValue = propArgs{2};
     propArgs  = propArgs(3:end);
-    switch propName
+    switch (propName)
       case 'gack'
         s.gack = propValue;
       otherwise
--- a/test/classes/@Gork/display.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@Gork/display.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,5 +1,5 @@
 function display (s)
-%  Display the critical info for a Gork.
+%%  Display the critical info for a Gork.
 
    dork_base = s.Dork
    %pork_base = s.Pork
--- a/test/classes/@Gork/get.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@Gork/get.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,13 +1,13 @@
 function v = get (s, propName)
 
-  switch propName
+  switch (propName)
     case 'cork'
       v = s.Cork;
     case 'gark'
       v = s.gark;
     otherwise
-      % Note that get/set for multiple parents is hard.  We only do one
-      % branch of the parent tree just to test this stuff out.
+      %% Note that get/set for multiple parents is hard.  We only do one
+      %% branch of the parent tree just to test this stuff out.
       v = get (s.Dork,propName);
   end
 
--- a/test/classes/@Gork/set.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@Gork/set.m	Thu Nov 19 13:08:00 2020 -0800
@@ -5,7 +5,7 @@
     propName  = propArgs{1};
     propValue = propArgs{2};
     propArgs  = propArgs(3:end);
-    switch propName
+    switch (propName)
       case 'cork'
         if (isa (propValue, 'Cork'))
           s.Cork = propValue;
@@ -15,8 +15,8 @@
       case 'gark'
         s.gark = propValue;
       otherwise
-        % Note that get/set for multiple parents is hard.  We only do one
-        % branch of the parent tree just to test this stuff out.
+        %% Note that get/set for multiple parents is hard.  We only do one
+        %% branch of the parent tree just to test this stuff out.
         s.Dork = set (s.Dork, propName, propValue);
     end
   end
--- a/test/classes/@Gork/subsasgn.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@Gork/subsasgn.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,8 +1,8 @@
 function g = subsasgn (g, s, x)
 
-  switch s.type
+  switch (s.type)
   case '.'
-    switch s.subs
+    switch (s.subs)
     case 'gyrk'
       g.gyrk = x;
     end
--- a/test/classes/@Gork/subsref.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@Gork/subsref.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,8 +1,8 @@
 function x = subsref (g, s)
 
-  switch s.type
+  switch (s.type)
   case '.'
-    switch s.subs
+    switch (s.subs)
     case 'gyrk'
       x = g.gyrk;
     end
--- a/test/classes/@Pork/display.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@Pork/display.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,5 +1,5 @@
 function display (s)
-%  Display the critical info for an amplifier
+%%  Display the critical info for an amplifier
 
    geek = get (s, 'geek');
    disp ([inputname(1),'.geek = ']);
--- a/test/classes/@Pork/get.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@Pork/get.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,6 +1,6 @@
 function v = get (s, propName)
 
-  switch propName
+  switch (propName)
     case 'gurk'
       v = s.gurk;
     otherwise
--- a/test/classes/@Pork/set.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@Pork/set.m	Thu Nov 19 13:08:00 2020 -0800
@@ -5,7 +5,7 @@
     propName  = propArgs{1};
     propValue = propArgs{2};
     propArgs  = propArgs(3:end);
-    switch propName
+    switch (propName)
       case 'gurk'
         s.gurk = propValue;
       otherwise
--- a/test/classes/@Sneetch/Sneetch.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@Sneetch/Sneetch.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,5 +1,5 @@
 function s = Sneetch (mcbean)
-% Test class: should produce error.
+%% Test class: should produce error.
 
   if (nargin == 1 && isa (mcbean, 'Sneetch'))
     s = mcbean;
--- a/test/classes/@Snork/Snork.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@Snork/Snork.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,5 +1,5 @@
 function s = Snork (gick)
-% Test class.
+%% Test class.
 
   if (nargin == 1 && isa (gick, 'Snork'))
     s = gick;
--- a/test/classes/@Snork/end.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@Snork/end.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,7 +1,7 @@
 function r = end (snk, index_pos, num_indices)
 
   if (num_indices ~= 1)
-    error ('Snork object may only have one index')
+    error ('Snork object may only have one index');
   end
 
   r = length (snk.cack);
--- a/test/classes/@Snork/get.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@Snork/get.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,6 +1,6 @@
 function v = get (s, propName)
 
-  switch propName
+  switch (propName)
     case 'gick'
       v = s.gick;
     otherwise
--- a/test/classes/@Snork/set.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@Snork/set.m	Thu Nov 19 13:08:00 2020 -0800
@@ -5,7 +5,7 @@
     propName  = propArgs{1};
     propValue = propArgs{2};
     propArgs  = propArgs(3:end);
-    switch propName
+    switch (propName)
       case 'gick'
         s.gick = propValue;
       otherwise
--- a/test/classes/@Spork/Spork.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@Spork/Spork.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,5 +1,5 @@
 function s = Spork (geek)
-% Test class.
+%% Test class.
 
     if (nargin == 1 && isa (geek, 'Spork'))
       s = geek;
--- a/test/classes/@Spork/get.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@Spork/get.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,6 +1,6 @@
 function v = get (s, propName)
 
-  switch propName
+  switch (propName)
     case 'geek'
       v = s.geek;
     otherwise
--- a/test/classes/@Spork/set.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/@Spork/set.m	Thu Nov 19 13:08:00 2020 -0800
@@ -5,7 +5,7 @@
     propName  = propArgs{1};
     propValue = propArgs{2};
     propArgs  = propArgs(3:end);
-    switch propName
+    switch (propName)
       case 'geek'
         s.geek = propValue;
       otherwise
--- a/test/classes/classes.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/classes/classes.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -65,9 +65,9 @@
 %! assert (isobject (snk));
 %! assert (isequal (class (snk), 'Snork'));
 %! assert (isa (snk, 'Snork'));
-%! assert (!isa (snk, 'Sneetch'));
+%! assert (! isa (snk, 'Sneetch'));
 %! assert (ismethod (snk, 'gick'));
-%! assert (!ismethod (snk, 'bletch'));
+%! assert (! ismethod (snk, 'bletch'));
 %! assert (exist ('snk') == 1);
 %! assert (exist ('blink') == 0);
 %!test snk1 = Snork (snk);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/colon-op/@legacy_colon_op/colon.m	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,7 @@
+function r = colon (a, b, c)
+  if (nargin == 2)
+    r = sprintf ("%s:%s", class (a), class (b));
+  else
+    r = sprintf ("%s:%s:%s", class (a), class (b), class (c));
+  endif
+endfunction
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/colon-op/@legacy_colon_op/legacy_colon_op.m	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,3 @@
+function obj = legacy_colon_op ()
+  obj = class (struct (), "legacy_colon_op");
+endfunction
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/colon-op/colon-op.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,25 @@
+%!test
+%! x = colon_op ();
+%! assert (x:2:3, "colon_op:double:double");
+%! assert (1:x:3, "double:colon_op:double");
+%! assert (1:2:x, "double:double:colon_op");
+%! assert (x:x:3, "colon_op:colon_op:double");
+%! assert (1:x:x, "double:colon_op:colon_op");
+%! assert (x:2:x, "colon_op:double:colon_op");
+%! assert (x:x:x, "colon_op:colon_op:colon_op");
+%! assert (x:2, "colon_op:double");
+%! assert (1:x, "double:colon_op");
+%! assert (x:x, "colon_op:colon_op");
+
+%!test
+%! x = legacy_colon_op ();
+%! assert (x:2:3, "legacy_colon_op:double:double");
+%! assert (1:x:3, "double:legacy_colon_op:double");
+%! assert (1:2:x, "double:double:legacy_colon_op");
+%! assert (x:x:3, "legacy_colon_op:legacy_colon_op:double");
+%! assert (1:x:x, "double:legacy_colon_op:legacy_colon_op");
+%! assert (x:2:x, "legacy_colon_op:double:legacy_colon_op");
+%! assert (x:x:x, "legacy_colon_op:legacy_colon_op:legacy_colon_op");
+%! assert (x:2, "legacy_colon_op:double");
+%! assert (1:x, "double:legacy_colon_op");
+%! assert (x:x, "legacy_colon_op:legacy_colon_op");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/colon-op/colon_op.m	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,11 @@
+classdef colon_op
+  methods
+    function r = colon (a, b, c)
+      if (nargin == 2)
+        r = sprintf ("%s:%s", class (a), class (b));
+      else
+        r = sprintf ("%s:%s:%s", class (a), class (b), class (c));
+      endif
+    endfunction
+  endmethods
+endclassdef
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/colon-op/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,7 @@
+colon_op_TEST_FILES = \
+  %reldir%/@legacy_colon_op/colon.m \
+  %reldir%/@legacy_colon_op/legacy_colon_op.m \
+  %reldir%/colon-op.tst \
+  %reldir%/colon_op.m
+
+TEST_FILES += $(colon_op_TEST_FILES)
--- a/test/command.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/command.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -174,5 +174,5 @@
 %! command_test w(m,1)   % edge weights
 %! assert (cmd_out, '|w(m,1)|');
 %!test
-%! command_test x2( size( x ) )
-%! assert (cmd_out, '|x2( size( x ) )|');
+%! command_test x2( size ( x ) )
+%! assert (cmd_out, '|x2( size ( x ) )|');
--- a/test/complex.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/complex.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -43,9 +43,9 @@
 
 ## bug #43313, -1 is both '>' and '==' to (-1 - 0i)
 %!test
-%! assert (complex(-1,0) == complex(-1,-0), true);
-%! assert (complex(-1,0) > complex(-1,-0), false);
-%! assert (complex(-1,0) < complex(-1,-0), false);
+%! assert (complex (-1,0) == complex (-1,-0), true);
+%! assert (complex (-1,0) > complex (-1,-0), false);
+%! assert (complex (-1,0) < complex (-1,-0), false);
 
 ## Test that sort and issorted both agree on boundary case
 %!test
--- a/test/ctor-vs-method/@parent/parent.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/ctor-vs-method/@parent/parent.m	Thu Nov 19 13:08:00 2020 -0800
@@ -3,12 +3,12 @@
   if (nargin == 0)
     rot = class (struct (), 'parent');
   else
-    switch class (a)
+    switch (class (a))
       case 'parent'
         %% copy constructor
         rot = a;
       otherwise
-        error ('type mismatch in parent constructor')
+        error ('type mismatch in parent constructor');
     end
   end
   __trace__ ('end parent/parent');
--- a/test/deprecate-props.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/deprecate-props.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -37,25 +37,3 @@
 %!    endif
 %!  endif
 %!endfunction
-
-## text/uicontrol/uipanel/uibuttongroup/uitable  "oblique" value for
-## "fontangle" property was deprecated in 5.0, remove from version 7:
-##   * remove "oblique" options in graphics.in.h, QtHandlesUtils.cc,
-##     and ft-text-renderer.cc
-##   * remove warnings from update_fontangle in graphics.in.h
-%!test
-%! hf = figure ("visible", "off");
-%! unwind_protect
-%!   ht = text ();
-%!   testprop (ht, "fontangle", "7.0", "oblique");
-%!   hui = uicontrol ();
-%!   testprop (hui, "fontangle", "7.0", "oblique");
-%!   hui = uipanel ();
-%!   testprop (hui, "fontangle", "7.0", "oblique");
-%!   hui = uibuttongroup ();
-%!   testprop (hui, "fontangle", "7.0", "oblique");
-%!   hui = uitable ();
-%!   testprop (hui, "fontangle", "7.0", "oblique");
-%! unwind_protect_cleanup
-%!   close (hf);
-%! end_unwind_protect
--- a/test/diag-perm.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/diag-perm.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -178,6 +178,8 @@
 %! assert (diag (D1D2), d1 .* d2);
 
 ## slicing
+## preserving diagonal matrix type is not possible if indices are
+## general matrix objects.
 %!test
 %! m = 13;
 %! n = 6;
@@ -185,7 +187,11 @@
 %! d = rand (mn, 1);
 %! D = diag (d, m, n);
 %! Dslice = D (1:(m-3), 1:(n-2));
-%! assert (typeinfo (Dslice), "diagonal matrix");
+%! if (disable_range ())
+%!   assert (typeinfo (Dslice), "matrix");
+%! else
+%!   assert (typeinfo (Dslice), "diagonal matrix");
+%! endif
 
 ## preserve dense matrix structure when scaling
 %!assert (typeinfo (rand (8) * (3 * eye (8))), "matrix")
@@ -226,7 +232,7 @@
 %! A = sprand (n, n, .5);
 %! scalefact = rand (n-2, 1);
 %! Dr = diag (scalefact, n, n-2);
-%! assert (full (Dr \ A), Dr \ full(A));
+%! assert (full (Dr \ A), Dr \ full (A));
 
 ## sparse inverse column scaling with a zero factor
 %!test
@@ -236,15 +242,15 @@
 %! Dc = diag (scalefact);
 %! scalefact(n-1) = Inf;
 %! Dc(n-1, n-1) = 0;
-%! assert (full (A / Dc), full(A) / Dc);
+%! assert (full (A / Dc), full (A) / Dc);
 
 ## short sparse inverse column scaling
 %!test
 %! n = 7;
 %! A = sprand (n, n, .5);
-%! scalefact = rand (1, n-2) + I () * rand(1, n-2);
+%! scalefact = rand (1, n-2) + I () * rand (1, n-2);
 %! Dc = diag (scalefact, n-2, n);
-%! assert (full (A / Dc), full(A) / Dc);
+%! assert (full (A / Dc), full (A) / Dc);
 
 ## adding sparse and diagonal stays sparse
 %!test
--- a/test/eval-catch.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/eval-catch.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -35,12 +35,12 @@
 
 %!test
 %! eval ("clear a; a; str = '';", "str=lasterr;");
-%! assert (lasterr()(1:13), "'a' undefined");
+%! assert (lasterr ()(1:13), "'a' undefined");
 %! assert (str(1:13), "'a' undefined");
 
 %!test
 %! eval ("error ('user-defined error'); str = '';", "str = lasterr;");
-%! assert (lasterr()(1:18), "user-defined error");
+%! assert (lasterr ()(1:18), "user-defined error");
 %! assert (str(1:18), "user-defined error");
 
 %!function ms = mangle (s)
--- a/test/fcn-handle/package-function.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/fcn-handle/package-function.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -33,4 +33,4 @@
 
 ## Also test without function handle.
 %!assert <*55975> (pkga.pkgb.f1 (), "pkg f1");
-%!assert (pkga.pkgb.f2 (), "pkg f2");
+%!assert (pkga.pkgb.f2 (), "pkg f2")
--- a/test/fcn-handle/static-method.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/fcn-handle/static-method.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -33,4 +33,4 @@
 
 ## Also test without function handle.
 %!assert <*55975> (pkga.pkgb.bug51709_a.smeth (), "pkg bug51709_a");
-%!assert (pkga.pkgb.bug51709_b.smeth (), "pkg bug51709_b");
+%!assert (pkga.pkgb.bug51709_b.smeth (), "pkg bug51709_b")
--- a/test/for.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/for.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -161,3 +161,45 @@
 %! endfor
 %! assert (cnt, 0);
 %! assert (k, cell (0,3));
+
+%!test <*45143>
+%! warning ("on", "Octave:infinite-loop", "local");
+%! fail ("for i = 0:inf; break; end", "warning",
+%!       "FOR loop limit is infinite");
+%!
+%! fail ("for i = 0:-1:-inf; break; end", "warning",
+%!       "FOR loop limit is infinite");
+
+%!test <*45143>
+%! warning ("on", "Octave:infinite-loop", "local");
+%! k = 0;
+%! for i = 1:Inf
+%!   if (++k > 10)
+%!     break;
+%!   endif
+%! endfor
+%! assert (i, 11);
+%!
+%! k = 0;
+%! for i = -1:-1:-Inf
+%!   if (++k > 10)
+%!     break;
+%!   endif
+%! endfor
+%! assert (i, -11);
+%!
+%! k = 0;
+%! for i = 1:-Inf
+%!   if (++k > 10)
+%!     break;
+%!   endif
+%! endfor
+%! assert (i, zeros (1,0));
+%!
+%! k = 0;
+%! for i = 0:-1:Inf
+%!   if (++k > 10)
+%!     break;
+%!   endif
+%! endfor
+%! assert (i, zeros (1,0));
--- a/test/func.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/func.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -81,8 +81,8 @@
 %!
 %!    y = feval (fn, m, varargin{:});
 %!    y2 = feval (fn, reshape (mn, size (m)), varargin{:});
-%!    if (!strcmp (class (y), class (m)) ||
-%!         issparse (y) != issparse (m) || !size_equal (y, y2))
+%!    if (! strcmp (class (y), class (m)) ||
+%!         issparse (y) != issparse (m) || ! size_equal (y, y2))
 %!      error ("failed for type %s\n", typ{i});
 %!    endif
 %!    if (!(strcmp (typ{i}, "cell") || strcmp (typ{i}, "struct")) &&
@@ -211,5 +211,14 @@
 %!  retval = in1;
 %!endfunction
 
-%!error <can't make function parameter retval persistent> __fnpersist1__ (1);
-%!error <can't make function parameter in1 persistent> __fnpersist2__ (1);
+%!error <can't make function parameter retval persistent> __fnpersist1__ (1)
+%!error <can't make function parameter in1 persistent> __fnpersist2__ (1)
+
+## Check nargin, nargout validation by interpreter
+%!function __fn_nargout0__ (in1)
+%!endfunction
+%!function [out1] = __fn_nargin2__ (in1, in2)
+%!endfunction
+
+%!error <function called with too many outputs> r = __fn_nargout0__ ()
+%!error <function called with too many inputs>  r = __fn_nargin2__ (1,2,3)
--- a/test/if.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/if.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -107,15 +107,15 @@
 %! assert (x, 13);
 
 ## test "is_true" of different data types
-%!error diag (NaN) || 0;
+%!error diag (NaN) || 0
 %!test
 %! d1 = diag ([])    || 0;
 %! d2 = diag (1)     || 0;
 %! d3 = diag ([1 2]) || 0;
 %! assert ([d1 d2 d3], [false true false]);
 
-%!error sparse (NaN) || 0;
-%!error sparse ([1 1 ; 1 NaN]) || 0;
+%!error sparse (NaN) || 0
+%!error sparse ([1 1 ; 1 NaN]) || 0
 %!test
 %! s1 = sparse ([])  || 0;
 %! s2 = sparse (1)   || 0;
@@ -133,5 +133,5 @@
 %! c1 = [2i 4i] || 0;
 %! c2 = [22 4i] || 0;
 %! c3 = i || 0;
-%! c4 = complex(0) || 0;
+%! c4 = complex (0) || 0;
 %! assert ([c1 c2 c3 c4], [true true true false]);
--- a/test/index.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/index.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -513,8 +513,8 @@
 %!error <index \(2\): out of bound 1>                1(2)
 %!error <index \(1\): out of bound 0>                [](1)
 %!error <index \(-1\): subscripts>                   1(1)(-1)(1)
-%!error <index \(_,1\): out of bound 0 \(dimensions are 5x0\)> zeros(5,0)(3,1)
-%!error <index \(3,_\): out of bound 0 \(dimensions are 0x5\)> zeros(0,5)(3,1)
+%!error <index \(_,1\): out of bound 0 \(dimensions are 5x0\)> zeros (5,0)(3,1)
+%!error <index \(3,_\): out of bound 0 \(dimensions are 0x5\)> zeros (0,5)(3,1)
 %!
 %!shared abc
 %! abc = [1, 2];
@@ -539,8 +539,8 @@
 %!error <=: nonconformant arguments \(op1 is 1x1, op2 is 1x5\)> abc(3,5) = 1:5
 
 ##  Test diagonal matrices, and access of function results
-%!error <index \(_,_,5\): out of bound 1 \(dimensions are 3x3\)> eye(3)(2,3,5)
-%!error <index \(-2,_\): subscripts>               eye(4)(-2,3)
+%!error <index \(_,_,5\): out of bound 1 \(dimensions are 3x3\)> eye (3)(2,3,5)
+%!error <index \(-2,_\): subscripts>               eye (4)(-2,3)
 
 ##  Test cells
 %!shared abc
@@ -558,7 +558,7 @@
 
 ##  Test sparse matrices
 %!shared abc
-%! abc = sparse(3,3);
+%! abc = sparse (3,3);
 %!error <abc\(-1\): subscripts>                abc(-1)
 %!error <abc\(-1\): subscripts>                abc(-1) = 1
 %!error <abc\(-1,_\): subscripts>              abc(-1,1)
@@ -578,7 +578,7 @@
 %! abc = [1 2];
 %!error <abc\(0\+1i\): subscripts must be real>     abc(i)
 %! abc = [1 2; 3 4];
-%!error <abc\(1\+0i\): subscripts must be real>     abc(complex(1))
+%!error <abc\(1\+0i\): subscripts must be real>     abc(complex (1))
 %!error <abc\(1\+0.5i,_\): subscripts must be real> abc(1+0.5*i,3)
 %!error <abc\(_,0-2i\): subscripts must be real>    abc(2,0-2*i)
 
@@ -587,6 +587,6 @@
 %! a(1,1,1).b(1) = 3;
 
 %!test <*39789>
-%! c = cell(1,1,1);
+%! c = cell (1,1,1);
 %! c{1,1,1} = zeros(5, 2);
 %! c{1,1,1}(:, 1) = 1;
--- a/test/inline-fcn.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/inline-fcn.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -6,7 +6,7 @@
 %!assert (fn (6), 37)
 %!assert (feval (inline ("sum (x(:))"), [1 2; 3 4]), 10)
 %!assert (feval (inline ("sqrt (x^2 + y^2)", "x", "y"), 3, 4), 5)
-%!assert (feval (inline ("exp (P1*x) + P2", 3), 3, 4, 5), exp(3*4) + 5)
+%!assert (feval (inline ("exp (P1*x) + P2", 3), 3, 4, 5), exp (3*4) + 5)
 
 ## Test input validation
 %!error inline ()
--- a/test/integer.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/integer.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -50,3 +50,111 @@
 %!   xdiv = clsmax / 0.5;
 %!   assert (xdiv, clsmax);
 %! endfor
+
+## Tests for binary constants
+%!assert (0b1, uint8 (2^0))
+%!assert (0b10000000, uint8 (2^7))
+%!assert (0b11111111, intmax ("uint8"))
+%!assert (0b100000000, uint16 (2^8))
+%!assert (0b1000000000000000, uint16 (2^15))
+%!assert (0b1111111111111111, intmax ("uint16"))
+%!assert (0b10000000000000000, uint32 (2^16))
+%!assert (0b10000000000000000000000000000000, uint32 (2^31))
+%!assert (0b11111111111111111111111111111111, intmax ("uint32"))
+%!assert (0b100000000000000000000000000000000, uint64 (2^32))
+%!assert (0b1000000000000000000000000000000000000000000000000000000000000000, uint64 (2^63))
+%!assert (0b1111111111111111111111111111111111111111111111111111111111111111, intmax ("uint64"))
+%!error <too many digits for binary constant> eval ("0b11111111111111111111111111111111111111111111111111111111111111111")
+
+%!assert (0b1u16, uint16 (2^0))
+%!assert (0b10000000u16, uint16 (2^7))
+
+%!assert (0b1u32, uint32 (2^0))
+%!assert (0b10000000u32, uint32 (2^7))
+%!assert (0b1000000000000000u32, uint32 (2^15))
+
+%!assert (0b1u64, uint64 (2^0))
+%!assert (0b10000000u64, uint64 (2^7))
+%!assert (0b1000000000000000u64, uint64 (2^15))
+%!assert (0b10000000000000000000000000000000u64, uint64 (2^31))
+
+%!assert (0b1s16, int16 (2^0))
+%!assert (0b10000000s16, int16 (2^7))
+
+%!assert (0b1s32, int32 (2^0))
+%!assert (0b10000000s32, int32 (2^7))
+%!assert (0b1000000000000000s32, int32 (2^15))
+
+%!assert (0b1s64, int64 (2^0))
+%!assert (0b10000000s64, int64 (2^7))
+%!assert (0b1000000000000000s64, int64 (2^15))
+%!assert (0b10000000000000000000000000000000s64, int64 (2^31))
+
+## Tests for hexadecimal constants
+%!assert (0x1, uint8 (2^0))
+%!assert (0x80, uint8 (2^7))
+%!assert (0xff, intmax ("uint8"))
+%!assert (0x100, uint16 (2^8))
+%!assert (0x8000, uint16 (2^15))
+%!assert (0xffff, intmax ("uint16"))
+%!assert (0x10000, uint32 (2^16))
+%!assert (0x80000000, uint32 (2^31))
+%!assert (0xffffffff, intmax ("uint32"))
+%!assert (0x100000000, uint64 (2^32))
+%!assert (0x8000000000000000, uint64 (2^63))
+%!assert (0xffffffffffffffff, intmax ("uint64"))
+%!error <too many digits for hexadecimal constant> eval ("0xfffffffffffffffff")
+
+%!assert (0x1u16, uint16 (2^0))
+%!assert (0x80u16, uint16 (2^7))
+
+%!assert (0x1u32, uint32 (2^0))
+%!assert (0x80u32, uint32 (2^7))
+%!assert (0x8000u32, uint32 (2^15))
+
+%!assert (0x1u64, uint64 (2^0))
+%!assert (0x80u64, uint64 (2^7))
+%!assert (0x8000u64, uint64 (2^15))
+%!assert (0x80000000u64, uint64 (2^31))
+
+%!assert (0x1s16, int16 (2^0))
+%!assert (0x80s16, int16 (2^7))
+
+%!assert (0x1s32, int32 (2^0))
+%!assert (0x80s32, int32 (2^7))
+%!assert (0x8000s32, int32 (2^15))
+
+%!assert (0x1s64, int64 (2^0))
+%!assert (0x80s64, int64 (2^7))
+%!assert (0x8000s64, int64 (2^15))
+%!assert (0x80000000s64, int64 (2^31))
+
+## Tests for decimal constants with extreme values
+
+%!assert (uint64 (9007199254740992), uint64 (flintmax ()))
+%!assert (int64 (9007199254740992), int64 (flintmax ()))
+%!assert (uint64 (-9007199254740992), uint64 (-flintmax ()))
+%!assert (int64 (-9007199254740992), int64 (-flintmax ()))
+
+%!assert (uint64 (9007199254740993), uint64 (flintmax ())+1)
+%!assert (int64 (9007199254740993), int64 (flintmax ())+1)
+%!assert (uint64 (-9007199254740993), uint64 (-flintmax ())-1)
+%!assert (int64 (-9007199254740993), int64 (-flintmax ())-1)
+
+%!assert (uint64 (18446744073709551615), intmax ("uint64"))
+
+%!assert (int64 (9223372036854775807), intmax ("int64"))
+%!assert (int64 (-9223372036854775808), intmin ("int64"))
+
+%!test
+%! a = int64 ([9223372036854775803; 9223372036854775804; 9223372036854775805; 9223372036854775806; 9223372036854775807]);
+%! bval = int64 (9223372036854775807);
+%! b = [bval; bval; bval; bval; bval];
+%! assert (a, b);
+
+%!test
+%! a = int64 ([int64(9223372036854775803); 9223372036854775804; 9223372036854775805; 9223372036854775806; 9223372036854775807]);
+%! b0val = int64 (9223372036854775803);
+%! bval = int64 (9223372036854775807);
+%! b = [b0val; bval; bval; bval; bval];
+%! assert (a, b);
--- a/test/io.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/io.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -196,7 +196,7 @@
 %! [load_status, load_files] = testls (1);
 %!
 %! for f = [save_files, load_files]
-%!   unlink (f{1});
+%!   sts = unlink (f{1});
 %! endfor
 %!
 %! assert (save_status && load_status);
@@ -228,7 +228,7 @@
 %!   assert (s64, s64t);
 %!   assert (u64, u64t);
 %! unwind_protect_cleanup
-%!   unlink (h5file);
+%!   sts = unlink (h5file);
 %! end_unwind_protect
 
 %!test
@@ -256,7 +256,7 @@
 %!       "-struct", "STR", "matrix_fld", "str*_fld");
 %! STR = load (struct_dat);
 %!
-%! assert (!isfield (STR,"scalar_fld") && ...
+%! assert (! isfield (STR,"scalar_fld") && ...
 %!         STR.matrix_fld == [1.1,2;3,4] && ...
 %!         STR.string_fld == "Octave" && ...
 %!         STR.struct_fld.x == 0 && ...
@@ -407,11 +407,11 @@
 %% Note use fprintf so output not sent to stdout
 %!test
 %! nm = tempname ();
-%! fid1 = fopen (nm,"w");
+%! fid1 = fopen (nm, "w");
 %! x = fprintf (fid1, "%s: %d\n", "test", 1);
 %! fclose (fid1);
-%! fid2 = fopen (nm,"r");
-%! str = fscanf (fid2,"%s");
+%! fid2 = fopen (nm, "r");
+%! str = fscanf (fid2, "%s");
 %! fclose (fid2);
 %! unlink (nm);
 %! assert (x, 8);
--- a/test/jit.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/jit.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -192,17 +192,17 @@
 %! assert (abs (result - 1/9) < 1e-5);
 %! assert (jit_failcnt, 0);
 
-# %!testif HAVE_LLVM
-# %! jit_failcnt (0);
-# %! temp = 1+1i;
-# %! nan = NaN;
-# %! while (1)
-# %!   temp = temp - 1i;
-# %!   temp = temp * nan;
-# %!   break;
-# %! endwhile
-# %! assert (imag (temp), 0);
-# %! assert (jit_failcnt, 0);
+## %!testif HAVE_LLVM
+## %! jit_failcnt (0);
+## %! temp = 1+1i;
+## %! nan = NaN;
+## %! while (1)
+## %!   temp = temp - 1i;
+## %!   temp = temp * nan;
+## %!   break;
+## %! endwhile
+## %! assert (imag (temp), 0);
+## %! assert (jit_failcnt, 0);
 
 %!testif HAVE_LLVM
 %! jit_failcnt (0);
@@ -217,15 +217,15 @@
 %! assert (imag (temp), 0);
 %! assert (jit_failcnt, 0);
 
-# %!testif HAVE_LLVM
-# %! jit_failcnt (0);
-# %! temp = 1+1i;
-# %! while (1)
-# %!   temp = temp * 5;
-# %!   break;
-# %! endwhile
-# %! assert (temp, 5+5i);
-# %! assert (jit_failcnt, 0);
+## %!testif HAVE_LLVM
+## %! jit_failcnt (0);
+## %! temp = 1+1i;
+## %! while (1)
+## %!   temp = temp * 5;
+## %!   break;
+## %! endwhile
+## %! assert (temp, 5+5i);
+## %! assert (jit_failcnt, 0);
 
 %!testif HAVE_LLVM
 %! jit_failcnt (0);
@@ -249,22 +249,22 @@
 %! assert (sum (mat) == total);
 %! assert (jit_failcnt, 0);
 
-# %!testif HAVE_LLVM
-# %! jit_failcnt (0);
-# %! nr = 1001;
-# %! mat = [3 1 5];
-# %! try
-# %!   for i = 1:nr
-# %!     if (i > 500)
-# %!       result = mat(100);
-# %!     else
-# %!       result = i;
-# %!     endif
-# %!   endfor
-# %! catch
-# %! end_try_catch
-# %! assert (result == 500);
-# %! assert (jit_failcnt, 0);
+## %!testif HAVE_LLVM
+## %! jit_failcnt (0);
+## %! nr = 1001;
+## %! mat = [3 1 5];
+## %! try
+## %!   for i = 1:nr
+## %!     if (i > 500)
+## %!       result = mat(100);
+## %!     else
+## %!       result = i;
+## %!     endif
+## %!   endfor
+## %! catch
+## %! end_try_catch
+## %! assert (result == 500);
+## %! assert (jit_failcnt, 0);
 
 %!function result = gen_test (n)
 %!  result = double (rand (1, n) > .01);
@@ -388,14 +388,14 @@
 %! endfor
 %!endfunction
 
-# %!testif HAVE_LLVM
-# %! jit_failcnt (0);
-# %! lasterr ("");
-# %! try
-# %!   test_divide ();
-# %! end_try_catch
-# %! assert (strcmp (lasterr (), "division by zero"));
-# %! assert (jit_failcnt, 0);
+## %!testif HAVE_LLVM
+## %! jit_failcnt (0);
+## %! lasterr ("");
+## %! try
+## %!   test_divide ();
+## %! end_try_catch
+## %! assert (strcmp (lasterr (), "division by zero"));
+## %! assert (jit_failcnt, 0);
 
 %!testif HAVE_LLVM
 %! jit_failcnt (0);
@@ -459,17 +459,17 @@
 %! assert (a == 9);
 %! assert (jit_failcnt, 0);
 
-# %!testif HAVE_LLVM
-# %! jit_failcnt (0);
-# %! num = 2;
-# %! a = zeros (1, num);
-# %! i = 1;
-# %! while i <= num
-# %!   a(i) = norm (eye (i));
-# %!   ++i;
-# %! endwhile
-# %! assert (a, ones (1, num));
-# %! assert (jit_failcnt, 0);
+## %!testif HAVE_LLVM
+## %! jit_failcnt (0);
+## %! num = 2;
+## %! a = zeros (1, num);
+## %! i = 1;
+## %! while i <= num
+## %!   a(i) = norm (eye (i));
+## %!   ++i;
+## %! endwhile
+## %! assert (a, ones (1, num));
+## %! assert (jit_failcnt, 0);
 
 %!function test_compute_idom ()
 %! while (li <= length (l1) && si <= length (s1))
@@ -583,14 +583,14 @@
 %! assert (id (1, 2), 1);
 %! assert (jit_failcnt, 0);
 
-# %!testif HAVE_LLVM
-# %! jit_failcnt (0);
-# %! lasterr ("");
-# %! try
-# %!   id ();
-# %! end_try_catch
-# %! assert (strncmp (lasterr (), "'x' undefined near", 18));
-# %! assert (jit_failcnt, 0);
+## %!testif HAVE_LLVM
+## %! jit_failcnt (0);
+## %! lasterr ("");
+## %! try
+## %!   id ();
+## %! end_try_catch
+## %! assert (strncmp (lasterr (), "'x' undefined near", 18));
+## %! assert (jit_failcnt, 0);
 
 ## Restore JIT settings
 %!testif HAVE_LLVM
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/json/jsondecode_BIST.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,556 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Unit tests for jsondecode()
+%%
+%% Code in libinterp/corefcn/jsondecode.cc
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Note: This script is intended to also run under Matlab to verify
+%%       compatibility.  Preserve Matlab-formatting when making changes.
+
+%%% Test 1: decode null values
+
+%% null, in non-numeric arrays -> Empty double []
+%!testif HAVE_RAPIDJSON
+%! json = '["str", 5, null, true]';
+%! exp  = {'str'; 5; []; true};
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% null, in numeric arrays to NaN (extracted from JSONio)
+%!testif HAVE_RAPIDJSON
+%! json = '[1, 2, null, 3]';
+%! exp  = [1; 2; NaN; 3];
+%! obs  = jsondecode (json);
+%! assert (isequaln (obs, exp));
+
+%% corner case: array of null values
+%!testif HAVE_RAPIDJSON
+%! json = '[null, null, null]';
+%! exp  = [NaN; NaN; NaN];
+%! obs  = jsondecode (json);
+%! assert (isequaln (obs, exp));
+
+%%% Test 2: Decode scalar Boolean, Number, and String values
+
+%!testif HAVE_RAPIDJSON
+%! assert (isequal (jsondecode ('true'), logical (1)));
+%! assert (isa (jsondecode ('true'), 'logical'));
+%! assert (isequal (jsondecode ('false'), logical (0)));
+%! assert (isa (jsondecode ('false'), 'logical'));
+%! assert (isequal (jsondecode ('123.45'), 123.45));
+%! assert (isequal (jsondecode ('"hello there"'), 'hello there'));
+
+%%% Test 3: Decode Array of Booleans, Numbers, and Strings values
+
+%% vectors are always rendered as column vectors
+%!testif HAVE_RAPIDJSON
+%! json = '[true, true, false, true]';
+%! exp  = logical ([1; 1; 0; 1]);
+%! obs  = jsondecode (json);
+%! assert (isa (obs, 'logical'));
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON <59135>
+%! json = '[[true, true], [false, true]]';
+%! exp  = logical ([1, 1; 0, 1]);
+%! obs  = jsondecode (json);
+%! assert (isa (obs, 'logical'));
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! json = '["true", "true", "false", "true"]';
+%! exp  = {'true'; 'true'; 'false'; 'true'};
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! json = '["foo", "bar", ["foo", "bar"]]';
+%! exp  = {'foo'; 'bar'; {'foo'; 'bar'}};
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% vectors are always rendered as column vectors
+%!testif HAVE_RAPIDJSON
+%! json = '[15000, 5, 12.25, 1502302.3012]';
+%! exp  = [15000; 5; 12.25; 1502302.3012];
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% row vectors are preserved by adding one level of hierarchy
+%% extracted from JSONio
+%!testif HAVE_RAPIDJSON
+%! json = '[[1,2]]';
+%! exp  = [1, 2];
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% If same dimensions -> transform to an array (extracted from JSONio)
+%!testif HAVE_RAPIDJSON
+%! json = '[[1, 2], [3, 4]]';
+%! exp  = [1, 2; 3, 4];
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% extracted from JSONio
+%!testif HAVE_RAPIDJSON
+%! json = '[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]';
+%! exp  = cat (3, [1, 3; 5, 7], [2, 4; 6, 8]);
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% try different dimensions for the array
+%!testif HAVE_RAPIDJSON
+%! json = '[[[1, 2, -1], [3, 4, null]], [[5, 6, Inf], [7, 8, -Inf]]]';
+%! exp  = cat (3, [1, 3; 5, 7], [2, 4; 6, 8], [-1, NaN; Inf, -Inf]);
+%! obs  = jsondecode (json);
+%! assert (isequaln (obs, exp));
+
+%% try different dimensions for the array
+%!testif HAVE_RAPIDJSON
+%! json = '[[[1, 2], [3, 4]], [[5, 6], [7, 8]], [[9, 10], [11, 12]]]';
+%! exp  = cat (3, [1, 3; 5, 7; 9, 11], [2, 4; 6, 8; 10, 12]);
+%! obs  = jsondecode (json);
+%! assert (isequaln (obs, exp));
+
+%% try higher dimensions for the array
+%!testif HAVE_RAPIDJSON
+%! json = ['[[[[1,-1], [2,-2]],[[3,-3],[4,-4]]],[[[5,-5],[6,-6]],[[7,-7],', ...
+%!         '[8,-8]]],[[[9,-9], [10,-10]],[[11,-11],[12,-12]]],', ...
+%!         '[[[13,-13],[14,-14]],[[15,-15],[16,-16]]]]'];
+%! var1 = cat (3, [1, 3; 5, 7; 9, 11; 13, 15], [2, 4; 6, 8; 10, 12; 14, 16]);
+%! var2 = cat (3, [-1, -3; -5, -7; -9, -11; -13, -15], ...
+%!             [-2, -4; -6, -8; -10, -12; -14, -16]);
+%! exp  = cat (4, var1, var2);
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! json = '[[true, false], [true, false], [true, false]]';
+%! exp  = logical ([1 0; 1 0; 1 0]);
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% If different dimensions -> transform to a cell array (extracted from JSONio)
+%!testif HAVE_RAPIDJSON
+%! json = '[[1, 2], [3, 4, 5]]';
+%! exp  = {[1; 2]; [3; 4; 5]};
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% extracted from JSONio
+%%!testif HAVE_RAPIDJSON
+%! json = '[1, 2, [3, 4]]';
+%! exp  = {1; 2; [3; 4]};
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! json = '[true, false, [true, false, false]]';
+%! exp  = {true; false; logical([1; 0; 0])};
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+%! assert (isa (obs{1}, 'logical'));
+%! assert (isa (obs{2}, 'logical'));
+%! assert (isa (obs{3}, 'logical'));
+
+%%% Test 4: decode JSON Objects
+
+%% Check decoding of Boolean, Number, and String values inside an Object
+%!testif HAVE_RAPIDJSON
+%! json = '{"number": 3.14, "string": "foobar", "boolean": false}';
+%! exp  = struct ('number', 3.14, 'string', 'foobar', 'boolean', false);
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+%! assert (isa (obs.boolean, 'logical'));
+
+%% Check decoding of null values and arrays inside an object & makeValidName
+%!testif HAVE_RAPIDJSON
+%! json = [ '{"nonnumeric array": ["str", 5, null],' ...
+%!          '"numeric array": [1, 2, null]}' ];
+%! exp  = struct ('nonnumericArray', {{'str'; 5; []}}, ...
+%!                'numericArray', {[1; 2; NaN]});
+%! obs  = jsondecode (json);
+%! assert (isequaln (obs, exp));
+
+%% Check decoding of objects inside an object & makeValidName (from JSONio)
+%!testif HAVE_RAPIDJSON
+%! json = '{"object": {"  field 1   ": 1, "field-   2": 2, "3field": 3, "": 1}}';
+%! exp  = struct ('object', ...
+%!                struct ('field1', 1, 'field_2', 2, 'x3field', 3, 'x', 1));
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% Check decoding of empty objects, empty arrays, and Inf inside an object
+%!testif HAVE_RAPIDJSON
+%! json = '{"a": Inf, "b": [], "c": {}}';
+%! exp  = struct ('a', Inf, 'b', [], 'c', struct ());
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% Check decoding of string arrays inside an object & makeValidName
+%% extracted from JSONio
+%!testif HAVE_RAPIDJSON
+%! json = '{"%string.array": ["Statistical","Parametric","Mapping"]}';
+%! exp  = struct ('x_string_array', ...
+%!                {{'Statistical'; 'Parametric'; 'Mapping'}});
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% extracted from jsonlab
+%!testif HAVE_RAPIDJSON
+%! json = ['{' , ...
+%!     '"glossary": { ', ...
+%!         '"title": "example glossary",', ...
+%! 		'"GlossDiv": {', ...
+%!             '"title": "S",', ...
+%! 			'"GlossList": {', ...
+%!                 '"GlossEntry": {', ...
+%!                     '"ID": "SGML",', ...
+%! 					'"SortAs": "SGML",', ...
+%! 					'"GlossTerm": "Standard Generalized Markup Language",', ...
+%! 					'"Acronym": "SGML",', ...
+%! 					'"Abbrev": "ISO 8879:1986",', ...
+%! 					'"GlossDef": {', ...
+%!                         '"para": "A meta-markup language, ', ...
+%!                         'used to create markup languages such as DocBook.",', ...
+%! 						'"GlossSeeAlso": ["GML", "XML"]', ...
+%!                     '},', ...
+%! 					'"GlossSee": "markup"', ...
+%!                 '}', ...
+%!             '}', ...
+%!         '}', ...
+%!     '}', ...
+%! '}'];
+%! var1 = struct ('para', ['A meta-markup language, used to create ' ...
+%!                         'markup languages such as DocBook.'], ...
+%!                'GlossSeeAlso', {{'GML'; 'XML'}});
+%! var2 = struct ('ID', 'SGML', 'SortAs', 'SGML', ...
+%!                'GlossTerm', 'Standard Generalized Markup Language', ...
+%!                'Acronym', 'SGML', 'Abbrev', 'ISO 8879:1986', ...
+%!                'GlossDef', var1, 'GlossSee', 'markup');
+%! exp  = struct ('glossary', ...
+%!                struct ('title', 'example glossary', ...
+%!                        'GlossDiv', struct ('title', 'S', ...
+%!                                            'GlossList', ...
+%!                                            struct ('GlossEntry', var2))));
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%%% Test 5: decode Array of JSON objects
+
+%% Arrays with the same field names in the same order (extracted from JSONio)
+%!testif HAVE_RAPIDJSON
+%! json = '{"structarray": [{"a":1,"b":2},{"a":3,"b":4}]}';
+%! exp  = struct ('structarray', struct ('a', {1; 3}, 'b', {2; 4}));
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% Different field names before calling makeValidName, BUT the same after
+%% calling it, resulting in structarray.
+%! json = [ '[', ...
+%!       '{', ...
+%!         '"i*d": 0,', ...
+%!         '"12name": "Osborn"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"i/d": 1,', ...
+%!         '"12name": "Mcdowell"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"i+d": 2,', ...
+%!         '"12name": "Jewel"', ...
+%!       '}', ...
+%!     ']'];
+%! exp  = struct ('i_d', {0; 1; 2}, ...
+%!                'x12name', {'Osborn'; 'Mcdowell'; 'Jewel'});
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% Arrays with the same field names in the same order.
+%% JSON text is generated from json-generator.com
+%!testif HAVE_RAPIDJSON
+%! json = ['[', ...
+%!   '{', ...
+%!     '"x_id": "5ee28980fc9ab3",', ...
+%!     '"index": 0,', ...
+%!     '"guid": "b229d1de-f94a",', ...
+%!     '"latitude": -17.124067,', ...
+%!     '"longitude": -61.161831,', ...
+%!     '"friends": [', ...
+%!       '{', ...
+%!         '"id": 0,', ...
+%!         '"name": "Collins"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id": 1,', ...
+%!         '"name": "Hays"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id": 2,', ...
+%!         '"name": "Griffin"', ...
+%!       '}', ...
+%!     ']', ...
+%!   '},', ...
+%!   '{', ...
+%!     '"x_id": "5ee28980dd7250",', ...
+%!     '"index": 1,', ...
+%!     '"guid": "39cee338-01fb",', ...
+%!     '"latitude": 13.205994,', ...
+%!     '"longitude": -37.276231,', ...
+%!     '"friends": [', ...
+%!       '{', ...
+%!         '"id": 0,', ...
+%!         '"name": "Osborn"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id": 1,', ...
+%!         '"name": "Mcdowell"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id": 2,', ...
+%!         '"name": "Jewel"', ...
+%!       '}', ...
+%!     ']', ...
+%!   '},', ...
+%!   '{', ...
+%!     '"x_id": "5ee289802422ac",', ...
+%!     '"index": 2,', ...
+%!     '"guid": "3db8d55a-663e",', ...
+%!     '"latitude": -35.453456,', ...
+%!     '"longitude": 14.080287,', ...
+%!     '"friends": [', ...
+%!       '{', ...
+%!         '"id": 0,', ...
+%!         '"name": "Socorro"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id": 1,', ...
+%!         '"name": "Darla"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id": 2,', ...
+%!         '"name": "Leanne"', ...
+%!       '}', ...
+%!     ']', ...
+%!   '}', ...
+%! ']'];
+%! var1 = struct ('id', {0; 1; 2}, 'name', {'Collins'; 'Hays'; 'Griffin'});
+%! var2 = struct ('id', {0; 1; 2}, 'name', {'Osborn'; 'Mcdowell'; 'Jewel'});
+%! var3 = struct ('id', {0; 1; 2}, 'name', {'Socorro'; 'Darla'; 'Leanne'});
+%! exp  = struct (...
+%!   'x_id', {'5ee28980fc9ab3'; '5ee28980dd7250'; '5ee289802422ac'}, ...
+%!   'index', {0; 1; 2}, ...
+%!   'guid', {'b229d1de-f94a'; '39cee338-01fb'; '3db8d55a-663e'}, ...
+%!   'latitude', {-17.124067; 13.205994; -35.453456}, ...
+%!   'longitude', {-61.161831; -37.276231; 14.080287}, ...
+%!   'friends', {var1; var2; var3});
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% Arrays with the same field names in different order (extracted from JSONio)
+%% Results in cell array, rather than struct array
+%!testif HAVE_RAPIDJSON
+%! json = '{"cellarray": [{"a":1,"b":2},{"b":3,"a":4}]}';
+%! exp  = struct ('cellarray', {{struct('a', 1, 'b', 2); ...
+%!                               struct('b', 3, 'a', 4)}});
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% Arrays with different field names (extracted from JSONio)
+%!testif HAVE_RAPIDJSON
+%! json = '{"cellarray": [{"a":1,"b":2},{"a":3,"c":4}]}';
+%! exp  = struct ('cellarray', {{struct('a', 1, 'b', 2); ...
+%!                               struct('a', 3, 'c', 4)}});
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% Arrays with different field names and a big test
+%!testif HAVE_RAPIDJSON
+%! json = ['[', ...
+%!   '{', ...
+%!     '"x_id": "5ee28980fc9ab3",', ...
+%!     '"index": 0,', ...
+%!     '"guid": "b229d1de-f94a",', ...
+%!     '"latitude": -17.124067,', ...
+%!     '"longitude": -61.161831,', ...
+%!     '"friends": [', ...
+%!       '{', ...
+%!         '"id": 0,', ...
+%!         '"name": "Collins"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id": 1,', ...
+%!         '"name": "Hays"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id": 2,', ...
+%!         '"name": "Griffin"', ...
+%!       '}', ...
+%!     ']', ...
+%!   '},', ...
+%!   '{"numeric array": ["str", 5, null], "nonnumeric array": [1, 2, null]},', ...
+%!   '{', ...
+%!      '"firstName": "John",', ...
+%!      '"lastName": "Smith",', ...
+%!      '"age": 25,', ...
+%!      '"address":', ...
+%!      '{', ...
+%!          '"streetAddress": "21 2nd Street",', ...
+%!          '"city": "New York",', ...
+%!          '"state": "NY"', ...
+%!      '},', ...
+%!      '"phoneNumber":', ...
+%!          '{', ...
+%!            '"type": "home",', ...
+%!            '"number": "212 555-1234"', ...
+%!          '}', ...
+%!  '}]'];
+%! var1 = struct ('x_id', '5ee28980fc9ab3', 'index', 0, ...
+%!                'guid', 'b229d1de-f94a', 'latitude', -17.124067, ...
+%!                'longitude', -61.161831, ...
+%!                'friends', ...
+%!                struct ('id', {0; 1; 2}, ...
+%!                        'name', {'Collins'; 'Hays'; 'Griffin'}));
+%! var2 = struct ('numericArray', {{'str'; 5; []}}, ...
+%!                'nonnumericArray', {[1; 2; NaN]});
+%! var3 = struct ('firstName', 'John', 'lastName', 'Smith', 'age', 25, ...
+%!                'address', ...
+%!                struct ('streetAddress', '21 2nd Street', ...
+%!                        'city', 'New York', 'state', 'NY'), ...
+%!                'phoneNumber', ...
+%!                struct ('type', 'home', 'number', '212 555-1234'));
+%! exp = {var1; var2; var3};
+%! obs  = jsondecode (json);
+%! assert (isequaln (obs, exp));
+
+%%% Test 6: decode Array of different JSON data types
+
+%!testif HAVE_RAPIDJSON
+%! json = ['[null, true, Inf, 2531.023, "hello there", ', ...
+%!   '{', ...
+%!     '"x_id": "5ee28980dd7250",', ...
+%!     '"index": 1,', ...
+%!     '"guid": "39cee338-01fb",', ...
+%!     '"latitude": 13.205994,', ...
+%!     '"longitude": -37.276231,', ...
+%!     '"friends": [', ...
+%!       '{', ...
+%!         '"id": 0,', ...
+%!         '"name": "Osborn"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id": 1,', ...
+%!         '"name": "Mcdowell"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id": 2,', ...
+%!         '"name": "Jewel"', ...
+%!       '}', ...
+%!     ']', ...
+%!   '}]'];
+%! var =  struct ('x_id', '5ee28980dd7250', 'index', 1, ...
+%!                'guid', '39cee338-01fb', 'latitude', 13.205994, ...
+%!                'longitude', -37.276231,
+%!                'friends', struct ('id', {0; 1; 2}, ...
+%!                                   'name', {'Osborn'; 'Mcdowell'; 'Jewel'}));
+%! exp = {[]; 1; Inf; 2531.023; 'hello there'; var};
+%! obs  = jsondecode (json);
+%! assert (isequaln (obs, exp));
+
+%% Array of arrays
+%!testif HAVE_RAPIDJSON
+%! json = ['[["str", Inf, null], [1, 2, null], ["foo", "bar", ["foo", "bar"]],', ...
+%!   '[[[1, 2], [3, 4]], [[5, 6], [7, 8]]],' , ...
+%!   '[', ...
+%!     '{', ...
+%!       '"x_id": "5ee28980fc9ab3",', ...
+%!       '"index": 0,', ...
+%!       '"guid": "b229d1de-f94a",', ...
+%!       '"latitude": -17.124067,', ...
+%!       '"longitude": -61.161831,', ...
+%!       '"friends": [', ...
+%!         '{', ...
+%!           '"id": 0,', ...
+%!           '"name": "Collins"', ...
+%!         '},', ...
+%!         '{', ...
+%!           '"id": 1,', ...
+%!           '"name": "Hays"', ...
+%!         '},', ...
+%!         '{', ...
+%!           '"id": 2,', ...
+%!           '"name": "Griffin"', ...
+%!         '}', ...
+%!       ']', ...
+%!     '},', ...
+%!     '{"numeric array": ["str", 5, null], "nonnumeric array": [1, 2, null]},', ...
+%!     '{', ...
+%!        '"firstName": "John",', ...
+%!        '"lastName": "Smith",', ...
+%!        '"age": 25,', ...
+%!        '"address":', ...
+%!        '{', ...
+%!            '"streetAddress": "21 2nd Street",', ...
+%!            '"city": "New York",', ...
+%!            '"state": "NY"', ...
+%!        '},', ...
+%!        '"phoneNumber":', ...
+%!            '{', ...
+%!              '"type": "home",', ...
+%!              '"number": "212 555-1234"', ...
+%!            '}', ...
+%!    '}]]'];
+%! var1 = struct ('x_id', '5ee28980fc9ab3', 'index', 0, ...
+%!                'guid', 'b229d1de-f94a', 'latitude', -17.124067, ...
+%!                'longitude', -61.161831, ...
+%!                'friends', struct ('id', {0; 1; 2}, ...
+%!                                   'name', {'Collins'; 'Hays'; 'Griffin'}));
+%! var2 = struct ('numericArray', {{'str'; 5; []}}, ...
+%!                'nonnumericArray', {[1; 2; NaN]});
+%! var3 = struct ('firstName', 'John', 'lastName', 'Smith', 'age', 25, ...
+%!                'address', ...
+%!                struct ('streetAddress', '21 2nd Street', ...
+%!                        'city', 'New York', 'state', 'NY'), ...
+%!                'phoneNumber', ...
+%!                struct ('type', 'home', 'number', '212 555-1234'));
+%! exp = {{'str'; Inf; []}; [1; 2; NaN]; {'foo'; 'bar'; {'foo'; 'bar'}};
+%!        cat(3, [1, 3; 5, 7], [2, 4; 6, 8]); {var1; var2 ;var3}};
+%! obs  = jsondecode (json);
+%! assert (isequaln (obs, exp));
+
+%%% Test 7: Check "ReplacementStyle" and "Prefix" options
+
+%!testif HAVE_RAPIDJSON
+%! json = '{"1a": {"1*a": {"1+*/-a": {"1#a": {}}}}}';
+%! exp  = struct ('n1a', ...
+%!                struct ('n1a', struct ('n1a', struct ('n1a', struct ()))));
+%! obs  = jsondecode (json, "ReplacementStyle", "delete", ...
+%!                          "Prefix", "_", "Prefix", "n");
+%! assert (isequal (obs, exp));
+
+%% Check forwarding of "ReplacementStyle" and "Prefix" options inside arrays
+%!testif HAVE_RAPIDJSON
+%! json = [ '[', ...
+%!       '{', ...
+%!         '"i*d": 0,', ...
+%!         '"12name": "Osborn"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"i*d": 1,', ...
+%!         '"12name": "Mcdowell"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"i*d": 2,', ...
+%!         '"12name": "Jewel"', ...
+%!       '}', ...
+%!     ']'];
+%! exp  = struct ('i0x2Ad', {0; 1; 2}, ...
+%!                'm_12name', {'Osborn'; 'Mcdowell'; 'Jewel'});
+%! obs  = jsondecode (json, "ReplacementStyle", "hex", "Prefix", "m_");
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! json = '{"cell*array": [{"1a":1,"b*1":2},{"1a":3,"b/2":4}]}';
+%! exp  = struct ('cell_array', {{struct('x_1a', 1, 'b_1', 2); ...
+%!                                struct('x_1a', 3, 'b_2', 4)}});
+%! obs  = jsondecode (json, "ReplacementStyle", "underscore", "Prefix", "x_");
+%! assert (isequal (obs, exp));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/json/jsonencode_BIST.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,658 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Unit tests for jsonencode()
+%%
+%% Code in libinterp/corefcn/jsonencode.cc
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Note: This script is intended to also run under Matlab to verify
+%%       compatibility.  Preserve Matlab-formatting when making changes.
+
+%% Some tests here are just the reverse of tests in jsondecode with
+%% some modifications.
+
+%%% Test 1: Encode logical and numeric scalars, NaN, NA, and Inf
+
+%!testif HAVE_RAPIDJSON
+%! assert (isequal (jsonencode (logical (1)), 'true'));
+%! assert (isequal (jsonencode (logical (0)), 'false'));
+%! assert (isequal (jsonencode (50.025), '50.025'));
+%! assert (isequal (jsonencode (NaN), 'null'));
+%! assert (isequal (jsonencode (NA), 'null'));    % Octave-only test
+%! assert (isequal (jsonencode (Inf), 'null'));
+%! assert (isequal (jsonencode (-Inf), 'null'));
+
+%% Customized encoding of Nan, NA, Inf, -Inf
+%!testif HAVE_RAPIDJSON
+%! assert (isequal (jsonencode (NaN, 'ConvertInfAndNaN', true), 'null'));
+%! % Octave-only test for NA
+%! assert (isequal (jsonencode (NA, 'ConvertInfAndNaN', true), 'null'));
+%! assert (isequal (jsonencode (Inf, 'ConvertInfAndNaN', true), 'null'));
+%! assert (isequal (jsonencode (-Inf, 'ConvertInfAndNaN', true), 'null'));
+
+%!testif HAVE_RAPIDJSON
+%! assert (isequal (jsonencode (NaN, 'ConvertInfAndNaN', false), 'NaN'));
+%! % Octave-only test for NA
+%! assert (isequal (jsonencode (NA, 'ConvertInfAndNaN', false), 'NaN'));
+%! assert (isequal (jsonencode (Inf, 'ConvertInfAndNaN', false), 'Infinity'));
+%! assert (isequal (jsonencode (-Inf, 'ConvertInfAndNaN', false), '-Infinity'));
+
+%%% Test 2: encode character vectors and arrays
+
+%!testif HAVE_RAPIDJSON
+%! assert (isequal (jsonencode (''), '""'));
+%! assert (isequal (jsonencode ('hello there'), '"hello there"'));
+%! assert (isequal (jsonencode (['foo'; 'bar']), '["foo","bar"]'));
+%! assert (isequal (jsonencode (['foo', 'bar'; 'foo', 'bar']), ...
+%!                  '["foobar","foobar"]'));
+
+%% Escape characters inside single-quoted and double-quoted strings
+%!testif HAVE_RAPIDJSON
+%! assert (isequal (jsonencode ('\0\a\b\t\n\v\f\r'), ...
+%!                              '"\\0\\a\\b\\t\\n\\v\\f\\r"'));
+%! % FIXME: Matlab produces a double-escaped string as above.
+%! assert (isequal (jsonencode ("\a\b\t\n\v\f\r"), ...
+%!                              '"\u0007\b\t\n\u000B\f\r"'));
+
+%!testif HAVE_RAPIDJSON
+%! data = [[['foo'; 'bar']; ['foo'; 'bar']], [['foo'; 'bar']; ['foo'; 'bar']]];
+%! exp  = '["foofoo","barbar","foofoo","barbar"]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = cat (3, ['a', 'b'; 'c', 'd'], ['e', 'f'; 'g', 'h']);
+%! exp  = '[["ab","ef"],["cd","gh"]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% Try different dimensions for the array
+%!testif HAVE_RAPIDJSON
+%! data = cat (3, ['a', 'b'; 'c', 'd'; '1', '2'], ...
+%!                ['e', 'f'; 'g', 'h'; '3', '4']);
+%! exp  = '[["ab","ef"],["cd","gh"],["12","34"]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% Try higher dimensions for the array
+%!testif HAVE_RAPIDJSON
+%! charmat1 = cat (3, ['1', '3'; '5', '7'; '9', 'e'; 'f', 'g'], ...
+%!                    ['2', '4'; '6', '8'; 'a', 'b'; 'c', 'd']);
+%! charmat2 = cat (3, ['1', '3'; '5', '7'; '9', 'e'; 'f', 'g'], ...
+%!                    ['2', '4'; '6', '8'; 'a', 'b'; 'c', 'd']);
+%! data = cat (4, charmat1, charmat2);
+%! exp  = [ '[[["13","13"],["24","24"]],[["57","57"],["68","68"]],', ...
+%!          '[["9e","9e"],["ab","ab"]],[["fg","fg"],["cd","cd"]]]' ];
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% Try different dimensions for an array with one of its dimensions equals one
+%!testif HAVE_RAPIDJSON
+%! data = cat (4, ['a'; 'b'], ['c'; 'd']);
+%! exp  = '[[["a","c"]],[["b","d"]]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% High dimension, but still a vector, is reduced to a vector
+%!testif HAVE_RAPIDJSON
+%! data = cat (8, ['a'], ['c']);
+%! exp  = '"ac"';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = cat (8, ['a'; 'b'; '1'], ['c'; 'd'; '2']);
+%! exp  = '[[[[[[["a","c"]]]]]],[[[[[["b","d"]]]]]],[[[[[["1","2"]]]]]]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%%% Test 3: encode numeric and logical arrays (with NaN and Inf)
+
+%% Test simple vectors
+%!testif HAVE_RAPIDJSON
+%! assert (isequal (jsonencode ([]), '[]'));
+%! assert (isequal (jsonencode ([1, 2, 3, 4]), '[1,2,3,4]'));
+%! assert (isequal (jsonencode ([true; false; true]), '[true,false,true]'));
+
+%% Test arrays
+%!testif HAVE_RAPIDJSON
+%! data = [1, NaN; 3, 4];
+%! exp  = '[[1,null],[3,4]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = cat (3, [NaN, 3; 5, Inf], [2, 4; -Inf, 8]);
+%! exp  = '[[[null,2],[3,4]],[[5,null],[null,8]]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% Customized encoding of Nan, Inf, -Inf
+%!testif HAVE_RAPIDJSON
+%! data = cat (3, [1, NaN; 5, 7], [2, Inf; 6, -Inf]);
+%! exp  = '[[[1,2],[NaN,Infinity]],[[5,6],[7,-Infinity]]]';
+%! obs  = jsonencode (data, 'ConvertInfAndNaN', false);
+%! assert (isequal (obs, exp));
+
+%% Try different dimensions for the array
+%!testif HAVE_RAPIDJSON
+%! data = cat (3, [1, 3; 5, 7], [2, 4; 6, 8], [-1, NaN; Inf, -Inf]);
+%! exp  = '[[[1,2,-1],[3,4,NaN]],[[5,6,Infinity],[7,8,-Infinity]]]';
+%! obs  = jsonencode (data, 'ConvertInfAndNaN', false);
+%! assert (isequal (obs, exp));
+
+%% Try different dimensions for the array with one of its dimensions equals one
+%!testif HAVE_RAPIDJSON
+%! data = cat (3, [1; 7; 11], [4; 8; 12]);
+%! exp  = '[[[1,4]],[[7,8]],[[11,12]]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! array1 = cat (3, [5, 7], [2, 4]);
+%! array2 = cat (3, [-1, -3], [-2, -4]);
+%! data = cat (4, array1, array2);
+%! exp  = '[[[[5,-1],[2,-2]],[[7,-3],[4,-4]]]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = cat (4, [1, 3; 5, 7], [-1, -3; -5, -7]);
+%! exp  = '[[[[1,-1]],[[3,-3]]],[[[5,-5]],[[7,-7]]]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% High-dimension vector is reduced to just a vector
+%!testif HAVE_RAPIDJSON
+%! data = ones ([1, 1, 1, 1, 1, 6]);
+%! exp  = '[1,1,1,1,1,1]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = ones ([1, 2, 2, 2, 2]);
+%! exp  = '[[[[[1,1],[1,1]],[[1,1],[1,1]]],[[[1,1],[1,1]],[[1,1],[1,1]]]]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = ones ([1, 2, 2, 1, 2]);
+%! exp  = '[[[[[1,1]],[[1,1]]],[[[1,1]],[[1,1]]]]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = ones ([1, 2, 1, 2, 1, 2]);
+%! exp  = '[[[[[[1,1]],[[1,1]]]],[[[[1,1]],[[1,1]]]]]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = ones ([1, 1, 2, 1, 2, 1, 2]);
+%! exp  = '[[[[[[[1,1]],[[1,1]]]],[[[[1,1]],[[1,1]]]]]]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = ones ([1, 2, 2, 1, 1, 2]);
+%! exp  = '[[[[[[1,1]]],[[[1,1]]]],[[[[1,1]]],[[[1,1]]]]]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = ones ([1, 2, 1, 3, 1, 1, 1, 2]);
+%! exp  = ['[[[[[[[[1,1]]]],[[[[1,1]]]],[[[[1,1]]]]]],[[[[[[1,1]]]],', ...
+%!         '[[[[1,1]]]],[[[[1,1]]]]]]]]'];
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = ones ([1, 1, 1, 1, 2, 1, 1, 1, 2]);
+%! exp  = '[[[[[[[[[1,1]]]],[[[[1,1]]]]]]]]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = ones ([1, 3, 2, 1, 1, 2, 1, 2, 2]);
+%! exp  = ['[[[[[[[[[1,1],[1,1]]],[[[1,1],[1,1]]]]]],[[[[[[1,1],', ...
+%!         '[1,1]]],[[[1,1],[1,1]]]]]]],[[[[[[[1,1],[1,1]]],[[[1,', ...
+%!         '1],[1,1]]]]]],[[[[[[1,1],[1,1]]],[[[1,1],[1,1]]]]]]],', ...
+%!         '[[[[[[[1,1],[1,1]]],[[[1,1],[1,1]]]]]],[[[[[[1,1],[1,', ...
+%!         '1]]],[[[1,1],[1,1]]]]]]]]]'];
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = ones ([1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 3, 1, 1, 1, 1, 1, 1, 1, 2]);
+%! exp  =  ['[[[[[[[[[[[[[[[[[[[[1,1]]]]]]]],[[[[[[[[1,1]]]]]]]],', ...
+%!          '[[[[[[[[1,1]]]]]]]]],[[[[[[[[[1,1]]]]]]]],[[[[[[[[1,1]]]]]', ...
+%!          ']]],[[[[[[[[1,1]]]]]]]]]],[[[[[[[[[[1,1]]]]]]]],[[[[[[[[1,1]', ...
+%!          ']]]]]]],[[[[[[[[1,1]]]]]]]]],[[[[[[[[[1,1]]]]]]]],[[[[[[', ...
+%!          '[[1,1]]]]]]]],[[[[[[[[1,1]]]]]]]]]]]]],[[[[[[[[[[[[[1,1]', ...
+%!          ']]]]]]],[[[[[[[[1,1]]]]]]]],[[[[[[[[1,1]]]]]]]]],[[[[[[[[', ...
+%!          '[1,1]]]]]]]],[[[[[[[[1,1]]]]]]]],[[[[[[[[1,1]]]]]]]]]],[[[', ...
+%!          '[[[[[[[1,1]]]]]]]],[[[[[[[[1,1]]]]]]]],[[[[[[[[1,1]]]]]]]]],', ...
+%!          '[[[[[[[[[1,1]]]]]]]],[[[[[[[[1,1]]]]]]]],[[[[[[[[1,1]]', ...
+%!          ']]]]]]]]]]]]]]]]]]'];
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% Try higher dimensions for the array
+%!testif HAVE_RAPIDJSON
+%! var1 = cat (3, [1, 3; 5, 7; 9, 11; 13, 15], [2, 4; 6, 8; 10, 12; 14, 16]);
+%! var2 = cat (3, [-1, -3; -5, -7; -9, -11; -13, -15], ...
+%!                [-2, -4; -6, -8; -10, -12; -14, -16]);
+%! data = cat (4, var1, var2);
+%! exp  = ['[[[[1,-1],[2,-2]],[[3,-3],[4,-4]]],[[[5,-5],[6,-6]],[[7,-7],', ...
+%!         '[8,-8]]],[[[9,-9],[10,-10]],[[11,-11],[12,-12]]],', ...
+%!         '[[[13,-13],[14,-14]],[[15,-15],[16,-16]]]]'];
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% Try logical array (tests above were all with numeric data)
+
+%% 2-D logical array
+%!testif HAVE_RAPIDJSON
+%! data = [true, false; true, false; true, false];
+%! exp  = '[[true,false],[true,false],[true,false]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% N-D logical array
+%!testif HAVE_RAPIDJSON <59198>
+%! data = true (2,2,2);
+%! data(1,1,2) = false;
+%! exp  = '[[[true,false],[true,true]],[[true,true],[true,true]]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%%% Test 4: encode containers.Map
+
+%% KeyType must be char to encode objects of containers.Map
+%!testif HAVE_RAPIDJSON
+%! assert (isequal (jsonencode (containers.Map ('1', [1, 2, 3])), ...
+%!                  '{"1":[1,2,3]}'));
+
+%!testif HAVE_RAPIDJSON
+%! data = containers.Map ({'foo'; 'bar'; 'baz'}, [1, 2, 3]);
+%! exp  = '{"bar":2,"baz":3,"foo":1}';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = containers.Map ({'foo'; 'bar'; 'baz'}, ...
+%!                        {{1, 'hello', NaN}, true, [2, 3, 4]});
+%! exp  = '{"bar":true,"baz":[2,3,4],"foo":[1,"hello",NaN]}';
+%! obs  = jsonencode (data, 'ConvertInfAndNaN', false);
+%! assert (isequal (obs, exp));
+
+%%% Test 5: encode scalar structs
+
+%% Check the encoding of Boolean, Number, and String values inside a struct
+%!testif HAVE_RAPIDJSON
+%! data = struct ('number', 3.14, 'string', 'foobar', 'boolean', false);
+%! exp  = '{"number":3.14,"string":"foobar","boolean":false}';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% Check the encoding of NaN, NA, Inf, and -Inf values inside a struct
+%!testif HAVE_RAPIDJSON
+%! % Octave-only test because of NA value
+%! data = struct ('numericArray', [7, NaN, NA, Inf, -Inf]);
+%! exp  = '{"numericArray":[7,null,null,null,null]}';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% Customized encoding of Nan, NA, Inf, -Inf
+%!testif HAVE_RAPIDJSON
+%! data = struct ('numericArray', [7, NaN, NA, Inf, -Inf]);
+%! exp  = '{"numericArray":[7,NaN,NaN,Infinity,-Infinity]}';
+%! obs  = jsonencode (data, 'ConvertInfAndNaN', false);
+%! assert (isequal (obs, exp));
+
+%% Check the encoding of structs inside a struct
+%!testif HAVE_RAPIDJSON
+%! data = struct ('object', struct ('field1', 1, 'field2', 2, 'field3', 3));
+%! exp  = '{"object":{"field1":1,"field2":2,"field3":3}}';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% Check the encoding of empty structs and empty arrays inside a struct
+%!testif HAVE_RAPIDJSON
+%! data = struct ('a', Inf, 'b', [], 'c', struct ());
+%! exp  = '{"a":null,"b":[],"c":{}}';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% a big test
+%!testif HAVE_RAPIDJSON
+%! var1 = struct ('para', ['A meta-markup language, used to create ' ...
+%!                         'markup languages such as DocBook.'], ...
+%!                'GlossSeeAlso', {{'GML'; 'XML'}});
+%! var2 = struct ('ID', 'SGML', 'SortAs', 'SGML', ...
+%!                'GlossTerm', 'Standard Generalized Markup Language', ...
+%!                'Acronym', 'SGML', 'Abbrev', 'ISO 8879:1986', ...
+%!                'GlossDef', var1, 'GlossSee', 'markup');
+%! data  = struct ('glossary', ...
+%!                struct ('title', 'example glossary', ...
+%!                        'GlossDiv', struct ('title', 'S', ...
+%!                                            'GlossList', ...
+%!                                            struct ('GlossEntry', var2))));
+%! exp = ['{' , ...
+%!     '"glossary":{', ...
+%!         '"title":"example glossary",', ...
+%! 		'"GlossDiv":{', ...
+%!             '"title":"S",', ...
+%! 			'"GlossList":{', ...
+%!                 '"GlossEntry":{', ...
+%!                     '"ID":"SGML",', ...
+%! 					'"SortAs":"SGML",', ...
+%! 					'"GlossTerm":"Standard Generalized Markup Language",', ...
+%! 					'"Acronym":"SGML",', ...
+%! 					'"Abbrev":"ISO 8879:1986",', ...
+%! 					'"GlossDef":{', ...
+%!                         '"para":"A meta-markup language, ', ...
+%!                         'used to create markup languages such as DocBook.",', ...
+%! 						'"GlossSeeAlso":["GML","XML"]', ...
+%!                     '},', ...
+%! 					'"GlossSee":"markup"', ...
+%!                 '}', ...
+%!             '}', ...
+%!         '}', ...
+%!     '}', ...
+%! '}'];
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%%% Test 6: Encode struct arrays
+
+%!testif HAVE_RAPIDJSON
+%! data = struct ('structarray', struct ('a', {1; 3}, 'b', {2; 4}));
+%! exp  = '{"structarray":[{"a":1,"b":2},{"a":3,"b":4}]}';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% another big Test
+%!testif HAVE_RAPIDJSON
+%! var1 = struct ('id', {0; 1; 2}, 'name', {'Collins'; 'Hays'; 'Griffin'});
+%! var2 = struct ('id', {0; 1; 2}, 'name', {'Osborn'; 'Mcdowell'; 'Jewel'});
+%! var3 = struct ('id', {0; 1; 2}, 'name', {'Socorro'; 'Darla'; 'Leanne'});
+%! data = struct (...
+%!   'x_id', {'5ee28980fc9ab3'; '5ee28980dd7250'; '5ee289802422ac'}, ...
+%!   'index', {0; 1; 2}, ...
+%!   'guid', {'b229d1de-f94a'; '39cee338-01fb'; '3db8d55a-663e'}, ...
+%!   'latitude', {-17.124067; 13.205994; -35.453456}, ...
+%!   'longitude', {-61.161831; -37.276231; 14.080287}, ...
+%!   'friends', {var1; var2; var3});
+%! exp  = ['[', ...
+%!   '{', ...
+%!     '"x_id":"5ee28980fc9ab3",', ...
+%!     '"index":0,', ...
+%!     '"guid":"b229d1de-f94a",', ...
+%!     '"latitude":-17.124067,', ...
+%!     '"longitude":-61.161831,', ...
+%!     '"friends":[', ...
+%!       '{', ...
+%!         '"id":0,', ...
+%!         '"name":"Collins"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id":1,', ...
+%!         '"name":"Hays"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id":2,', ...
+%!         '"name":"Griffin"', ...
+%!       '}', ...
+%!     ']', ...
+%!   '},', ...
+%!   '{', ...
+%!     '"x_id":"5ee28980dd7250",', ...
+%!     '"index":1,', ...
+%!     '"guid":"39cee338-01fb",', ...
+%!     '"latitude":13.205994,', ...
+%!     '"longitude":-37.276231,', ...
+%!     '"friends":[', ...
+%!       '{', ...
+%!         '"id":0,', ...
+%!         '"name":"Osborn"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id":1,', ...
+%!         '"name":"Mcdowell"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id":2,', ...
+%!         '"name":"Jewel"', ...
+%!       '}', ...
+%!     ']', ...
+%!   '},', ...
+%!   '{', ...
+%!     '"x_id":"5ee289802422ac",', ...
+%!     '"index":2,', ...
+%!     '"guid":"3db8d55a-663e",', ...
+%!     '"latitude":-35.453456,', ...
+%!     '"longitude":14.080287,', ...
+%!     '"friends":[', ...
+%!       '{', ...
+%!         '"id":0,', ...
+%!         '"name":"Socorro"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id":1,', ...
+%!         '"name":"Darla"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id":2,', ...
+%!         '"name":"Leanne"', ...
+%!       '}', ...
+%!     ']', ...
+%!   '}', ...
+%! ']'];
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%%% Test 7: encode cell arrays
+
+%!testif HAVE_RAPIDJSON
+%! assert (isequal (jsonencode ({}), '[]'));
+%! assert (isequal (jsonencode ({5}), '[5]'));
+%! assert (isequal (jsonencode ({'hello there'}), '["hello there"]'));
+
+%% Logical cell arrays
+%!testif HAVE_RAPIDJSON
+%! data = {'true', 'true'; 'false', 'true'};
+%! exp  = '["true","false","true","true"]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% Cell array of character vectors
+%!testif HAVE_RAPIDJSON
+%! data = {'foo'; 'bar'; {'foo'; 'bar'}};
+%! exp  = '["foo","bar",["foo","bar"]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% cell array of structs & a big test
+%!testif HAVE_RAPIDJSON
+%! var1 = struct ('x_id', '5ee28980fc9ab3', 'index', 0, ...
+%!                'guid', 'b229d1de-f94a', 'latitude', -17.124067, ...
+%!                'longitude', -61.161831, ...
+%!                'friends', struct ('id', {0; 1; 2}, ...
+%!                                   'name', {'Collins'; 'Hays'; 'Griffin'}));
+%! var2 = struct ('numericArray', {{'str'; 5; []}}, ...
+%!                'nonnumericArray', {[1; 2; NaN]});
+%! var3 = struct ('firstName', 'John', 'lastName', 'Smith', 'age', 25, ...
+%!                'address', ...
+%!                struct ('streetAddress', '21 2nd Street', ...
+%!                        'city', 'New York', 'state', 'NY'), ...
+%!                'phoneNumber', ...
+%!                struct ('type', 'home', 'number', '212 555-1234'));
+%! data = {var1; var2; var3};
+%! exp  = ['[', ...
+%!   '{', ...
+%!     '"x_id":"5ee28980fc9ab3",', ...
+%!     '"index":0,', ...
+%!     '"guid":"b229d1de-f94a",', ...
+%!     '"latitude":-17.124067,', ...
+%!     '"longitude":-61.161831,', ...
+%!     '"friends":[', ...
+%!       '{', ...
+%!         '"id":0,', ...
+%!         '"name":"Collins"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id":1,', ...
+%!         '"name":"Hays"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id":2,', ...
+%!         '"name":"Griffin"', ...
+%!       '}', ...
+%!     ']', ...
+%!   '},', ...
+%!   '{"numericArray":["str",5,[]],"nonnumericArray":[1,2,null]},', ...
+%!   '{', ...
+%!      '"firstName":"John",', ...
+%!      '"lastName":"Smith",', ...
+%!      '"age":25,', ...
+%!      '"address":', ...
+%!      '{', ...
+%!          '"streetAddress":"21 2nd Street",', ...
+%!          '"city":"New York",', ...
+%!          '"state":"NY"', ...
+%!      '},', ...
+%!      '"phoneNumber":', ...
+%!          '{', ...
+%!            '"type":"home",', ...
+%!            '"number":"212 555-1234"', ...
+%!          '}', ...
+%!  '}]'];
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% cell array of diferrent types & Customized encoding of Nan, Inf, -Inf
+%!testif HAVE_RAPIDJSON
+%! var =  struct ('x_id', '5ee28980dd7250', 'index', 1, ...
+%!                'guid', '39cee338-01fb', 'latitude', 13.205994, ...
+%!                'longitude', -37.276231,
+%!                'friends', struct ('id', {0; 1; 2}, ...
+%!                                   'name', {'Osborn'; 'Mcdowell'; 'Jewel'}));
+%! data = {NaN; true; Inf; 2531.023; 'hello there'; var};
+%! exp  = ['[NaN,true,Infinity,2531.023,"hello there",', ...
+%!   '{', ...
+%!     '"x_id":"5ee28980dd7250",', ...
+%!     '"index":1,', ...
+%!     '"guid":"39cee338-01fb",', ...
+%!     '"latitude":13.205994,', ...
+%!     '"longitude":-37.276231,', ...
+%!     '"friends":[', ...
+%!       '{', ...
+%!         '"id":0,', ...
+%!         '"name":"Osborn"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id":1,', ...
+%!         '"name":"Mcdowell"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id":2,', ...
+%!         '"name":"Jewel"', ...
+%!       '}', ...
+%!     ']', ...
+%!   '}]'];
+%! obs  = jsonencode (data, 'ConvertInfAndNaN', false);
+%! assert (isequal (obs, exp));
+
+%% a big example
+%!testif HAVE_RAPIDJSON
+%! var1 = struct ('x_id', '5ee28980fc9ab3', 'index', 0, ...
+%!                'guid', 'b229d1de-f94a', 'latitude', -17.124067, ...
+%!                'longitude', -61.161831, ...
+%!                'friends', struct ('id', {0; 1; 2}, ...
+%!                                   'name', {'Collins'; 'Hays'; 'Griffin'}));
+%! var2 = struct ('numericArray', {{'str'; 5; -Inf}}, ...
+%!                'nonnumericArray', {[1; 2; NaN]});
+%! var3 = struct ('firstName', 'John', 'lastName', 'Smith', 'age', 25, ...
+%!                'address', ...
+%!                struct ('streetAddress', '21 2nd Street', ...
+%!                        'city', 'New York', 'state', 'NY'), ...
+%!                'phoneNumber', ...
+%!                struct ('type', 'home', 'number', '212 555-1234'));
+%! data = {{'str'; Inf; {}}; [1; 2; NaN]; {'foo'; 'bar'; {'foo'; 'bar'}};
+%!        cat(3, [1, 3; 5, 7], [2, 4; 6, 8]); {var1; var2 ;var3}};
+%! exp  = ['[["str",null,[]],[1,2,null],["foo","bar",["foo","bar"]],', ...
+%!   '[[[1,2],[3,4]],[[5,6],[7,8]]],' , ...
+%!   '[', ...
+%!     '{', ...
+%!       '"x_id":"5ee28980fc9ab3",', ...
+%!       '"index":0,', ...
+%!       '"guid":"b229d1de-f94a",', ...
+%!       '"latitude":-17.124067,', ...
+%!       '"longitude":-61.161831,', ...
+%!       '"friends":[', ...
+%!         '{', ...
+%!           '"id":0,', ...
+%!           '"name":"Collins"', ...
+%!         '},', ...
+%!         '{', ...
+%!           '"id":1,', ...
+%!           '"name":"Hays"', ...
+%!         '},', ...
+%!         '{', ...
+%!           '"id":2,', ...
+%!           '"name":"Griffin"', ...
+%!         '}', ...
+%!       ']', ...
+%!     '},', ...
+%!     '{"numericArray":["str",5,null],"nonnumericArray":[1,2,null]},', ...
+%!     '{', ...
+%!        '"firstName":"John",', ...
+%!        '"lastName":"Smith",', ...
+%!        '"age":25,', ...
+%!        '"address":', ...
+%!        '{', ...
+%!            '"streetAddress":"21 2nd Street",', ...
+%!            '"city":"New York",', ...
+%!            '"state":"NY"', ...
+%!        '},', ...
+%!        '"phoneNumber":', ...
+%!            '{', ...
+%!              '"type":"home",', ...
+%!              '"number":"212 555-1234"', ...
+%!            '}', ...
+%!    '}]]'];
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% Just basic tests to ensure option "PrettyWriter" is functional. 
+%!testif HAVE_RAPIDJSON_PRETTYWRITER
+%! data = {'Hello'; 'World!'};
+%! exp  = do_string_escapes ([ '[\n', ...
+%!                             '    "Hello",\n', ...
+%!                             '    "World!"\n', ...
+%!                             ']' ]);
+%! obs  = jsonencode (data, 'PrettyWriter', true);
+%! assert (isequal (obs, exp));
+%!
+%! exp  = '["Hello","World!"]';
+%! obs  = jsonencode (data, 'PrettyWriter', false);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON_PRETTYWRITER
+%! data = [1, 2; 3, 4];
+%! exp  = do_string_escapes ([ ...
+%! '[\n'                       ...
+%! '    [\n'                   ...
+%! '        1,\n'              ...
+%! '        2\n'               ...
+%! '    ],\n'                  ...
+%! '    [\n'                   ...
+%! '        3,\n'              ...
+%! '        4\n'               ...
+%! '    ]\n'                   ...
+%! ']' ]);
+%! obs  = jsonencode (data, 'PrettyWriter', true);
+%! assert (isequal (obs, exp));
+%!
+%! exp  = '[[1,2],[3,4]]';
+%! obs  = jsonencode (data, 'PrettyWriter', false);
+%! assert (isequal (obs, exp));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/json/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,5 @@
+json_TEST_FILES = \
+  %reldir%/jsondecode_BIST.tst \
+  %reldir%/jsonencode_BIST.tst
+
+TEST_FILES += $(json_TEST_FILES)
--- a/test/line-continue.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/line-continue.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -61,7 +61,7 @@
 %!
 %!assert (f (), 1)
 
-# String continuation using '\'
+## String continuation using '\'
 %!assert (["abc\
 %! def"], "abc def")
 
--- a/test/mex/bug-51725.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/mex/bug-51725.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -24,4 +24,5 @@
 ########################################################################
 
 %!assert (bug_51725 (), [])
+## Note: ';' is required to suppress output
 %!error <element number 2 undefined in return list> [x,y,z] = bug_51725 ();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/mex/mexnumtst.c	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,91 @@
+#include "mex.h"
+
+// To be called with
+//
+//   single array
+//   complex single array
+//   double array
+//   complex double array
+//
+// Will return arrays of the same type, but created internally to test
+// the mxArray -> octave_value conversion
+
+void
+mexFunction (int nlhs, mxArray *plhs[],
+             int nrhs, const mxArray *prhs[])
+{
+  if (nrhs != 4 || nlhs != 4)
+    mexErrMsgTxt ("invalid arguments");
+
+  const mxArray *sngl_ra = prhs[0];
+  const mxArray *cplx_sngl_ra = prhs[1];
+  const mxArray *dble_ra = prhs[2];
+  const mxArray *cplx_dble_ra = prhs[3];
+
+#if MX_HAS_INTERLEAVED_COMPLEX
+
+  mxSingle *sngl_data = mxGetSingles (sngl_ra);
+  size_t sngl_data_nr = mxGetM (sngl_ra);
+  size_t sngl_data_nc = mxGetN (sngl_ra);
+
+  plhs[0] = mxCreateNumericMatrix (sngl_data_nr, sngl_data_nc, mxSINGLE_CLASS, mxREAL);
+  mxSetSingles (plhs[0], sngl_data);
+
+  mxComplexSingle *cplx_sngl_data = mxGetComplexSingles (cplx_sngl_ra);
+  size_t cplx_sngl_data_nr = mxGetM (cplx_sngl_ra);
+  size_t cplx_sngl_data_nc = mxGetN (cplx_sngl_ra);
+
+  plhs[1] = mxCreateNumericMatrix (cplx_sngl_data_nr, cplx_sngl_data_nc, mxSINGLE_CLASS, mxCOMPLEX);
+  mxSetComplexSingles (plhs[1], cplx_sngl_data);
+
+  mxDouble *dble_data = mxGetDoubles (dble_ra);
+  size_t dble_data_nr = mxGetM (dble_ra);
+  size_t dble_data_nc = mxGetN (dble_ra);
+
+  plhs[2] = mxCreateNumericMatrix (dble_data_nr, dble_data_nc, mxDOUBLE_CLASS, mxREAL);
+  mxSetDoubles (plhs[2], dble_data);
+
+  mxComplexDouble *cplx_dble_data = mxGetComplexDoubles (cplx_dble_ra);
+  size_t cplx_dble_data_nr = mxGetM (cplx_dble_ra);
+  size_t cplx_dble_data_nc = mxGetN (cplx_dble_ra);
+
+  plhs[3] = mxCreateNumericMatrix (cplx_dble_data_nr, cplx_dble_data_nc, mxDOUBLE_CLASS, mxCOMPLEX);
+  mxSetComplexDoubles (plhs[3], cplx_dble_data);
+
+#else
+
+  mxSingle *sngl_data = (mxSingle *) mxGetData (sngl_ra);
+  size_t sngl_data_nr = mxGetM (sngl_ra);
+  size_t sngl_data_nc = mxGetN (sngl_ra);
+
+  mxSingle *cplx_sngl_data_real = (mxSingle *) mxGetData (cplx_sngl_ra);
+  mxSingle *cplx_sngl_data_imag = (mxSingle *) mxGetImagData (cplx_sngl_ra);
+  size_t cplx_sngl_data_nr = mxGetM (cplx_sngl_ra);
+  size_t cplx_sngl_data_nc = mxGetN (cplx_sngl_ra);
+
+  mxDouble *dble_data = (mxDouble *) mxGetData (dble_ra);
+  size_t dble_data_nr = mxGetM (dble_ra);
+  size_t dble_data_nc = mxGetN (dble_ra);
+
+  mxDouble *cplx_dble_data_real = (mxDouble *) mxGetData (cplx_dble_ra);
+  mxDouble *cplx_dble_data_imag = (mxDouble *) mxGetImagData (cplx_dble_ra);
+  size_t cplx_dble_data_nr = mxGetM (cplx_dble_ra);
+  size_t cplx_dble_data_nc = mxGetN (cplx_dble_ra);
+
+  plhs[0] = mxCreateNumericMatrix (sngl_data_nr, sngl_data_nc, mxSINGLE_CLASS, mxREAL);
+  mxSetData (plhs[0], sngl_data);
+
+  plhs[1] = mxCreateNumericMatrix (cplx_sngl_data_nr, cplx_sngl_data_nc, mxSINGLE_CLASS, mxCOMPLEX);
+  mxSetData (plhs[1], cplx_sngl_data_real);
+  mxSetImagData (plhs[1], cplx_sngl_data_imag);
+
+  plhs[2] = mxCreateNumericMatrix (dble_data_nr, dble_data_nc, mxDOUBLE_CLASS, mxREAL);
+  mxSetData (plhs[2], dble_data);
+
+  plhs[3] = mxCreateNumericMatrix (cplx_dble_data_nr, cplx_dble_data_nc, mxDOUBLE_CLASS, mxCOMPLEX);
+  mxSetData (plhs[3], cplx_dble_data_real);
+  mxSetImagData (plhs[3], cplx_dble_data_imag);
+
+#endif
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/mex/mexnumtst.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -0,0 +1,11 @@
+%!test
+%! s = rand (3, 4, "single");
+%! sc = s + i * rand (3, 4, "single");
+%! d = rand (3, 4, "double");
+%! dc = d + i * rand (3, 4, "double");
+%!
+%! [sx, scx, dx, dcx] = mexnumtst (s, sc, d, dc);
+%! assert (s, sx)
+%! assert (sc, scx)
+%! assert (d, dx)
+%! assert (dc, dcx)
--- a/test/mex/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/mex/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -1,11 +1,13 @@
 mex_TEST_FILES = \
   %reldir%/bug-54096.tst \
   %reldir%/bug-51725.tst \
+  %reldir%/mexnumtst.tst \
   $(MEX_TEST_SRC)
 
 MEX_TEST_SRC = \
   %reldir%/bug_54096.c \
-  %reldir%/bug_51725.c
+  %reldir%/bug_51725.c \
+  %reldir%/mexnumtst.c
 
 MEX_TEST_FUNCTIONS = $(MEX_TEST_SRC:%.c=%.mex)
 
--- a/test/mk-conv-tst.sh	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/mk-conv-tst.sh	Thu Nov 19 13:08:00 2020 -0800
@@ -28,7 +28,7 @@
 cat <<EOF
 ## !!! DO NOT EDIT !!!
 ## THIS IS AN AUTOMATICALLY GENERATED FILE
-## modify build-conv-tests.sh to generate the tests you need.
+## modify mk-conv-tst.sh to generate the tests you need.
 
 
 %!shared r,dq,sq,b,bm,dm,cdm,fdm,fcdm,pm,sm,sbm,scm,s,m,cs,cm,fs,fm,fcs,fcm,i8s,i16s,i32s,i64s,i8m,i16m,i32m,i64m,ui8s,ui16s,ui32s,ui64s,ui8m,ui16m,ui32m,ui64m
@@ -71,7 +71,12 @@
 %! ui32m = uint32 (rand (5) * 10);
 %! ui64m = uint64 (rand (5) * 10);
 %!
-%!assert (typeinfo (r), "range")
+%!test
+%! if (disable_range ())
+%!   assert (typeinfo (r), "matrix")
+%! else
+%!   assert (typeinfo (r), "range")
+%! endif
 %!assert (typeinfo (dq), "string")
 %!assert (typeinfo (sq), "sq_string")
 %!assert (typeinfo (b), "bool")
--- a/test/mk-sparse-tst.sh	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/mk-sparse-tst.sh	Thu Nov 19 13:08:00 2020 -0800
@@ -216,7 +216,7 @@
 %!assert (nnz (sparse (1,1,0)), 0)
 %!assert (nnz (sparse (eye (3))*0), 0)
 %!assert (nnz (sparse (eye (3))-sparse (eye (3))), 0)
-%!assert (full (sparse (eye (3))/0), full (eye (3)/0));
+%!assert (full (sparse (eye (3))/0), full (eye (3)/0))
 
 EOF
 }
@@ -576,8 +576,8 @@
 %!assert (as',  sparse (af'))
 %!assert (-as, sparse (-af))
 %!assert (!as, sparse (!af))
-%!error [i,j] = size (af);as(i-1,j+1);
-%!error [i,j] = size (af);as(i+1,j-1);
+%!error [i,j] = size (af);as(i-1,j+1)
+%!error [i,j] = size (af);as(i+1,j-1)
 %!test
 %! [Is,Js,Vs] = find (as);
 %! [If,Jf,Vf] = find (af);
--- a/test/mk_bc_overloads_expected.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/mk_bc_overloads_expected.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,9 +1,9 @@
-% this script is intended to be Matlab compatible
-% first, run the script
+%% this script is intended to be Matlab compatible
+%% first, run the script
 %
-%   ./build_bc_overloads_tests.sh overloads_only
+%%   ./build_bc_overloads_tests.sh overloads_only
 %
-% to generate the overloaded functions.
+%% to generate the overloaded functions.
 %
 ex.double = 1;
 ex.single = single (1);
--- a/test/module.mk	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/module.mk	Thu Nov 19 13:08:00 2020 -0800
@@ -8,6 +8,7 @@
   %reldir%/fntests.m \
   %reldir%/args.tst \
   %reldir%/bug-31371.tst \
+  %reldir%/bug-40117.tst \
   %reldir%/bug-45969.tst \
   %reldir%/bug-45972.tst \
   %reldir%/bug-46330.tst \
@@ -90,8 +91,10 @@
 include %reldir%/classdef/module.mk
 include %reldir%/classdef-multiple-inheritance/module.mk
 include %reldir%/classes/module.mk
+include %reldir%/colon-op/module.mk
 include %reldir%/ctor-vs-method/module.mk
 include %reldir%/fcn-handle/module.mk
+include %reldir%/json/module.mk
 include %reldir%/local-functions/module.mk
 include %reldir%/mex/module.mk
 include %reldir%/nest/module.mk
--- a/test/nest/arg_nest.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/nest/arg_nest.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,4 +1,4 @@
-# arg_nest.m
+## arg_nest.m
 function x = arg_nest
   x = 1;
   A (x);
--- a/test/nest/nest.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/nest/nest.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -156,5 +156,5 @@
 %! assert (observed, [1, 2, 1, 3, 2]);
 
 ## Test visibility of nested function from script called from parent.
-%!assert (script_nest_2 (42), 84);
+%!assert (script_nest_2 (42), 84)
 %!error script_nest_2 (0)
--- a/test/nest/no_closure.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/nest/no_closure.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,4 +1,4 @@
-# no_closure.m
+## no_closure.m
 function r = no_closure (n)
   if (ischar (n))
     r = nested (n);
--- a/test/nest/persistent_nest.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/nest/persistent_nest.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,4 +1,4 @@
-# persistent_nest
+## persistent_nest
 function y = persistent_nest ()
   persistent x = 0;
   g;
--- a/test/nest/recursive_nest.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/nest/recursive_nest.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,11 +1,11 @@
-# recursive_nest.m
+## recursive_nest.m
 function x = recursive_nest ()
   global recursive_nest_inc = 1
   x = 5;
   f (20);
 
   function f (n)
-    if n > 0
+    if (n > 0)
       x = x + recursive_nest_inc;
       f (n - 1);
     end
--- a/test/nest/recursive_nest2.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/nest/recursive_nest2.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,4 +1,4 @@
-# recursive_nest2.m
+## recursive_nest2.m
 function x = recursive_nest2 ()
   x = B (20);
   function v = B (n)
@@ -7,7 +7,7 @@
     C;
     v = Y;
     function BB (m)
-      if m > 0
+      if (m > 0)
         Y = Y + 1;
         BB(m - 1);
         C;
--- a/test/nest/scope0.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/nest/scope0.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,4 +1,4 @@
-# scope0.m
+## scope0.m
 function scope0
   C;
   function A
--- a/test/nest/scope1.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/nest/scope1.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,7 +1,7 @@
-# scope1.m
+## scope1.m
 function scope1 (n)
   value = n;
-  if value
+  if (value)
     C;
   end
   function A
--- a/test/nest/scope2.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/nest/scope2.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,4 +1,4 @@
-# scope2.m
+## scope2.m
 function scope2
   C;
   function A
--- a/test/nest/scope3.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/nest/scope3.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,4 +1,4 @@
-# scope3.m
+## scope3.m
 function scope3
   C;
   function A
--- a/test/nest/script_nest.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/nest/script_nest.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,8 +1,8 @@
-# script_nest.m
+## script_nest.m
 function x = script_nest
   A (5)
   function A (n)
-    if n <= 0
+    if (n <= 0)
       script_nest_script;
     else
       A (n - 1);
--- a/test/nest/script_nest_2.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/nest/script_nest_2.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,4 +1,4 @@
-# script_nest.m
+## script_nest.m
 function r = script_nest_2 (x)
   function r = nest_fun ()
     r = 13;
--- a/test/nest/script_nest_script.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/nest/script_nest_script.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,2 +1,2 @@
-# script_nest_script.m
+## script_nest_script.m
 x = 5;
--- a/test/nest/script_nest_script_2.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/nest/script_nest_script_2.m	Thu Nov 19 13:08:00 2020 -0800
@@ -1,4 +1,4 @@
-# script_nest_script.m
+## script_nest_script.m
 if (x > 0)
   r = x * 2;
 else
--- a/test/nest/varg_nest2.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/nest/varg_nest2.m	Thu Nov 19 13:08:00 2020 -0800
@@ -2,12 +2,12 @@
   [a, b] = f;
   x = a;
 
-  if nargout == 1
+  if (nargout == 1)
     x = a;
   endif
 
   function [a, b] = f
-    if nargout == 2
+    if (nargout == 2)
       a = b = 5;
     endif
   endfunction
--- a/test/parser.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/parser.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -104,7 +104,7 @@
 %! assert (2 ^++a, 8);
 %! assert (a, 3);
 %! assert (a' ^2, 9);
-%! assert (2 ^sin(0), 1);
+%! assert (2 ^sin (0), 1);
 %! assert (-2 ^2, -4);;
 %! assert (2 ^+1 ^3, 8);
 %! assert (2 ^-1 ^3, 0.125);
@@ -214,7 +214,7 @@
 ## Level 13 (parentheses and indexing)
 %!test
 %! a.b1 = 2;
-%! assert (a.(strcat('b','1'))++, 2);
+%! assert (a.(strcat ('b','1'))++, 2);
 %! assert (a.b1, 3);
 %! b = {1 2 3 4 5};
 %! assert (b{(a. b1 + 1)}, 4);
@@ -286,19 +286,19 @@
 %!assert (123_456, 123456)
 %!assert (.123_456, .123456)
 %!assert (123_456.123_456, 123456.123456)
-%!assert (0xAB_CD, 43981)
+%!assert (0xAB_CD, uint16 (43981))
 %!assert (2e0_1, 20)
 
 ## Test binary constants
-%!assert (0b101, 5)
+%!assert (0b101, uint8 (5))
 %!assert (0B1100_0001, 0xC1)
-%!assert (class (0b1), "double")
+%!assert (class (0b1), "uint8")
 
 ## Test range of large binary and hexadecimal literals
-%!assert (0x8000_0000_0000_0000, 2^63)
-%!assert (0xFFFF_FFFF_FFFF_FFFF, 2^64)
-%!assert (0b10000000_0000000_000000000_00000000_00000000_00000000_00000000_00000000, 2^63)
-%!assert (0b11111111_1111111_111111111_11111111_11111111_11111111_11111111_11111111, 2^64)
+%!assert (0x8000_0000_0000_0000, uint64 (2^63))
+%!assert (0xFFFF_FFFF_FFFF_FFFF, uint64 (2^64))
+%!assert (0b10000000_0000000_000000000_00000000_00000000_00000000_00000000_00000000, uint64 (2^63))
+%!assert (0b11111111_1111111_111111111_11111111_11111111_11111111_11111111_11111111, uint64 (2^64))
 
 ## Test creation of anonymous functions
 
@@ -335,7 +335,7 @@
 #!error <vertical dimensions mismatch \(1x2 vs 1x1\)> z = [1, 2; 3]
 
 %!test
-%! f = @(s,t=toeplitz(s),u=t(x=2:end-1,x)=32)t;
+%! f = @(s,t=toeplitz (s),u=t(x=2:end-1,x)=32)t;
 %! assert (f (1), 1);
 %! assert (f (1, 2), 2);
 
--- a/test/pkg/pkg.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/pkg/pkg.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -31,6 +31,11 @@
 
 %!shared old_prefix, old_archprefix, old_local_list, old_global_list, prefix, restorecfg, restorecache, restoreglobalcache, rmtmpdir, mfile_pkg_name, mfile_pkg_tgz
 
+%!function test_cleanup (prefix)
+%! confirm_recursive_rmdir (0, "local");
+%! sts = rmdir (prefix, "s");
+%!endfunction
+
 %!testif HAVE_Z
 %! ## Do all tests in a temporary directory
 %! [old_prefix, old_archprefix] = pkg ("prefix");
@@ -48,7 +53,7 @@
 %! pkg ("prefix", prefix, prefix);
 %! pkg ("local_list", fullfile (prefix, "octave_packages"));
 %! pkg ("global_list", fullfile (prefix, "octave_packages"));
-%! rmtmpdir = @onCleanup (@() confirm_recursive_rmdir (0, "local") && rmdir (prefix, "s"));
+%! rmtmpdir = @onCleanup (@() test_cleanup (prefix));
 %!
 %! ## Create tar.gz file packages of testing directories in prefix directory
 %! mfile_pkg_name = {"mfile_basic_test", "mfile_minimal_test"};
@@ -74,7 +79,7 @@
 %!
 %!error pkg ("install", "nonexistent.zip")
 
-# -local
+## -local
 %!testif HAVE_Z
 %! for i = 1:numel (mfile_pkg_name)
 %!   silent_pkg_install ("-local", mfile_pkg_tgz{i});
@@ -82,18 +87,18 @@
 %!   pkg ("uninstall", mfile_pkg_name{i});
 %! endfor
 
-# -forge (need check for options?)
+## -forge (need check for options?)
 ## FIXME: Need test
-# We do not test this yet ... fails if no internet connection
-# use dataframe which is an mfile only package
+## We do not test this yet ... fails if no internet connection
+## use dataframe which is an mfile only package
 #%!test
 #%! silent_pkg_install ("-forge", "dataframe");
 #%! pkg ("uninstall", "dataframe");
 
-# -nodeps
+## -nodeps
 ## FIXME: Need test
 
-# -verbose
+## -verbose
 ## FIXME: Need test
 
 ## Action load/unload (within install/uninstall)
@@ -111,19 +116,19 @@
 %!   end_unwind_protect
 %! endfor
 %!
-%!error <package foobar is not installed> pkg ("load", "foobar");
+%!error <package foobar is not installed> pkg ("load", "foobar")
 
-# -nodeps
+## -nodeps
 ## FIXME: Need test
 
-# -verbose
+## -verbose
 ## FIXME: Need test
 
 ## Action list
 %!test
 %! [user_packages, system_packages] = pkg ("list");
 
-# -forge
+## -forge
 #%!test
 #%! oct_forge_pkgs = pkg ("list", "-forge");
 
@@ -136,7 +141,7 @@
 %! system (["chmod -Rf u+w '" prefix "'"]);     ## FIXME: Work around bug #53578
 %! pkg ("uninstall", mfile_pkg_name{1});
 
-# -verbose
+## -verbose
 ## FIXME: Need test
 
 ## Action prefix
@@ -151,11 +156,11 @@
 
 ## Action build
 ## FIXME: Need test
-# pkg build -verbose /tmp image-*
+## pkg build -verbose /tmp image-*
 
 ## Action rebuild
 ## FIXME: Need test
-# pkg rebuild signal
+## pkg rebuild signal
 
 ## Future commands
 %!error pkg ("whereis", "myfunc.m")
--- a/test/publish/publish.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/publish/publish.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -49,7 +49,7 @@
 %!     publish (fname{1}, opts);
 %!   endfor
 %!   confirm_recursive_rmdir (false, "local");
-%!   rmdir (tmpDir, "s");
+%!   sts = rmdir (tmpDir, "s");
 %! unwind_protect_cleanup
 %!   set (0, "defaultfigurevisible", visibility);
 %!   graphics_toolkit (toolkit);
@@ -81,7 +81,7 @@
 %!   str1 = fileread ("test_script.m");
 %!   str2 = grabcode (fullfile (tmpDir, "test_script.html"));
 %!   confirm_recursive_rmdir (false, "local");
-%!   rmdir (tmpDir, "s");
+%!   sts = rmdir (tmpDir, "s");
 %!   ## Canonicalize strings
 %!   str1 = strjoin (deblank (strsplit (str1, "\n")), "\n");
 %!   str2 = strjoin (deblank (strsplit (str2, "\n")), "\n");
--- a/test/publish/test_script.m	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/publish/test_script.m	Thu Nov 19 13:08:00 2020 -0800
@@ -32,7 +32,7 @@
 i = 0:2*pi
 
 # some real comment
-y = sin(i)
+y = sin (i)
 
 %%
 %
@@ -43,16 +43,16 @@
 x = 0:2*pi
 
 # some real comment and split code block
-y = sin(x)
+y = sin (x)
 
 %%
 %
 
 % reusing old values
-y = cos(i)
+y = cos (i)
 
 # some real comment and split code block
-y = cos(x)
+y = cos (x)
 
 %% Text formatting
 % PLAIN TEXT _ITALIC TEXT_ *BOLD TEXT* |MONOSPACED TEXT|
--- a/test/struct.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/struct.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -37,7 +37,7 @@
 
 %!test
 %! s.a = 1;
-%! fail ("fieldnames (s, 1)", "Invalid call to fieldnames");
+%! fail ("fieldnames (s, 1)", "called with too many inputs");
 
 %!error fieldnames (1)
 
--- a/test/system.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/system.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -98,13 +98,13 @@
 %! assert ((e1 && strcmp (s2.modestr(1), "d") && e3 && e4 < 0));
 
 %!error <Invalid call to mkdir> mkdir ()
-%!error <Invalid call to mkdir> mkdir ("foo", 1, 2)
+%!error <called with too many inputs> mkdir ("foo", 1, 2)
 %!error <Invalid call to rmdir> rmdir ()
 
 %!test
 %! crr = confirm_recursive_rmdir ();
 %! confirm_recursive_rmdir (0);
-%! assert (!rmdir ("foo", "s"));
+%! assert (! rmdir ("foo", "s"));
 %! confirm_recursive_rmdir (crr);
 
 %!test
--- a/test/try.tst	Thu Nov 19 13:05:51 2020 -0800
+++ b/test/try.tst	Thu Nov 19 13:08:00 2020 -0800
@@ -47,7 +47,7 @@
 %! catch
 %! end_try_catch
 %! a = 2;
-%! assert (!exist ('x'));
+%! assert (! exist ('x'));
 %! assert (a,2);
 
 %!test
@@ -65,9 +65,9 @@
 %!   a;
 %!   error ("Shouldn't get here");
 %! catch
-%!   assert (lasterr()(1:13), "'a' undefined");
+%!   assert (lasterr ()(1:13), "'a' undefined");
 %! end_try_catch
-%! assert (lasterr()(1:13), "'a' undefined");
+%! assert (lasterr ()(1:13), "'a' undefined");
 
 %!test
 %! try
@@ -96,13 +96,13 @@
 %!     a;
 %!     error ("Shouldn't get here");
 %!   catch
-%!     assert (lasterr()(1:13), "'a' undefined");
+%!     assert (lasterr ()(1:13), "'a' undefined");
 %!   end_try_catch
 %!   clear b;
 %!   b;
 %!   error ("Shouldn't get here");
 %! catch
-%!   assert (lasterr()(1:13), "'b' undefined");
+%!   assert (lasterr ()(1:13), "'b' undefined");
 %! end_try_catch
 
 %!test
@@ -112,12 +112,12 @@
 %!   error ("Shouldn't get here");
 %! catch
 %!   try
-%!     assert (lasterr()(1:13), "'a' undefined");
+%!     assert (lasterr ()(1:13), "'a' undefined");
 %!     clear b;
 %!     b;
 %!     error ("Shouldn't get here");
 %!   catch
-%!     assert (lasterr()(1:13), "'b' undefined");
+%!     assert (lasterr ()(1:13), "'b' undefined");
 %!   end_try_catch
 %! end_try_catch
 
@@ -131,7 +131,7 @@
 %!     error (["rethrow: " lasterr]);
 %!   end_try_catch
 %! catch
-%!   assert (lasterr()(1:22), "rethrow: 'a' undefined");
+%!   assert (lasterr ()(1:22), "rethrow: 'a' undefined");
 %! end_try_catch
 
 %!test