changeset 28199:7ac8b3188b27

maint: merge stable to default.
author John W. Eaton <jwe@octave.org>
date Wed, 08 Apr 2020 16:03:51 -0400
parents 20dea4a919c0 (diff) 52b2680e091c (current diff)
children b8384ed4d500
files
diffstat 140 files changed, 5014 insertions(+), 2757 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Wed Mar 25 16:46:30 2020 -0400
+++ b/NEWS	Wed Apr 08 16:03:51 2020 -0400
@@ -1,246 +1,73 @@
-Summary of important user-visible changes for version 6 (yyyy-mm-dd):
+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.
-
-- 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.
+- 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.
 
-- 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).
+    Command Form Example
 
-- 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.
+    `mkdir new_directory`
 
-- 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"`.
+    Function Form Example
 
-- 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:
+    `status = mkdir ("new_directory")`
 
-        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
+    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 `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` now can 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).
-
-- 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.
-
-#### 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, but 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.
+    The following list of functions have been modified.
 
-- 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.
+    * `copyfile`
+    * `fcntl`
+    * `fileattrib`
+    * `kill`
+    * `link`
+    * `mkfifo`
+    * `movefile`
+    * `rename`
+    * `rmdir`
+    * `symlink`
+    * `unlink`
 
-- 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.
+### Graphics backend
 
-- 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.
+- Support for Qt4 for graphics and the GUI has been removed.
 
 ### 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.
-
-- 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.
+- The function `griddata` now accepts 3-D inputs by passing data
+directly to `griddata3`.
 
-### Alphabetical list of new functions added in Octave 6
+- Coordinate transformation functions `cart2sph`, `sph2cart`,
+`cart2pol`, and `pol2cart` can 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.
 
-* `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`
-* `ostreamtube`
-* `rescale`
-* `rotx`
-* `roty`
-* `rotz`
-* `stream2`
-* `stream3`
-* `streamline`
-* `streamtube`
-* `uisetfont`
-* `verLessThan`
-* `web`
-* `weboptions`
-* `webread`
-* `webwrite`
-* `workspace`
+### Alphabetical list of new functions added in Octave 7
 
+* `rng`
 
 ### 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
 
@@ -248,47 +75,31 @@
   -----------------|---------------|------------
                    |               |
 
-
 ### 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/configure.ac	Wed Mar 25 16:46:30 2020 -0400
+++ b/configure.ac	Wed Apr 08 16:03:51 2020 -0400
@@ -27,7 +27,7 @@
 
 ### Initialize Autoconf
 AC_PREREQ([2.65])
-AC_INIT([GNU Octave], [6.0.1], [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,9 +39,9 @@
 ## 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=1
+OCTAVE_PATCH_VERSION=0
 
 dnl PACKAGE_VERSION is set by the AC_INIT VERSION argument.
 OCTAVE_VERSION="$PACKAGE_VERSION"
@@ -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-v54"
+OCTAVE_API_VERSION="api-v54+"
 
 AC_SUBST(OCTAVE_MAJOR_VERSION)
 AC_SUBST(OCTAVE_MINOR_VERSION)
@@ -2999,7 +2999,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/matrix.txi	Wed Mar 25 16:46:30 2020 -0400
+++ b/doc/interpreter/matrix.txi	Wed Apr 08 16:03:51 2020 -0400
@@ -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/etc/GNULIB.UPDATE	Wed Mar 25 16:46:30 2020 -0400
+++ b/etc/GNULIB.UPDATE	Wed Apr 08 16:03:51 2020 -0400
@@ -1,39 +1,13 @@
 ## Instructions for updating gnulib on development branch
 
-## Change directory to the local Octave repositoy and clone the gnulib git
-## repository:
-git clone git://git.savannah.gnu.org/gnulib.git gnulib-git
-
-## Convert to hg (might take some time):
-hg --config extensions.convert= convert ./gnulib-git ./gnulib-hg
+## "cd" to a directory where you want to clone the gnulib repository and run:
+git clone git://git.savannah.gnu.org/gnulib.git
 
-## Change directory to the gnulib sub-repo in Octave and execute the following
-## commands:
-cd ./gnulib
-hg pull default
-hg update
-hg log -rtip --template "{node}\n"
-
-## Take note of the SHA-1 hash (LAST_OLD_HASH) of that revision.
+## If you already have a local gnulib git repository, pull the latest changes:
+git pull
 
-## Locate the first new revision in the converted repository and replace it in
-## the following command:
-cd ../gnulib-hg
-hg log -r20111 --template "{node}\n"
-
-## Take note of the SHA-1 hash (FIRST_NEW_HASH) of that revision.
+## Query the commit id of the current head:
+git rev-parse HEAD
 
-## Change to the main directory of the local Octave repository and execute the
-## following command replacing the hashes with the information just gathered:
-cd ..
-echo FIRST_NEW_HASH LAST_OLD_HASH > splicemap
-
-## Execute the following command (having replaced FIRST_NEW_HASH):
-hg --config extensions.convert= convert ./gnulib-hg ./gnulib --splicemap ./splicemap --config convert.hg.startrev=FIRST_NEW_HASH
-
-## In the Octave repository do the following:
-cd gnulib
-hg update
-cd ..
-hg commit -m "maint: update gnulib subrepo."
-hg push default -r . 
+## Locate the line in bootstrap.conf starting with ": ${GNULIB_REVISION=" and
+## replace the git commit id with the new one.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/etc/NEWS.6	Wed Apr 08 16:03:51 2020 -0400
@@ -0,0 +1,296 @@
+Summary of important user-visible changes for version 6 (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.
+
+- 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` now can 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).
+
+- 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.
+
+#### 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, but 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.
+
+### 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.
+
+- 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
+
+* `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`
+* `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
+  -----------------|---------------|------------
+                   |               |
+
+
+### 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/libgui/src/files-dock-widget.cc	Wed Mar 25 16:46:30 2020 -0400
+++ b/libgui/src/files-dock-widget.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -720,17 +720,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/gui-preferences-ed.h	Wed Mar 25 16:46:30 2020 -0400
+++ b/libgui/src/gui-preferences-ed.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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/m-editor/file-editor-tab.cc	Wed Mar 25 16:46:30 2020 -0400
+++ b/libgui/src/m-editor/file-editor-tab.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -1833,7 +1833,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;
@@ -1990,6 +2006,22 @@
     return eol_mode;
   }
 
+  QString file_editor_tab::eol_string (void)
+  {
+    switch (m_edit_area->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");
+  }
+
   void file_editor_tab::update_eol_indicator (void)
   {
     switch (m_edit_area->eolMode ())
@@ -2255,10 +2287,36 @@
     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 ())
+      {
+        int line, col;
+        m_edit_area->getCursorPosition (&line,&col);
+
+        QString eol = eol_string ();
+        QString edit_text = m_edit_area->text ();
+
+        edit_text.replace (QRegExp ("[\\t ]+" + eol), eol);  // All lines
+        long int idx = edit_text.lastIndexOf (QRegExp ("[^\\t^ ]"));
+        edit_text.chop (edit_text.length () - idx - 1); // Last line
+
+        m_edit_area->setText (edit_text);
+        m_edit_area->setCursorPosition (line,col);
+      }
+
+    // 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 << eol_string ();   // Add newline if desired
+
     out.flush ();
     QApplication::restoreOverrideCursor ();
     file.flush ();
@@ -2476,9 +2534,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 +2550,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
 
--- a/libgui/src/m-editor/file-editor-tab.h	Wed Mar 25 16:46:30 2020 -0400
+++ b/libgui/src/m-editor/file-editor-tab.h	Wed Apr 08 16:03:51 2020 -0400
@@ -295,6 +295,7 @@
     QString get_function_name (void);
 
     QsciScintilla::EolMode detect_eol_mode (void);
+    QString eol_string (void);
     void update_eol_indicator (void);
 
     octave_qscintilla *m_edit_area;
--- a/libgui/src/settings-dialog.cc	Wed Mar 25 16:46:30 2020 -0400
+++ b/libgui/src/settings-dialog.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -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 ());
 
@@ -935,6 +937,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 ());
--- a/libgui/src/settings-dialog.ui	Wed Mar 25 16:46:30 2020 -0400
+++ b/libgui/src/settings-dialog.ui	Wed Apr 08 16:03:51 2020 -0400
@@ -32,7 +32,7 @@
       </size>
      </property>
      <property name="currentIndex">
-      <number>5</number>
+      <number>2</number>
      </property>
      <widget class="QWidget" name="tab_general">
       <property name="enabled">
@@ -841,9 +841,9 @@
           <property name="geometry">
            <rect>
             <x>0</x>
-            <y>0</y>
+            <y>-898</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>
--- a/libinterp/corefcn/data.cc	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/corefcn/data.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -4248,6 +4248,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:
@@ -4908,6 +4920,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 +4944,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)
--- a/libinterp/corefcn/dirfns.cc	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/corefcn/dirfns.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -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, ,
@@ -567,8 +607,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 +620,7 @@
 %!   delete (filename{n});
 %! endfor
 %! cd (cwd);
-%! rmdir (tmpdir);
+%! sts = rmdir (tmpdir);
 %! assert (result1, {"file1"; "myfile1"});
 %! assert (result2, {"myfile1"});
 %! assert (result3, {"file1"; "file2"});
--- a/libinterp/corefcn/dynamic-ld.cc	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/corefcn/dynamic-ld.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -199,13 +199,41 @@
     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);
@@ -230,29 +258,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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/corefcn/dynamic-ld.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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/file-io.cc	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/corefcn/file-io.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -1641,8 +1641,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 +2287,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
@@ -2890,7 +2931,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/graphics.cc	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/corefcn/graphics.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -8732,6 +8732,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,
--- a/libinterp/corefcn/graphics.in.h	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/corefcn/graphics.in.h	Wed Apr 08 16:03:51 2020 -0400
@@ -4364,8 +4364,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"
@@ -4472,11 +4471,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 (); }
 
@@ -5502,8 +5496,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"
@@ -5553,11 +5546,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 (); }
 
@@ -5618,8 +5606,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"
@@ -5710,8 +5697,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"
@@ -5804,8 +5790,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"
@@ -5846,11 +5831,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/input.cc	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/corefcn/input.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -1406,40 +1406,3 @@
 
   return input_sys.mfile_encoding (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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/corefcn/input.h	Wed Apr 08 16:03:51 2020 -0400
@@ -278,17 +278,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/mex.cc	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/corefcn/mex.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -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),
       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),
       pr (mxArray::calloc (get_number_of_elements (), get_element_size ())),
       pi (nullptr)
   {
@@ -1134,8 +1619,8 @@
     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),
       pr (mxArray::calloc (get_number_of_elements (), get_element_size ())),
@@ -1148,8 +1633,8 @@
   }
 
   // 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)),
       pr (mxArray::calloc (get_number_of_elements (), get_element_size ())),
       pi (nullptr)
   {
@@ -1178,9 +1663,11 @@
   mxArray_number (const mxArray_number& val)
     : mxArray_matlab (val),
       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 +1685,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 +1696,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 +1766,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 +1893,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 +1943,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 +2055,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 +2074,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 +2094,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 +2144,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 +2157,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 +2216,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
             {
@@ -1657,10 +2310,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 +2337,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 +2350,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 +2362,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 +2606,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 +2690,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 +2791,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 +2879,7 @@
 {
 public:
 
-  mex (octave_mex_function *f)
+  mex (octave_mex_function& f)
     : curr_mex_fcn (f), memlist (), arraylist (), fname (nullptr) { }
 
   // No copying!
@@ -2363,7 +3112,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 +3138,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 +3149,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 +3189,6 @@
     else
       warning ("%s: value not marked", function_name ());
 #endif
-
   }
 };
 
@@ -2478,8 +3228,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 +3331,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 +3788,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 +3815,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 +3938,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));
@@ -3177,7 +4253,7 @@
   // Save old mex pointer.
   frame.protect_var (mex_context);
 
-  mex context (&mex_fcn);
+  mex context (mex_fcn);
 
   for (int i = 0; i < nargin; i++)
     argin[i] = context.make_value (args(i));
@@ -3619,17 +4695,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 +4724,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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/corefcn/mexproto.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ /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	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/corefcn/module.mk	Wed Apr 08 16:03:51 2020 -0400
@@ -58,6 +58,7 @@
   %reldir%/ls-utils.h \
   %reldir%/mex.h \
   %reldir%/mexproto.h \
+  %reldir%/mxarray.h \
   %reldir%/oct-errno.h \
   %reldir%/oct-fstrm.h \
   %reldir%/oct-handle.h \
@@ -91,7 +92,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 \
@@ -300,8 +300,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 && \
@@ -334,11 +334,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/mxarray.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ /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	Wed Apr 08 16:03:51 2020 -0400
@@ -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-stream.cc	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/corefcn/oct-stream.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -1914,7 +1914,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 +2472,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 ())
@@ -3500,11 +3500,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 +3893,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 +3944,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)))
--- a/libinterp/corefcn/syscalls.cc	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/corefcn/syscalls.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/corefcn/sysdep.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -244,6 +244,44 @@
 #endif
 }
 
+DEFUN (__is_elevated_process__, args, ,
+       doc: /* -*- texinfo -*-
+@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,
+return false.
+On non-Windows platforms, this function fails with an error.
+@end deftypefn */)
+{
+#if defined (OCTAVE_USE_WINDOWS_API)
+  if (args.length () != 0)
+    print_usage ();
+
+  bool retval = false;
+  HANDLE h_token = nullptr;
+
+  if (OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &h_token))
+    {
+      TOKEN_ELEVATION elevation;
+      DWORD return_length = sizeof (TOKEN_ELEVATION);
+      if (GetTokenInformation (h_token, TokenElevation, &elevation,
+                               sizeof (elevation), &return_length))
+        retval = elevation.TokenIsElevated;
+    }
+
+  if (h_token)
+    CloseHandle (h_token);
+
+  return ovl (retval);
+
+#else
+  octave_unused_parameter (args);
+  error ("__is_elevated_process__: "
+         "Function is only supported on Windows platforms.");
+#endif
+}
+
 namespace octave
 {
 #if defined (__MINGW32__)
--- a/libinterp/corefcn/sysdep.h	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/corefcn/sysdep.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/corefcn/text-engine.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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/tril.cc	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/corefcn/tril.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -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;
 
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ /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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/corefcn/utils.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -1647,183 +1647,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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/corefcn/utils.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/corefcn/variables.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -1467,42 +1467,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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/corefcn/variables.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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/dldfcn/gzip.cc	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/dldfcn/gzip.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -700,7 +700,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
@@ -840,7 +840,7 @@
 %!  unwind_protect_cleanup
 %!    confirm_recursive_rmdir (false, "local");
 %!    for idx = 1:numel(out_dirs)
-%!      rmdir (out_dirs{idx}, "s");
+%!      sts = rmdir (out_dirs{idx}, "s");
 %!    endfor
 %!  end_unwind_protect
 %!endfunction
--- a/libinterp/module.mk	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/module.mk	Wed Apr 08 16:03:51 2020 -0400
@@ -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/ov-base-diag.cc	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-base-diag.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-base-diag.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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.cc	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-base.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -974,7 +974,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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-base.h	Wed Apr 08 16:03:51 2020 -0400
@@ -697,7 +697,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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-bool-mat.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-bool-mat.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-bool-sparse.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-bool-sparse.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-bool.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-bool.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-cell.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -1410,9 +1410,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 ());
 
@@ -1421,7 +1421,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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-cell.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-ch-mat.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-ch-mat.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-class.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -1637,7 +1637,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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-class.h	Wed Apr 08 16:03:51 2020 -0400
@@ -200,7 +200,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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-complex.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-complex.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-cx-mat.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-cx-mat.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-cx-sparse.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-cx-sparse.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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-float.cc	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-float.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-float.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-flt-complex.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-flt-complex.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-flt-cx-mat.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-flt-cx-mat.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-flt-re-mat.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-flt-re-mat.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-intx.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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;
   }
@@ -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-lazy-idx.h	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-lazy-idx.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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
--- a/libinterp/octave-value/ov-mex-fcn.cc	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-mex-fcn.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-mex-fcn.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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; }
+
   // We don't need to override both forms of the call method.  The using
   // declaration will avoid warnings about partially-overloaded virtual
   // functions.
@@ -111,14 +115,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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-perm.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-perm.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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;
 
--- a/libinterp/octave-value/ov-range.cc	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-range.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -771,20 +771,20 @@
 }
 
 mxArray *
-octave_range::as_mxArray (void) const
+octave_range::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 ();
 
   Matrix m = matrix_value ();
 
-  const double *p = m.data ();
+  const double *pdata = m.data ();
 
   for (mwSize i = 0; i < nel; i++)
-    pr[i] = p[i];
+    pd[i] = pdata[i];
 
   return retval;
 }
--- a/libinterp/octave-value/ov-range.h	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-range.h	Wed Apr 08 16:03:51 2020 -0400
@@ -306,7 +306,7 @@
     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
   {
--- a/libinterp/octave-value/ov-re-mat.cc	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-re-mat.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-re-mat.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-re-sparse.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-re-sparse.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-scalar.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-scalar.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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-struct.cc	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-struct.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -1011,7 +1011,7 @@
 }
 
 mxArray *
-octave_struct::as_mxArray (void) const
+octave_struct::as_mxArray (bool interleaved) const
 {
   int nf = nfields ();
   string_vector kv = map_keys ();
@@ -1021,7 +1021,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 ());
 
@@ -1037,7 +1037,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;
@@ -1629,7 +1629,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 ();
@@ -1639,7 +1639,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 ());
 
@@ -1655,7 +1655,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;
--- a/libinterp/octave-value/ov-struct.h	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov-struct.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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.cc	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -2626,6 +2626,75 @@
   rep->print_info (os, prefix + ' ');
 }
 
+void *
+octave_value::mex_get_data (mxClassID class_id, mxComplexity complexity) const
+{
+  // 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)
+    {
+      bool type_ok = false;
+
+      switch (class_id)
+        {
+        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");
+          break;
+        }
+
+      if (! type_ok)
+        error ("mex_get_data: type mismatch");
+
+      if (complexity == mxCOMPLEX && ! iscomplex ())
+        error ("mex_get_data: objectis not complex as requested");
+    }
+
+  return rep->mex_get_data ();
+}
+
 OCTAVE_NORETURN static void
 err_unary_op (const std::string& on, const std::string& tn)
 {
--- a/libinterp/octave-value/ov.h	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/octave-value/ov.h	Wed Apr 08 16:03:51 2020 -0400
@@ -60,6 +60,8 @@
 class octave_fcn_inline;
 class octave_value_list;
 
+#include "mxtypes.h"
+
 #include "oct-stream.h"
 #include "ov-base.h"
 
@@ -1326,13 +1328,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); }
--- a/libinterp/parse-tree/bp-table.cc	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/parse-tree/bp-table.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/parse-tree/bp-table.h	Wed Apr 08 16:03:51 2020 -0400
@@ -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/oct-parse.yy	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/parse-tree/oct-parse.yy	Wed Apr 08 16:03:51 2020 -0400
@@ -5301,23 +5301,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)
   {
--- a/libinterp/parse-tree/parse.h	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/parse-tree/parse.h	Wed Apr 08 16:03:51 2020 -0400
@@ -656,14 +656,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/pt-arg-list.h	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/parse-tree/pt-arg-list.h	Wed Apr 08 16:03:51 2020 -0400
@@ -128,10 +128,4 @@
   };
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-// tree_argument_list is derived from a template.
-
 #endif
-
-#endif
--- a/libinterp/parse-tree/pt-classdef.h	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/parse-tree/pt-classdef.h	Wed Apr 08 16:03:51 2020 -0400
@@ -829,10 +829,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-misc.h	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/parse-tree/pt-misc.h	Wed Apr 08 16:03:51 2020 -0400
@@ -119,11 +119,4 @@
   };
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-// tree_parameter_list is derived from a template.
-// tree_return_list is derived from a template.
-
 #endif
-
-#endif
--- a/libinterp/parse-tree/token.h	Wed Mar 25 16:46:30 2020 -0400
+++ b/libinterp/parse-tree/token.h	Wed Apr 08 16:03:51 2020 -0400
@@ -123,12 +123,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;
--- a/scripts/deprecated/module.mk	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/deprecated/module.mk	Wed Apr 08 16:03:51 2020 -0400
@@ -1,7 +1,6 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
-  %reldir%/output_max_field_width.m \
   %reldir%/runtests.m
 
 %canon_reldir%dir = $(fcnfiledir)/deprecated
--- a/scripts/deprecated/output_max_field_width.m	Wed Mar 25 16:46:30 2020 -0400
+++ /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/general/cart2pol.m	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/general/cart2pol.m	Wed Apr 08 16:03:51 2020 -0400
@@ -28,21 +28,47 @@
 ## @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
 
@@ -53,44 +79,54 @@
   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);
@@ -179,15 +232,17 @@
 ## Test input validation
 %!error 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	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/general/cart2sph.m	Wed Apr 08 16:03:51 2020 -0400
@@ -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]);
@@ -145,11 +192,13 @@
 %!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 <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/module.mk	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/general/module.mk	Wed Apr 08 16:03:51 2020 -0400
@@ -60,6 +60,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/pol2cart.m	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/general/pol2cart.m	Wed Apr 08 16:03:51 2020 -0400
@@ -28,21 +28,43 @@
 ## @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
+## @var{x} = @var{r} * cos (@var{theta})
+## @var{y} = @var{r} * sin (@var{theta})
+## @var{z} = @var{z}
+## @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
 
@@ -53,44 +75,55 @@
   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 +131,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 +189,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);
@@ -182,15 +235,17 @@
 ## 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 <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)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/general/rng.m	Wed Apr 08 16:03:51 2020 -0400
@@ -0,0 +1,303 @@
+########################################################################
+##
+## 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 @code{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/sph2cart.m	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/general/sph2cart.m	Wed Apr 08 16:03:51 2020 -0400
@@ -26,22 +26,43 @@
 ## -*- 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
+## @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 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 +73,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 +104,6 @@
   y = r .* cos (phi) .* sin (theta);
   z = r .* sin (phi);
 
-  if (nargout <= 1)
-    x = [x(:), y(:), z(:)];
-  endif
-
 endfunction
 
 
@@ -89,13 +117,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,8 +160,18 @@
 
 %!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]);
@@ -143,11 +190,13 @@
 %!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 <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/geometry/griddata.m	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/geometry/griddata.m	Wed Apr 08 16:03:51 2020 -0400
@@ -27,123 +27,158 @@
 ## @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{})
-##
-## Generate a regular mesh from irregular data using interpolation.
+## @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})
 ##
-## The function is defined by @code{@var{z} = f (@var{x}, @var{y})}.  Inputs
+## Generate a regular mesh from irregular data using 2-D or 3-D interpolation.
+##
+## For 2-D interpolation, 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.
+## @code{@var{x}, @var{y}} are vectors and @code{@var{z}} is 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 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 function is defined by
+## @code{@var{v} = f (@var{x}, @var{y}, @var{z})}, and the interpolation points
+## are specified by @var{xi}, @var{yi}, @var{zi}.
+##
+## For both 2-D and 3-D cases, the interpolation method can be
+## @qcode{"nearest"} 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.  See @code{delaunayn} for information on the defaults and
+## how to pass different values.
 ## @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, xi, yi, method = "linear")
+function [rx, ry, rz] = griddata (x, y, z, varargin)
 
-  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 3D 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};
+
+    if (nargin == 6)
+      if (! ischar (varargin{3}))
+        error ("griddata: unknown interpolation METHOD");
+      endif
+      method = tolower (varargin{3});
+    else
+      method = "linear";
+    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 (any (strcmp (method, {"cubic", "natural", "v4"})))
+      ## FIXME: implement missing interpolation methods.
+      error ('griddata: "%s" interpolation not yet implemented', method);
 
-  if (nargout > 1)
-    rx = xi;
-    ry = yi;
-    rz = zi;
-  else
-    rx = zi;
+    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);
+
+    else
+      error ('griddata: unknown interpolation METHOD: "%s"', method);
+    endif
+
+    if (nargout > 1)
+      rx = xi;
+      ry = yi;
+      rz = zi;
+    else
+      rx = zi;
+    endif
+
   endif
 
 endfunction
@@ -155,10 +190,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 +201,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,19 +213,20 @@
 %! 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);
@@ -200,11 +237,16 @@
 %!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 <only one output argument> [xi,yi] = griddata (1,2,3,4,5,6,7)
+%!error <unknown interpolation METHOD> griddata (1,2,3,4,5, {"linear"})
+%!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 <"cubic" .* not yet implemented> griddata (1,2,3,4,5, "cubic")
+%!error <"natural" .* not yet implemented> griddata (1,2,3,4,5, "natural")
+%!error <"v4" .* not yet implemented> griddata (1,2,3,4,5, "v4")
+%!error <unknown interpolation METHOD: "foobar"> griddata (1,2,3,4,5, "foobar")
--- a/scripts/legacy/textread.m	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/legacy/textread.m	Wed Apr 08 16:03:51 2020 -0400
@@ -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/linear-algebra/condest.m	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/linear-algebra/condest.m	Wed Apr 08 16:03:51 2020 -0400
@@ -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/miscellaneous/copyfile.m	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/miscellaneous/copyfile.m	Wed Apr 08 16:03:51 2020 -0400
@@ -53,7 +53,7 @@
   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,11 +147,19 @@
     ## 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
 
 
@@ -172,3 +194,4 @@
 %!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	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/miscellaneous/delete.m	Wed Apr 08 16:03:51 2020 -0400
@@ -80,7 +80,7 @@
 %!   delete (file);
 %!   assert (! exist (file, "file"));
 %! unwind_protect_cleanup
-%!   unlink (file);
+%!   sts = unlink (file);
 %! end_unwind_protect
 
 %!test
--- a/scripts/miscellaneous/dir.m	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/miscellaneous/dir.m	Wed Apr 08 16:03:51 2020 -0400
@@ -224,7 +224,7 @@
 %!   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
 
@@ -238,7 +238,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/fieldnames.m	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/miscellaneous/fieldnames.m	Wed Apr 08 16:03:51 2020 -0400
@@ -28,19 +28,19 @@
 ## @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)
@@ -49,9 +49,14 @@
     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	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/miscellaneous/fileattrib.m	Wed Apr 08 16:03:51 2020 -0400
@@ -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,17 +67,20 @@
 ## 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 = ".")
@@ -87,7 +93,7 @@
     error ("fileattrib: FILE must be a string");
   endif
 
-  status = true;
+  sts = 1;
   msg = "";
   msgid = "";
 
@@ -108,10 +114,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 +147,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/isfolder.m	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/miscellaneous/isfolder.m	Wed Apr 08 16:03:51 2020 -0400
@@ -70,8 +70,8 @@
 %!   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
--- a/scripts/miscellaneous/mkdir.m	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/miscellaneous/mkdir.m	Wed Apr 08 16:03:51 2020 -0400
@@ -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
--- a/scripts/miscellaneous/movefile.m	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/miscellaneous/movefile.m	Wed Apr 08 16:03:51 2020 -0400
@@ -59,7 +59,7 @@
   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
@@ -187,3 +209,4 @@
 %!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/run.m	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/miscellaneous/run.m	Wed Apr 08 16:03:51 2020 -0400
@@ -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,7 +140,7 @@
 %!   assert (tstval2, true);
 %! unwind_protect_cleanup
 %!   unlink (test_function);
-%!   rmdir (tmp_dir);
+%!   sts = rmdir (tmp_dir);
 %!   path (path_orig);
 %! end_unwind_protect
 
--- a/scripts/miscellaneous/tar.m	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/miscellaneous/tar.m	Wed Apr 08 16:03:51 2020 -0400
@@ -149,12 +149,8 @@
 %!   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
--- a/scripts/miscellaneous/unpack.m	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/miscellaneous/unpack.m	Wed Apr 08 16:03:51 2020 -0400
@@ -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
--- a/scripts/miscellaneous/zip.m	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/miscellaneous/zip.m	Wed Apr 08 16:03:51 2020 -0400
@@ -126,11 +126,11 @@
 %!     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
--- a/scripts/path/pathdef.m	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/path/pathdef.m	Wed Apr 08 16:03:51 2020 -0400
@@ -112,7 +112,7 @@
 %!   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
 
@@ -128,7 +128,7 @@
 %!   path_2 = path ();
 %!   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	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/path/savepath.m	Wed Apr 08 16:03:51 2020 -0400
@@ -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
--- a/scripts/pkg/pkg.m	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/pkg/pkg.m	Wed Apr 08 16:03:51 2020 -0400
@@ -329,7 +329,7 @@
 
 function [local_packages, global_packages] = pkg (varargin)
 
-  ## Installation prefix (FIXME: what should these be on windows?)
+  ## Installation prefix
   persistent user_prefix = false;
   persistent prefix = false;
   persistent archprefix = -1;
@@ -337,9 +337,13 @@
   persistent global_list = fullfile (OCTAVE_HOME (), "share", "octave",
                                      "octave_packages");
 
-  ## If user is superuser set global_istall to true
-  ## FIXME: is it OK to set this always true on windows?
-  global_install = ((ispc () && ! isunix ()) || (geteuid () == 0));
+  ## If user is superuser (posix) or the process has elevated rights (Windows),
+  ## set global_install to true.
+  if (ispc () && ! isunix ())
+    global_install = __is_elevated_process__ ();
+  else
+    global_install = (geteuid () == 0);
+  endif
 
   if (isbool (prefix))
     [prefix, archprefix] = default_prefix (global_install);
--- a/scripts/pkg/private/configure_make.m	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/pkg/private/configure_make.m	Wed Apr 08 16:03:51 2020 -0400
@@ -88,7 +88,7 @@
       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);
       endif
@@ -105,7 +105,7 @@
       [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);
       endif
--- a/scripts/pkg/private/install.m	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/pkg/private/install.m	Wed Apr 08 16:03:51 2020 -0400
@@ -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
@@ -450,7 +450,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
@@ -465,7 +465,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
@@ -517,7 +517,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 ()))
@@ -532,39 +532,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);
         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
@@ -575,8 +575,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
 
@@ -596,8 +596,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
@@ -629,8 +629,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
@@ -801,8 +801,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/uninstall.m	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/pkg/private/uninstall.m	Wed Apr 08 16:03:51 2020 -0400
@@ -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);
--- a/scripts/plot/draw/lightangle.m	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/plot/draw/lightangle.m	Wed Apr 08 16:03:51 2020 -0400
@@ -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");
--- a/scripts/plot/draw/surfl.m	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/plot/draw/surfl.m	Wed Apr 08 16:03:51 2020 -0400
@@ -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/util/isprop.m	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/plot/util/isprop.m	Wed Apr 08 16:03:51 2020 -0400
@@ -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,6 +76,11 @@
 %!assert (isprop (zeros (2, 3), "visible"), true (2, 3))
 %!assert (isprop ([-2, -1, 0], "visible"), [false, false, true])
 
+%!test
+%! m = containers.Map ();
+%! assert (isprop (m, "KeyType"));
+%! assert (! isprop (m, "FooBar"));
+
 %!error isprop ()
 %!error isprop (1)
 %!error isprop (1,2,3)
--- a/scripts/prefs/getpref.m	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/prefs/getpref.m	Wed Apr 08 16:03:51 2020 -0400
@@ -151,9 +151,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
--- a/scripts/prefs/setpref.m	Wed Mar 25 16:46:30 2020 -0400
+++ b/scripts/prefs/setpref.m	Wed Apr 08 16:03:51 2020 -0400
@@ -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
--- a/src/mkoctfile.in.cc	Wed Mar 25 16:46:30 2020 -0400
+++ b/src/mkoctfile.in.cc	Wed Apr 08 16:03:51 2020 -0400
@@ -601,6 +601,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";
@@ -657,6 +683,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++)
     {
@@ -737,6 +768,27 @@
         {
           std::cerr << "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"))
         {
@@ -807,6 +859,8 @@
         }
       else if (arg == "-mex" || arg == "--mex")
         {
+          creating_mex_file = true;
+
           incflags += " -I.";
 #if defined (_MSC_VER)
           ldflags += " -Wl,-export:mexFunction";
@@ -847,10 +901,37 @@
         octfile = file;
     }
 
-  if (output_ext ==  ".mex"
-      && vars["ALL_CFLAGS"].find ("-g") != std::string::npos)
+  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 << "warning: -R2017b option ignored unless creating mex file"
+                  << std::endl;
+
+      if (r2018a_option)
+        std::cerr << "warning: -R2018a option ignored unless creating mex file"
+                  << std::endl;
     }
 
   if (compile_only && output_file_option
--- a/test/deprecate-props.tst	Wed Mar 25 16:46:30 2020 -0400
+++ b/test/deprecate-props.tst	Wed Apr 08 16:03:51 2020 -0400
@@ -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/io.tst	Wed Mar 25 16:46:30 2020 -0400
+++ b/test/io.tst	Wed Apr 08 16:03:51 2020 -0400
@@ -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
@@ -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);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/mex/mexnumtst.c	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Apr 08 16:03:51 2020 -0400
@@ -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	Wed Mar 25 16:46:30 2020 -0400
+++ b/test/mex/module.mk	Wed Apr 08 16:03:51 2020 -0400
@@ -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/pkg/pkg.tst	Wed Mar 25 16:46:30 2020 -0400
+++ b/test/pkg/pkg.tst	Wed Apr 08 16:03:51 2020 -0400
@@ -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"};
--- a/test/publish/publish.tst	Wed Mar 25 16:46:30 2020 -0400
+++ b/test/publish/publish.tst	Wed Apr 08 16:03:51 2020 -0400
@@ -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/system.tst	Wed Mar 25 16:46:30 2020 -0400
+++ b/test/system.tst	Wed Apr 08 16:03:51 2020 -0400
@@ -104,7 +104,7 @@
 %!test
 %! crr = confirm_recursive_rmdir ();
 %! confirm_recursive_rmdir (0);
-%! assert (!rmdir ("foo", "s"));
+%! assert (! rmdir ("foo", "s"));
 %! confirm_recursive_rmdir (crr);
 
 %!test